Android : 跟我学Binder --- (4) 驱动情景分析

目录:

一、数据结构

  首先基于之前的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机制

原文地址:https://www.cnblogs.com/blogs-of-lxl/p/10326797.html

时间: 2024-11-08 22:53:58

Android : 跟我学Binder --- (4) 驱动情景分析的相关文章

Android : 跟我学Binder --- (3) C程序示例

目录: Android : 跟我学Binder --- (1) 什么是Binder IPC?为何要使用Binder机制? Android : 跟我学Binder --- (2) AIDL分析及手动实现 Android : 跟我学Binder --- (3) C程序示例 待完善... 一.Binder框架分析 1.IPC.LPC和RPC的概念: IPC:  (Inter Process Communication )跨进程通信,泛指进程之间任何形式的通信行为,它不仅包括各种形式的消息传递,还可以指

Android : 跟我学Binder ---- (1) 什么是Binder机制?

一.引言 如果把Android系统比作一幅精美绝伦的画,那Binder则是其浓墨重彩的独特一笔.初步了解过的人应该知道Binder是Android核心进程间通信(IPC:Internet Process Connection)手段之一,它是基于开源的 OpenBinder 实现,OpenBinder 起初由 Be Inc. 开发,后由 Plam Inc. 接手.从字面上来解释 Binder 有胶水.粘合剂的意思,顾名思义就是粘和不同的进程,使之实现通信.而日常开发中涉及到的如:AIDL.插件化编

9.5 Binder系统_驱动情景分析_transaction_stack机制

参考文章:http://www.cnblogs.com/samchen2009/p/3316001.html test_server服务进程可能有多个线程,而在发送数据的时候handle只表示了那个进程 (1)发给谁?handle只表示了那个进程,数据是发给进程还是某个线程 一般数据放在binder_proc的todo链表,其会唤醒等待与binder_proc.wait上的空闲线程: 对于双向传输,则放在binder_thread.todo链表上,然后唤醒该线程(用transaction_sta

Binder系统_驱动情景分析7_binder_server的多线程(1)

怎么写APP: 1.设置max_threads void binder_set_maxthreads(struct binder_state *bs, int threads) { ioctl(bs->fd, BINDER_SET_MAX_THREADS, &threads); } 记得在在binder.h中声明 D:\4412\APP_0003_Binder_C_App(2)\test_server.c 2.收到BR_SPAWN_LOOPER后创建新线程 3.新线程发出ioctl:BC_R

9.6 Binder系统_驱动情景分析_server的多线程实现

当多个client对server发出请求的时候,如果server忙不过来的时候会创建多线程来处理请求 那么忙不过来由谁来判断? server进程有个binder_proc结构体,其里面有todo链表(放有client发过来的数据),并且会唤醒等待在binder_proc.wait上的线程,如果有线程在wait上等待,表面server进程忙的过来:如果wait上空了,就表面server太忙了,驱动会向应用程序反馈 (1)驱动判断是否忙不过来 (2)驱动向APP发请求:创建新线程 (3)APP创建新

第6课第2节_Binder系统_驱动情景分析_打印数据交互过程

添加宏: 功能:把NAME(n) 中的n作为字符串返回,eg:BR_NOOP作为字符串返回 BR开头:Binder--->IPC BC开头:IPC------>Binder #define NAME(n) case n: return #n const char *binder_cmd_name(uint32_t cmd) { switch(cmd) { NAME(BR_NOOP); NAME(BR_TRANSACTION_COMPLETE); NAME(BR_INCREFS); NAME(B

《Android系统源代码情景分析》连载回忆录:灵感之源

上个月,在花了一年半时间之后,写了55篇文章,分析完成了Chromium在Android上的实现,以及Android基于Chromium实现的WebView.学到了很多东西,不过也挺累的,平均不到两个星期一篇文章.本来想休息一段时间后,再继续分析Chromium使用的JS引擎V8.不过某天晚上,躺在床上睡不着,鬼使神差想着去创建一个个人站点,用来连载<Android系统源代码情景分析>一书的内容. 事情是这样的,躺在床上睡不着,就去申请了一个域名,0xcc0xcd.com.域名申请到了,总不能

android开发难学吗? Android开发学习方法

Android开发难学吗?新手应该如何怎样学好android开发?现在学习android开发晚了吗?这些都是想学android开发(http://www.maiziedu.com/course/android-px/)的新手提出的疑惑,其中有些问题不是我们应该担心,既然喜欢了,那就去做,不做怎么知道学了android开发会不会给自己带来变化,那么新手应该如何学好android开发呢?现在就随着小编一起来看看. 1.Java基础 很多朋友一上手就开始学习Android,似乎太着急了一些.Andro

Android中Input型输入设备驱动原理分析(一)

转自:http://blog.csdn.net/eilianlau/article/details/6969361 话说Android中Event输入设备驱动原理分析还不如说Linux输入子系统呢,反正这个是没变的,在android的底层开发中对于Linux的基本驱动程序设计还是没变的,当然Android底层机制也增加几个属于android自己的机制.典型的IPC Android中的input设备驱动主要包括:游戏杆(joystick).鼠标(mouse)和事件设备(Event). 1.Inpu