• Android跨进程通信,IPC,RPC,Binder系统,C语言应用层调用


    Android跨进程通信,IPC,RPC,Binder系统,C语言应用层调用()

    1.概念

    IPC,进程间通信,a进程发送数据给b进程,就是跨进程通信。

    RPC,远程调用,a进程想打开led,点亮led,调用led_open函数,通过IPC发送数据给b进程,b取出数据,然后调用b进程的led_open函数,看似a进程来直接操作led_open函数一样,实际上是a发送数据给b,b操作硬件

    b进程服务端程序要先向servicemanager注册服务,a进程查询led_服务,得到一个handle,指向进程b。

    数据一般存在char buf[1024]里面。a,b进程通过buffer传递数据双端。

    谷歌的源码参考目录

    在这里插入图片描述

    binder.c(谷歌封装好的c函数)

    2.流程

    servicemanager先由系统先运行,

    1. open binder驱动
    2. 告诉驱动程序自己就是servicemanager
    3. while(1)循环,读数据,读取驱动,获取数据,没有数据就休眠,得到数据就解析数据。
      • 服务端注册服务,在链表中记录服务名,
      • 客户端获取服务,查询链表中的服务,返回服务端进程

    服务端程序:

    1. open驱动
    2. 注册服务,向servicemanager发送服务的名字,
    3. while(1)读驱动,无数据就休眠,解析数据,调用系统对应的底层函数,

    客户端程序:

    1. open驱动。
    2. 获取服务,向servicemanager查询服务,获得一个handle,
    3. 向handle句柄发送数据。

    打开驱动程序

    在这里插入图片描述

    告诉驱动程序自己就是servicemanager

    在这里插入图片描述

    循环读取数据,

    在这里插入图片描述

    binder_loop读数据,

    在这里插入图片描述

    解析数据

    在这里插入图片描述

    处理回复信息给客户端

    在这里插入图片描述

    客户端获取服务

    在这里插入图片描述

    注册服务

    在这里插入图片描述

    3.bctest.c

    3.1 注册服务,打开binder驱动

    在这里插入图片描述

    注册服务,构造好数据

    在这里插入图片描述

    发给目标target

    在这里插入图片描述

    我们看一下这个值

    在这里插入图片描述

    在头文件中定义,句柄是0,进程间通信,0就是servicemanager进程,

    在这里插入图片描述

    通过binder_call调用,code: 表示要调用servicemanager中的"addservice"函数

    3.2 获取服务

    打开驱动, 循环查询服务列表

    在这里插入图片描述

    if (binder_call(bs, &msg, &reply, target, SVC_MGR_CHECK_SERVICE))
    return 0;

    还是调用binder_call函数,msg中含有你想获取服务的名字,含有servicemanager回复的数据,

    4.binder_call

    实现远程调用, 向谁发数据,

    target,目的进程

    code,调用的函数

    msg,提供的数据参数

    reply,返回值

    构造我们要发送的数据,放在buffer中,用binder_io

    调用ioctl发送数据。

    int binder_call(struct binder_state *bs,
                    struct binder_io *msg, struct binder_io *reply,
                    uint32_t target, uint32_t code)
    {
        int res;
        struct binder_write_read bwr;
        struct {
            uint32_t cmd;
            struct binder_transaction_data txn;
        } __attribute__((packed)) writebuf;
        unsigned readbuf[32];
    
        if (msg->flags & BIO_F_OVERFLOW) {
            fprintf(stderr,"binder: txn buffer overflow\n");
            goto fail;
        }
    
        writebuf.cmd = BC_TRANSACTION;
        writebuf.txn.target.handle = target;
        writebuf.txn.code = code;
        writebuf.txn.flags = 0;
        writebuf.txn.data_size = msg->data - msg->data0;
        writebuf.txn.offsets_size = ((char*) msg->offs) - ((char*) msg->offs0);
        writebuf.txn.data.ptr.buffer = (uintptr_t)msg->data0;
        writebuf.txn.data.ptr.offsets = (uintptr_t)msg->offs0;
    
        bwr.write_size = sizeof(writebuf);
        bwr.write_consumed = 0;
        bwr.write_buffer = (uintptr_t) &writebuf;
    
        hexdump(msg->data0, msg->data - msg->data0);
        for (;;) {
            bwr.read_size = sizeof(readbuf);
            bwr.read_consumed = 0;
            bwr.read_buffer = (uintptr_t) readbuf;
    		//调用ioctl发送数据。bwr结构体
            res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
    
            if (res < 0) {
                fprintf(stderr,"binder: ioctl failed (%s)\n", strerror(errno));
                goto fail;
            }
    
            res = binder_parse(bs, reply, (uintptr_t) readbuf, bwr.read_consumed, 0);
            if (res == 0) return 0;
            if (res < 0) goto fail;
        }
    
    fail:
        memset(reply, 0, sizeof(*reply));
        reply->flags |= BIO_F_IOERROR;
        return -1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    在这里插入图片描述

    数据要转换,binder_io参数是这个类型,内核驱动要求res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);bwr是上图的类型。

    ioctl收数据,也会收到binder_write_read,然后转化为binder_io

    svcmgr_lookup看下面源码

    uint32_t svcmgr_lookup(struct binder_state *bs, uint32_t target, const char *name)
    {
        uint32_t handle;
        //binder_io对缓冲区的管理
        unsigned iodata[512/4];
        //初始化结构体binder_io
        struct binder_io msg, reply;
    	//初始化就可以在缓冲池里面放数据 了
        bio_init(&msg, iodata, sizeof(iodata), 4);
        bio_put_uint32(&msg, 0);  // strict mode header
        bio_put_string16_x(&msg, SVC_MGR_NAME);
        bio_put_string16_x(&msg, name);
    	//binder_io发送给驱动
        if (binder_call(bs, &msg, &reply, target, SVC_MGR_CHECK_SERVICE))
            return 0;
    
        handle = bio_get_ref(&reply);
    
        if (handle)
            binder_acquire(bs, handle);
    
        binder_done(bs, &msg, &reply);
    
        return handle;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
  • 相关阅读:
    电影院排行查询易语言代码
    查看吾托帮88.47的docker里的tomcat日志
    【技术积累】数据结构中的二叉树及其相关算法【一】
    [蓝牙 Mesh & Zephyr]-[004]- 基础 Model
    100天精通Python(数据分析篇)——第51天:numpy函数进阶
    爆料,前华为微服务专家纯手打500页落地架构实战笔记,已开源
    vue3 不推荐使用index作为v-for遍历的key
    VS2017/2019均适用的opencv 快速通用免重复安装配置流程
    JavaScript之document对象最常用相关知识总结
    Tomcat安装教程
  • 原文地址:https://blog.csdn.net/weixin_46039528/article/details/134478966