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
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 }
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; }
为了避免后面晕头转向,先简单介绍一下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正整数。
一、服务的注册过程分析: