资讯专栏INFORMATION COLUMN

android servicemanager与binder源码分析一 ------ native层的

马忠志 / 875人阅读

摘要:以版本源码为例。源码位于下打开驱动设备,将自己作为的管理者,进入循环,作为等待的请求位于首先,建立一个结构体,然后剩下的就是给这个结构体的成员赋值。同属于这一层,因此我们看看具体内容刚才从驱动设备读取的的前位取出来作为进行判断处理。

前一阵子在忙项目,没什么更新,这次开始写点android源码内部的东西分析下。以6.0.1_r10版本android源码为例。
servicemanager是android服务管理,非常基础的组件之一,分析他的目的是能够深入看到binder的一些处理方式。在开始前先说下阅读源码或者非常复杂代码的方式,我的方式是层级进入,一层掌握脉络之后如果感兴趣再对具体的点深入分析了解,并且每层进行总结,这样我认为会比较好理解,也不容易产生一个点一直走下去,最后迷失在复杂繁琐的代码里的情况。当然我只代表我个人的体验。东西是写给自己的,如果能帮到他人我会非常高兴。

然后这里推荐下罗升阳先生的博客文章,确实非常不错,可以作为阅读参考。

servicemanager源码位于/frameworks/native/cmds/servicemanager/service_manager.c下:

</>复制代码

  1. 347int main(int argc, char **argv)
  2. 348{
  3. 349 struct binder_state *bs;
  4. 350
  5. 351 bs = binder_open(128*1024);
  6. 352 if (!bs) {
  7. 353 ALOGE("failed to open binder driver
  8. ");
  9. 354 return -1;
  10. 355 }
  11. 356
  12. 357 if (binder_become_context_manager(bs)) {
  13. 358 ALOGE("cannot become context manager (%s)
  14. ", strerror(errno));
  15. 359 return -1;
  16. 360 }
  17. 361
  18. 362 selinux_enabled = is_selinux_enabled();
  19. 363 sehandle = selinux_android_service_context_handle();
  20. 364 selinux_status_open(true);
  21. 365
  22. 366 if (selinux_enabled > 0) {
  23. 367 if (sehandle == NULL) {
  24. 368 ALOGE("SELinux: Failed to acquire sehandle. Aborting.
  25. ");
  26. 369 abort();
  27. 370 }
  28. 371
  29. 372 if (getcon(&service_manager_context) != 0) {
  30. 373 ALOGE("SELinux: Failed to acquire service_manager context. Aborting.
  31. ");
  32. 374 abort();
  33. 375 }
  34. 376 }
  35. 377
  36. 378 union selinux_callback cb;
  37. 379 cb.func_audit = audit_callback;
  38. 380 selinux_set_callback(SELINUX_CB_AUDIT, cb);
  39. 381 cb.func_log = selinux_log_callback;
  40. 382 selinux_set_callback(SELINUX_CB_LOG, cb);
  41. 383
  42. 384 binder_loop(bs, svcmgr_handler);
  43. 385
  44. 386 return 0;
  45. 387}

1.binder_open打开binder驱动设备;
2.binder_become_context_manager(bs),将自己作为binder的管理者;
3.binder_loop(bs, svcmgr_handler),进入循环,作为server等待client的请求;

binder_open

位于/frameworks/native/cmds/servicemanager/binder.c:

</>复制代码

  1. 96struct binder_state *binder_open(size_t mapsize)
  2. 97{
  3. 98 struct binder_state *bs;
  4. 99 struct binder_version vers;
  5. 100
  6. 101 bs = malloc(sizeof(*bs));
  7. 102 if (!bs) {
  8. 103 errno = ENOMEM;
  9. 104 return NULL;
  10. 105 }
  11. 106
  12. 107 bs->fd = open("/dev/binder", O_RDWR);
  13. 108 if (bs->fd < 0) {
  14. 109 fprintf(stderr,"binder: cannot open device (%s)
  15. ",
  16. 110 strerror(errno));
  17. 111 goto fail_open;
  18. 112 }
  19. 113
  20. 114 if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||
  21. 115 (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {
  22. 116 fprintf(stderr,
  23. 117 "binder: kernel driver version (%d) differs from user space version (%d)
  24. ",
  25. 118 vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION);
  26. 119 goto fail_open;
  27. 120 }
  28. 121
  29. 122 bs->mapsize = mapsize;
  30. 123 bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
  31. 124 if (bs->mapped == MAP_FAILED) {
  32. 125 fprintf(stderr,"binder: cannot map device (%s)
  33. ",
  34. 126 strerror(errno));
  35. 127 goto fail_map;
  36. 128 }
  37. 129
  38. 130 return bs;
  39. 131
  40. 132fail_map:
  41. 133 close(bs->fd);
  42. 134fail_open:
  43. 135 free(bs);
  44. 136 return NULL;
  45. 137}

首先,建立一个结构体binder_state,然后剩下的就是给这个结构体的成员赋值。bs->fd给打开的驱动设备文件描述符;bs->mapped给内存映射地址;
插一句,这里对goto的应用很规范,可见任何语句并非有好与不好,而在于怎么用。
看到这里其实可以猜测,binder的机制就是内存映射,或者可以说是文件映射,因为在linux上任何的设备都可以看做是文件。
现在不要深入,往回看,之前的service_manager.c的main函数里,后面就要走binder_become_context_manager这个将自己设为binder管理者。

</>复制代码

  1. 146int binder_become_context_manager(struct binder_state *bs)
  2. 147{
  3. 148 return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
  4. 149}

这里就做了一件事儿,就是下发控制字,告诉驱动设置context管理者为0,这里也可以猜测,这个0代表一定含义,应该就是servicemanager自己,后面再继续解释这个问题。

binder_looper

</>复制代码

  1. 372void binder_loop(struct binder_state *bs, binder_handler func)
  2. 373{
  3. 374 int res;
  4. 375 struct binder_write_read bwr;
  5. 376 uint32_t readbuf[32];
  6. 377
  7. 378 bwr.write_size = 0;
  8. 379 bwr.write_consumed = 0;
  9. 380 bwr.write_buffer = 0;
  10. 381
  11. 382 readbuf[0] = BC_ENTER_LOOPER;
  12. 383 binder_write(bs, readbuf, sizeof(uint32_t));
  13. 384
  14. 385 for (;;) {
  15. 386 bwr.read_size = sizeof(readbuf);
  16. 387 bwr.read_consumed = 0;
  17. 388 bwr.read_buffer = (uintptr_t) readbuf;
  18. 389
  19. 390 res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
  20. 391
  21. 392 if (res < 0) {
  22. 393 ALOGE("binder_loop: ioctl failed (%s)
  23. ", strerror(errno));
  24. 394 break;
  25. 395 }
  26. 396
  27. 397 res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
  28. 398 if (res == 0) {
  29. 399 ALOGE("binder_loop: unexpected reply?!
  30. ");
  31. 400 break;
  32. 401 }
  33. 402 if (res < 0) {
  34. 403 ALOGE("binder_loop: io error %d %s
  35. ", res, strerror(errno));
  36. 404 break;
  37. 405 }
  38. 406 }

1.先通过binder_write下发了一个BC_ENTER_LOOPER控制字,表示要驱动设备进入looper状态(binder_write内部也是走的ioctrl BINDER_WRITE_READ写入驱动设备);
2.进入死循环,不停从设备读取数据,成功读取到之后,进入binder_parse函数;
3.binder_parse,从字面看是解析binder,但是具体做什么不清楚,只能猜测是对刚才读取到的内容进行处理。
同属于binder.c这一层,因此我们看看binder_parse具体内容:

</>复制代码

  1. 204int binder_parse(struct binder_state *bs, struct binder_io *bio,
  2. 205 uintptr_t ptr, size_t size, binder_handler func)
  3. 206{
  4. 207 int r = 1;
  5. 208 uintptr_t end = ptr + (uintptr_t) size;
  6. 209
  7. 210 while (ptr < end) {
  8. 211 uint32_t cmd = *(uint32_t *) ptr;
  9. 212 ptr += sizeof(uint32_t);
  10. 213#if TRACE
  11. 214 fprintf(stderr,"%s:
  12. ", cmd_name(cmd));
  13. 215#endif
  14. 216 switch(cmd) {
  15. 217 case BR_NOOP:
  16. 218 break;
  17. 219 case BR_TRANSACTION_COMPLETE:
  18. 220 break;
  19. 221 case BR_INCREFS:
  20. 222 case BR_ACQUIRE:
  21. 223 case BR_RELEASE:
  22. 224 case BR_DECREFS:
  23. 225#if TRACE
  24. 226 fprintf(stderr," %p, %p
  25. ", (void *)ptr, (void *)(ptr + sizeof(void *)));
  26. 227#endif
  27. 228 ptr += sizeof(struct binder_ptr_cookie);
  28. 229 break;
  29. 230 case BR_TRANSACTION: {
  30. 231 struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
  31. 232 if ((end - ptr) < sizeof(*txn)) {
  32. 233 ALOGE("parse: txn too small!
  33. ");
  34. 234 return -1;
  35. 235 }
  36. 236 binder_dump_txn(txn);
  37. 237 if (func) {
  38. 238 unsigned rdata[256/4];
  39. 239 struct binder_io msg;
  40. 240 struct binder_io reply;
  41. 241 int res;
  42. 242
  43. 243 bio_init(&reply, rdata, sizeof(rdata), 4);
  44. 244 bio_init_from_txn(&msg, txn);
  45. 245 res = func(bs, txn, &msg, &reply);
  46. 246 binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
  47. 247 }
  48. 248 ptr += sizeof(*txn);
  49. 249 break;
  50. 250 }
  51. 251 case BR_REPLY: {
  52. 252 struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
  53. 253 if ((end - ptr) < sizeof(*txn)) {
  54. 254 ALOGE("parse: reply too small!
  55. ");
  56. 255 return -1;
  57. 256 }
  58. 257 binder_dump_txn(txn);
  59. 258 if (bio) {
  60. 259 bio_init_from_txn(bio, txn);
  61. 260 bio = 0;
  62. 261 } else {
  63. 262 /* todo FREE BUFFER */
  64. 263 }
  65. 264 ptr += sizeof(*txn);
  66. 265 r = 0;
  67. 266 break;
  68. 267 }
  69. 268 case BR_DEAD_BINDER: {
  70. 269 struct binder_death *death = (struct binder_death *)(uintptr_t) *(binder_uintptr_t *)ptr;
  71. 270 ptr += sizeof(binder_uintptr_t);
  72. 271 death->func(bs, death->ptr);
  73. 272 break;
  74. 273 }
  75. 274 case BR_FAILED_REPLY:
  76. 275 r = -1;
  77. 276 break;
  78. 277 case BR_DEAD_REPLY:
  79. 278 r = -1;
  80. 279 break;
  81. 280 default:
  82. 281 ALOGE("parse: OOPS %d
  83. ", cmd);
  84. 282 return -1;
  85. 283 }
  86. 284 }
  87. 285
  88. 286 return r;
  89. 287}

刚才从驱动设备读取的buffer的前32位取出来作为cmd进行switch判断处理。BR_代表从设备驱动反馈的命令,BR_TRANSACTION字面看是交易,那么可以猜测是对接受到的发送方(client)的内容进行处理。往下看,BR_TRANSACTION流程里,先把收到的数据转成binder_transaction_data结构,然后走了binder_dump_txn,这里基本上就是输出一些信息,不太关注。之后是关键的部分,调用了func,这个东西是个binder_handler,其实看看定义就知道,是个回调函数,回到servicemanager里面的main,可以看到是个svcmgr_handler,具体内容也在servicemanager里面,如下:

</>复制代码

  1. 244int svcmgr_handler(struct binder_state *bs,
  2. 245 struct binder_transaction_data *txn,
  3. 246 struct binder_io *msg,
  4. 247 struct binder_io *reply)
  5. 248{
  6. 249 struct svcinfo *si;
  7. 250 uint16_t *s;
  8. 251 size_t len;
  9. 252 uint32_t handle;
  10. 253 uint32_t strict_policy;
  11. 254 int allow_isolated;
  12. 255
  13. 256 //ALOGI("target=%p code=%d pid=%d uid=%d
  14. ",
  15. 257 // (void*) txn->target.ptr, txn->code, txn->sender_pid, txn->sender_euid);
  16. 258
  17. 259 if (txn->target.ptr != BINDER_SERVICE_MANAGER)
  18. 260 return -1;
  19. 261
  20. 262 if (txn->code == PING_TRANSACTION)
  21. 263 return 0;
  22. 264
  23. 265 // Equivalent to Parcel::enforceInterface(), reading the RPC
  24. 266 // header with the strict mode policy mask and the interface name.
  25. 267 // Note that we ignore the strict_policy and don"t propagate it
  26. 268 // further (since we do no outbound RPCs anyway).
  27. 269 strict_policy = bio_get_uint32(msg);
  28. 270 s = bio_get_string16(msg, &len);
  29. 271 if (s == NULL) {
  30. 272 return -1;
  31. 273 }
  32. 274
  33. 275 if ((len != (sizeof(svcmgr_id) / 2)) ||
  34. 276 memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
  35. 277 fprintf(stderr,"invalid id %s
  36. ", str8(s, len));
  37. 278 return -1;
  38. 279 }
  39. 280
  40. 281 if (sehandle && selinux_status_updated() > 0) {
  41. 282 struct selabel_handle *tmp_sehandle = selinux_android_service_context_handle();
  42. 283 if (tmp_sehandle) {
  43. 284 selabel_close(sehandle);
  44. 285 sehandle = tmp_sehandle;
  45. 286 }
  46. 287 }
  47. 288
  48. 289 switch(txn->code) {
  49. 290 case SVC_MGR_GET_SERVICE:
  50. 291 case SVC_MGR_CHECK_SERVICE:
  51. 292 s = bio_get_string16(msg, &len);
  52. 293 if (s == NULL) {
  53. 294 return -1;
  54. 295 }
  55. 296 handle = do_find_service(bs, s, len, txn->sender_euid, txn->sender_pid);
  56. 297 if (!handle)
  57. 298 break;
  58. 299 bio_put_ref(reply, handle);
  59. 300 return 0;
  60. 301
  61. 302 case SVC_MGR_ADD_SERVICE:
  62. 303 s = bio_get_string16(msg, &len);
  63. 304 if (s == NULL) {
  64. 305 return -1;
  65. 306 }
  66. 307 handle = bio_get_ref(msg);
  67. 308 allow_isolated = bio_get_uint32(msg) ? 1 : 0;
  68. 309 if (do_add_service(bs, s, len, handle, txn->sender_euid,
  69. 310 allow_isolated, txn->sender_pid))
  70. 311 return -1;
  71. 312 break;
  72. 313
  73. 314 case SVC_MGR_LIST_SERVICES: {
  74. 315 uint32_t n = bio_get_uint32(msg);
  75. 316
  76. 317 if (!svc_can_list(txn->sender_pid)) {
  77. 318 ALOGE("list_service() uid=%d - PERMISSION DENIED
  78. ",
  79. 319 txn->sender_euid);
  80. 320 return -1;
  81. 321 }
  82. 322 si = svclist;
  83. 323 while ((n-- > 0) && si)
  84. 324 si = si->next;
  85. 325 if (si) {
  86. 326 bio_put_string16(reply, si->name);
  87. 327 return 0;
  88. 328 }
  89. 329 return -1;
  90. 330 }
  91. 331 default:
  92. 332 ALOGE("unknown code %d
  93. ", txn->code);
  94. 333 return -1;
  95. 334 }
  96. 335
  97. 336 bio_put_uint32(reply, 0);
  98. 337 return 0;
  99. 338}

简单看下,就是对传递的数据的具体处理,包括了addservice等具体的过程处理。暂时先不深究。

至此我们可以看出来,servicemanager->binder.c这层基本上就是servicemanager提供系统的服务管理,binder.c提供对驱动设备的操作api。整个过程再梳理下:
1.打开binder驱动设备;
2.将自己作为binder上下文的管理者,通过binder.c传递0给设备驱动(ioctrl);
3.进入binder_looper循环,不停从binder设备驱动读取内容,并解析,然后根据cmd判断后抛给servicemanager进行真正处理;
4.servicemanager里再根据读取到的数据内容来决定进行各种cmd动作的处理,包括addservice等;
这么看这一层的脉络基本上比较清晰了。这么写把binder独立了出来作为一个api层,可以搭载任何的生成调用,也就是说binder.c这一层只管与binder设备驱动通讯,其余的抛给调用者,很标准聪明的解耦。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/65009.html

相关文章

  • android servicemanagerbinder源码分析三------如何进入内核通讯

    摘要:的构造传递进入的就是。如果状态是,直接返回。到底是否正确呢看代码先创建一个对象,这个对象是个存储读写内容的对象。然后终于进入了内核驱动的部分。 承接上文,从getService开始,要开始走binder的通讯机制了。首先是上文的java层 /frameworks/base/core/java/android/os/ServiceManagerNative.java: 118 pu...

    lijy91 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<