Binder 驱动分析C(一)示例代码

提前声明:此文章为学习后的一些心得体会,若有错误请指出,如有侵权请联系。

Binder驱动不是单独拿出来分析,是结合在Android中的使用情景分析的,我们在此是结合Android Service来分析Binder驱动:

主要分析以下几部分:

  1.服务的注册过程;

  2.服务的获取和使用过程;

  3.transaction stack机制(replay和双向服务)。

在Android系统中,Binder的使用是很常见的,无论是java层、C++层还是C层使用Binder系统都是通过底层的Binder驱动。

  Binder的作用就是为了提供进程间通信的一种方法,Android中的service类似于网络通信中C/S模式,Binder的作用与http/UDP作用类似,只是提供的数据的通道;

  网络通讯中只要应用层序解析数据包的协议一致,我们就可以在不同的平台(windows、linux、mac)之间通信;

  Android中的service也一样,只要上层服务和客户端解析数据的协议一致,则C层、C++层和Java层都可以通过Binder进行通信。

我们在此分析由易到难,先分析C层的,然后分析C++和Java层的。

 

先贴出C层分析的代码:

可以参考 framework/native/cmds/servicemanager目录下的代码编写测试程序,在此我贴出简化版的的示例,仅用于分析;

一共有6个文件:

  binder.c binder.h service_manager.c test_client.c test_server.c test_server.h

  其中前3个文件可以在Android系统源码中找到。

1 #ifndef _TEST_SERVER_H
2 #define _TEST_SERVER_H
3 
4 #define HELLO_SVR_CMD_SAYHELLO     1
5 #define HELLO_SVR_CMD_SAYHELLO_TO  2
6 
7 #endif // _TEST_SERVER_H
test_server.h
  1 int svcmgr_publish(struct binder_state *bs, uint32_t target, const char *name, void *ptr)
  2 {
  3     int status;
  4     unsigned iodata[512/4];
  5     struct binder_io msg, reply;
  6 
  7     bio_init(&msg, iodata, sizeof(iodata), 4);
  8     bio_put_uint32(&msg, 0);  // strict mode header
  9     bio_put_string16_x(&msg, SVC_MGR_NAME);
 10     bio_put_string16_x(&msg, name);
 11     bio_put_obj(&msg, ptr);
 12 
 13     if (binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE))
 14         return -1;
 15 
 16     status = bio_get_uint32(&reply);
 17 
 18     binder_done(bs, &msg, &reply);
 19 
 20     return status;
 21 }
 22 
 23 void sayhello(void)
 24 {
 25     static int cnt = 0;
 26     fprintf(stderr, "say hello : %d\n", ++cnt);
 27 }
 28 
 29 
 30 int sayhello_to(char *name)
 31 {
 32     static int cnt = 0;
 33     fprintf(stderr, "say hello to %s : %d\n", name, ++cnt);
 34     return cnt;
 35 }
 36 
 37 int hello_service_handler(struct binder_state *bs,
 38                    struct binder_transaction_data *txn,
 39                    struct binder_io *msg,
 40                    struct binder_io *reply)
 41 {
 42     uint16_t *s;
 43     char name[512];
 44     size_t len;
 45     uint32_t handle;
 46     uint32_t strict_policy;
 47     int i;
 48 
 49     strict_policy = bio_get_uint32(msg);
 50 
 51     switch(txn->code) {
 52     case HELLO_SVR_CMD_SAYHELLO:
 53         sayhello();
 54         bio_put_uint32(reply, 0); 
 55         return 0;
 56 
 57     case HELLO_SVR_CMD_SAYHELLO_TO:
 58         s = bio_get_string16(msg, &len);  //"IHelloService"
 59         s = bio_get_string16(msg, &len);  // name
 60         if (s == NULL) {
 61             return -1;
 62         }
 63         for (i = 0; i < len; i++)
 64             name[i] = s[i];
 65         name[i] = '\0';
 66 
 67         i = sayhello_to(name);
 68 
 69         bio_put_uint32(reply, 0); /* no exception */
 70         bio_put_uint32(reply, i);
 71         
 72         break;
 73 
 74     default:
 75         fprintf(stderr, "unknown code %d\n", txn->code);
 76         return -1;
 77     }
 78 
 79     return 0;
 80 }
 81 
 82 int test_server_handler(struct binder_state *bs,
 83                    struct binder_transaction_data *txn,
 84                    struct binder_io *msg,
 85                    struct binder_io *reply)
 86 {
 87     int (*handler)(struct binder_state *bs,
 88                    struct binder_transaction_data *txn,
 89                    struct binder_io *msg,
 90                    struct binder_io *reply);
 91 
 92     handler = (int (*)(struct binder_state *bs,
 93                    struct binder_transaction_data *txn,
 94                    struct binder_io *msg,
 95                    struct binder_io *reply))txn->target.ptr;
 96     
 97     return handler(bs, txn, msg, reply);
 98 }
 99 
