Android : 跟我学Binder --- (4) 驱动情景分析 Android : 跟我学Binder --- (1) 什么是Binder IPC?为何要使用Binder机制?

目录:

一、数据结构

  首先基于之前的c程序代码再添加一个goodbye服务,引入以下几个概念:

binder_ref
binder_node
binder_proc
binder_thread
binder_buffer

  1.test_server.c中实现goodbye服务处理函数:

int goodbye_service_handler(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply)
{
    /* 根据txn->code知道要调用哪一个函数
     * 如果需要参数, 可以从msg取出
     * 如果要返回结果, 可以把结果放入reply
     */

    /* saygoodbye
     * saygoodbye_to
     */
    
    uint16_t *s;
    char name[512];
    size_t len;
    uint32_t handle;
    uint32_t strict_policy;
    int i;


    // Equivalent to Parcel::enforceInterface(), reading the RPC
    // header with the strict mode policy mask and the interface name.
    // Note that we ignore the strict_policy and don't propagate it
    // further (since we do no outbound RPCs anyway).
    strict_policy = bio_get_uint32(msg);


    switch(txn->code) {
    case GOODBYE_SVR_CMD_SAYGOODBYE:
        saygoodbye();
        bio_put_uint32(reply, 0); /* no exception */
        return 0;

    case GOODBYE_SVR_CMD_SAYGOODBYE_TO:
        /* 从msg里取出字符串(16位转8位) */
        s = bio_get_string16(msg, &len);  //"IGoodbyeService"
        s = bio_get_string16(msg, &len);  // name
        if (s == NULL) {
            return -1;
        }
        for (i = 0; i < len; i++)
            name[i] = s[i];
        name[i] = '\0';

        /* 处理 */
        i = saygoodbye_to(name);

        /* 把结果放入reply */
        bio_put_uint32(reply, 0); /* no exception */
        bio_put_uint32(reply, i);
        
        break;

    default:
        fprintf(stderr, "unknown code %d\n", txn->code);
        return -1;
    }

    return 0;
}

  2.main函数中注册服务:

    /* add service */
    ret = svcmgr_publish(bs, svcmgr, "hello", hello_service_handler);
    if (ret) {
        fprintf(stderr, "failed to publish hello service\n");
        return -1;
    }
    ret = svcmgr_publish(bs, svcmgr, "goodbye", goodbye_service_handler);
    if (ret) {
        fprintf(stderr, "failed to publish goodbye service\n");
    }
......
  
   binder_loop(bs, test_server_handler); //通过函数test_server_handler处理消息

  其中 test_server_handler 会根据binder_transaction_data中的descriptor信息调用对应服务的处理函数:

int test_server_handler(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply)
{
    int (*handler)(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply);

    handler = (int (*)(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply))txn->target.ptr;
    
    return handler(bs, txn, msg, reply); // 根据txn->target.ptr转换成对应的处理函数
}

  3.test_client.c中获取服务并使用:

    /* get service */
    handle = svcmgr_lookup(bs, svcmgr, "goodbye");
    if (!handle) {
        fprintf(stderr, "failed to get goodbye service\n");
        return -1;
    }
    g_goodbye_handle = handle;
    fprintf(stderr, "Handle for goodbye service = %d\n", g_goodbye_handle);
/* use service */
void saygoodbye(void)
{
    unsigned iodata[512/4];
    struct binder_io msg, reply;

    /* 构造binder_io */
    bio_init(&msg, iodata, sizeof(iodata), 4);
    bio_put_uint32(&msg, 0);  // strict mode header
    bio_put_string16_x(&msg, "IGoodbyeService");

    /* 放入参数 */

    /* 调用binder_call */
    if (binder_call(g_bs, &msg, &reply, g_goodbye_handle, GOODBYE_SVR_CMD_SAYGOODBYE))
        return ;
    
    /* 从reply中解析出返回值 */

    binder_done(g_bs, &msg, &reply);
    
}

 通过分别对hello和goodbye服务的注册/获取,注册和获取打印的handle值并不对应相同,这就涉及到IPC的概念:①源(自己)、②目的(handle表示)、③数据;

  例如调用binder_call:

    if (binder_call(g_bs, &msg, &reply, g_goodbye_handle, GOODBYE_SVR_CMD_SAYGOODBYE))
        return ;

  其原型为:

/*
*@msg:提供的参数
*@reply:返回的数据
*@target:发送数据的目标(服务的引用)
*@code:调用函数
*/
int binder_call(struct binder_state *bs,
                struct binder_io *msg, struct binder_io *reply,
                uint32_t target, uint32_t code)

 binder驱动会根据handle找到目的进程,驱动内部通过 binder_ref 管理对应的引用:

struct binder_ref {
    int debug_id;
    struct rb_node rb_node_desc;
    struct rb_node rb_node_node;
    struct hlist_node node_entry;
    struct binder_proc *proc;
    struct binder_node *node;
    uint32_t desc;
    int strong;
    int weak;
    struct binder_ref_death *death;
};

 binder_ref添加逻辑,如图:

 

                

二、打印数据交互过程

  从前面编写的示例程序可知,与binder驱动交互主要是通过ioctl操作:

res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);

  传入的数据为 struct binder_write_read bwr,该结构体中的 write_buffer 指向数据本身,对应结构体如下:

    struct {
        uint32_t cmd;  //头4个字节表示数据类型
        struct binder_transaction_data txn;
    } __attribute__((packed)) writebuf;

三、服务注册/获取/使用过程

四、transaction_stack机制

猜你喜欢

转载自www.cnblogs.com/blogs-of-lxl/p/10326797.html