100 int main(int argc, char **argv)
101 {
102     int fd;
103     struct binder_state *bs;
104     uint32_t svcmgr = BINDER_SERVICE_MANAGER;
105     uint32_t handle;
106     int ret;
107 
108     bs = binder_open(128*1024);
109     if (!bs) {
110         fprintf(stderr, "failed to open binder driver\n");
111         return -1;
112     }
113 
114     /* add service */
115     ret = svcmgr_publish(bs, svcmgr, "hello", hello_service_handler);
116     if (ret) {
117         fprintf(stderr, "failed to publish hello service\n");
118         return -1;
119     }
120     
121     binder_set_maxthreads(bs, 10);
122 
123     binder_loop(bs, test_server_handler);
124 
125     return 0;
126 }
test_server.c
uint32_t svcmgr_lookup(struct binder_state *bs, uint32_t target, const char *name)
{
    uint32_t handle;
    unsigned iodata[512/4];
    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);

    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;
}


struct binder_state *g_bs;
uint32_t g_hello_handle;
uint32_t g_goodbye_handle;

void sayhello(void)
{
    unsigned iodata[512/4];
    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, "IHelloService");

    if (binder_call(g_bs, &msg, &reply, g_hello_handle, HELLO_SVR_CMD_SAYHELLO))
        return ;
    
    binder_done(g_bs, &msg, &reply);
    
}

int sayhello_to(char *name)
{
    unsigned iodata[512/4];
    struct binder_io msg, reply;
    int ret;
    int exception;

    bio_init(&msg, iodata, sizeof(iodata), 4);
    bio_put_uint32(&msg, 0);  // strict mode header
    bio_put_string16_x(&msg, "IHelloService");

    bio_put_string16_x(&msg, name);

    if (binder_call(g_bs, &msg, &reply, g_hello_handle, HELLO_SVR_CMD_SAYHELLO_TO))
        return 0;
    
    exception = bio_get_uint32(&reply);
    if (exception)
        ret = -1;
    else
        ret = bio_get_uint32(&reply);

    binder_done(g_bs, &msg, &reply);

    return ret;
    
}

/* ./test_client hello
 * ./test_client hello <name>
 */

int main(int argc, char **argv)
{
    int fd;
    struct binder_state *bs;
    uint32_t svcmgr = BINDER_SERVICE_MANAGER;
    uint32_t handle;
    int ret;

    if (argc < 2){
        fprintf(stderr, "Usage:\n");
        fprintf(stderr, "%s hello\n", argv[0]);
        fprintf(stderr, "%s hello <name>\n", argv[0]);
        return -1;
    }

    bs = binder_open(128*1024);
    if (!bs) {
        fprintf(stderr, "failed to open binder driver\n");
        return -1;
    }
    g_bs = bs;


    /* get service */
    handle = svcmgr_lookup(bs, svcmgr, "hello");
    g_hello_handle = handle;

    /* send data to server */
    if (argc == 2) {
        sayhello();
    } else if (argc == 3) {
        ret = sayhello_to(argv[2]);
        fprintf(stderr, "get ret of sayhello_to = %d\n", ret);        
    }
    
    binder_release(bs, handle);
    return 0;
}
test_client.c

为了避免后面晕头转向,先简单介绍一下Binder驱动相关的数据结构:

图片中完整的语句是:Handle是服务进程A对客户进程B提供的服务S的引用在客户进程B中的Index;

binder_proc

针对每个进程,使用binder_proc结构体描述,由于每个进程可能创建多个线程,所以其中的threads成员以红黑树管理着所有的线程;

其中的nodes成员管理着所有的binder_node结构,binder_node结构代表每个被注册的服务,这个成员一般是服务进程使用;

其中的refs_by_desc和refs_by_node成员管理着所有的binder_refs结构,binder_refs结构代表获取到的服务的引用,这个成员一般是客户进程使用;

binder_node 

针对每个被注册的服务,驱动程序会创建binder_node结构,用于描述注册的服务;

proc成员指向创建对应服务的进程;

cookie和ptr可以理解为服务的私有数据;

binder_refs

客户进程获取服务时,不是直接获取到服务所对应的binder_node结构,而是获取到它的引用,引用使用binder_refs结构描述;

其中的proc成员指向获取服务的进程;

node成员指向期望得到的服务所对应的binder_node结构;

desc为在某个进程中获取到的服务的索引值,该值只与在该进程中获取服务的先后有关;

注意:只有服务管理者(SM)的desc为0,其他服务的desc都是非0正整数。

 

一、服务的注册过程分析:

 

 

posted on 2017-11-23 10:27  黑大米  阅读(1424)  评论(0编辑  收藏  举报

导航