ServiceManager启动分析
 
简述:
  ServiceManager是一个全局的manager、调用了Jni函数,实现addServicew getService checkService listService等函数,
Server进程先注册一些service到SercviceManager中。
Client想获得一些service,就要到Service中去获取该Service。
这样,Server和Client之间就可以进行通讯了,
Server和Client之间的通讯都是通过Binder进行的。
 
 
三步走:
1.初始化Binder通讯环境,打开Binder设备,并映射内存。
2.注册自身为上下文管理者(context_manager)
3.进入无限循环的looping!!!
 
详细过程:
 
1 ,启动入口  一个标准的  main函数!

  1. int main(int argc, char **argv)
  2. {
  3. //记录serviceManager的状态
  4. struct binder_state *bs;
  5. void *svcmgr = BINDER_SERVICE_MANAGER;
  6. //用于打开binder设备 用于打开设备 后把设备映射到内存时申请的内存大小128*1024
  7. bs = binder_open(*);
  8. //注册自身为上下文管理者(context_manager)
  9. if (binder_become_context_manager(bs)) {
  10. ALOGE("cannot become context manager (%s)\n", strerror(errno));
  11. return -;
  12. }
  13.  
  14. svcmgr_handle = svcmgr;
  15. //loop无线循环,等待接收IPC同请求
  16. binder_loop(bs, svcmgr_handler);
  17. return ;
  18. }
 
2 bind_open函数。用来打开binder设备。 call
by1

  1. struct binder_state *binder_open(unsigned mapsize)
  2. {
  3. struct binder_state *bs;
  4.  
  5. bs = malloc(sizeof(*bs));
  6. if (!bs) {
  7. errno = ENOMEM;
  8. return ;
  9. }
  10.  
  11. bs->fd = open("/dev/binder", O_RDWR);//打开binder设备
  12. if (bs->fd < ) {
  13. fprintf(stderr,"binder: cannot open device (%s)\n",
  14. strerror(errno));
  15. goto fail_open;
  16. }
  17.  
  18. bs->mapsize = mapsize;//bs是用来保存open 和mmap的返回信息
  19. bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, );//进行内存映射,返回的映射区的起始地址给bs->mapped
  20. if (bs->mapped == MAP_FAILED) {//映射失败吹里逻辑
  21. fprintf(stderr,"binder: cannot map device (%s)\n",
  22. strerror(errno));
  23. goto fail_map;
  24. }
  25.  
  26. /* TODO: check version */
  27.  
  28. return bs;
  29.  
  30. fail_map://映射失败的 goto处。
  31. close(bs->fd);
  32. fail_open://打开设备失败的goto处。
  33. free(bs);
  34. return ;
 
 
3.设置上下文Manager call by1

  1. int binder_become_context_manager(struct binder_state *bs)
  2. {
  3. return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, );
  4. //直接用ioctl函数( 提供了一种获得设备信息和向设备发送控制参数的手段)来让设备Binder设置上下文
  5. }
 
4.进入loop。 call by 1
  1. void binder_loop(struct binder_state *bs, binder_handler func)
  2. {
  3. int res;
  4. struct binder_write_read bwr;
  5. unsigned readbuf[];
  6.  
  7. bwr.write_size = ;
  8. bwr.write_consumed = ;
  9. bwr.write_buffer = ;
  10. //设置事务类型,Binder Command 为 BC_ENTER_LOOPER
  11. readbuf[] = BC_ENTER_LOOPER;
  12. //在binder_write中调用了ioctl函数,调用Binder设备的函数,标志serviceManager进入的Loop 状态。
  13. binder_write(bs, readbuf, sizeof(unsigned));
  14.  
  15. for (;;) {
  16. bwr.read_size = sizeof(readbuf);
  17. bwr.read_consumed = ;
  18. bwr.read_buffer = (unsigned) readbuf;
  19. //每次循环都进入Binder设备的缓冲区中,看看是否有IPC请求。
  20. res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
  21.  
  22. if (res < ) {
  23. ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
  24. break;
  25. }
  26. //对获取的结果进行解析。
  27. res = binder_parse(bs, , readbuf, bwr.read_consumed, func);
  28. if (res == ) {
  29. ALOGE("binder_loop: unexpected reply?!\n");
  30. break;
  31. }
  32. if (res < ) {
  33. ALOGE("binder_loop: io error %d %s\n", res, strerror(errno));
  34. break;
  35. }
  36. }
  37. }
 
5.把返回的数据进行解析 call by 4

  1. int binder_parse(struct binder_state *bs, struct binder_io *bio,
  2. uint32_t *ptr, uint32_t size, binder_handler func)
  3. {
  4. int r = ;
  5. uint32_t *end = ptr + (size / );
  6.  
  7. while (ptr < end) {
  8. uint32_t cmd = *ptr++;
  9. #if TRACE
  10. fprintf(stderr,"%s:\n", cmd_name(cmd));
  11. #endif
  12. switch(cmd) {
  13. case BR_NOOP:
  14. break;
  15. case BR_TANSACTION_COMPLETE:
  16. break;R
  17. case BR_INCREFS:
  18. case BR_ACQUIRE:
  19. case BR_RELEASE:
  20. case BR_DECREFS:
  21. #if TRACE
  22. fprintf(stderr," %08x %08x\n", ptr[], ptr[]);
  23. #endif
  24. ptr += ;
  25. break;
  26. case BR_TRANSACTION: {
  27. struct binder_txn *txn = (void *) ptr;
  28. if ((end - ptr) * sizeof(uint32_t) < sizeof(struct binder_txn)) {
  29. ALOGE("parse: txn too small!\n");
  30. return -;
  31. }
  32. binder_dump_txn(txn);
  33. if (func) {
  34. unsigned rdata[/];
  35. struct binder_io msg;//
  36. struct binder_io reply;//回复信息的结构体
  37. int res;
  38.  
  39. bio_init(&reply, rdata, sizeof(rdata), );//数据的初始化
  40. bio_init_from_txn(&msg, txn);
  41. //fun函数中会进行事务最终的处理,add Service find service 注册 service
  42. res = func(bs, txn, &msg, &reply);
  43. binder_send_reply(bs, &reply, txn->data, res);
  44. }
  45. ptr += sizeof(*txn) / sizeof(uint32_t);
  46. break;
  47. }
  48. case BR_REPLY: {
  49. struct binder_txn *txn = (void*) ptr;
  50. if ((end - ptr) * sizeof(uint32_t) < sizeof(struct binder_txn)) {
  51. ALOGE("parse: reply too small!\n");
  52. return -;
  53. }
  54. binder_dump_txn(txn);
  55. if (bio) {
  56. bio_init_from_txn(bio, txn);
  57. bio = ;
  58. } else {
  59. /* todo FREE BUFFER */
  60. }
  61. ptr += (sizeof(*txn) / sizeof(uint32_t));
  62. r = ;
  63. break;
 
6 在该函数中会对事务进行相应的出路 callby 5

  1. int svcmgr_handler(struct binder_state *bs,
  2. struct binder_txn *txn,
  3. struct binder_io *msg,
  4. struct binder_io *reply)
  5. {
  6. struct svcinfo *si;
  7. uint16_t *s;
  8. unsigned len;
  9. void *ptr;
  10. uint32_t strict_policy;
  11. int allow_isolated;
  12.  
  13. // ALOGI("target=%p code=%d pid=%d uid=%d\n",
  14. // txn->target, txn->code, txn->sender_pid, txn->sender_euid);
  15.  
  16. if (txn->target != svcmgr_handle)
  17. return -;
  18.  
  19. // Equivalent to Parcel::enforceInterface(), reading the RPC
  20. // header with the strict mode policy mask and the interface name.
  21. // Note that we ignore the strict_policy and don't propagate it
  22. // further (since we do no outbound RPCs anyway).
  23. strict_policy = bio_get_uint32(msg);
  24. s = bio_get_string16(msg, &len);
  25. if ((len != (sizeof(svcmgr_id) / )) ||
  26. memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
  27. fprintf(stderr,"invalid id %s\n", str8(s));
  28. return -;
  29. }
  30.  
  31. switch(txn->code) {
  32. case SVC_MGR_GET_SERVICE:
  33. case SVC_MGR_CHECK_SERVICE:
  34. s = bio_get_string16(msg, &len);
  35. //查找相应的service
  36. ptr = do_find_service(bs, s, len, txn->sender_euid);//call 7
  37. if (!ptr)
  38. break;
  39. bio_put_ref(reply, ptr);
  40. return ;
  41.  
  42. case SVC_MGR_ADD_SERVICE:
  43. s = bio_get_string16(msg, &len);
  44. ptr = bio_get_ref(msg);
  45. allow_isolated = bio_get_uint32(msg) ? : ;
  46. //add service 进行service的注册。
  47. if (do_add_service(bs, s, len, ptr, txn->sender_euid, allow_isolated))
  48. return -;
  49. break;
  50.  
  51. case SVC_MGR_LIST_SERVICES: {
  52. unsigned n = bio_get_uint32(msg);
  53.  
  54. si = svclist;
  55. while ((n-- > ) && si)
  56. si = si->next;
  57. if (si) {
  58. bio_put_string16(reply, si->name);
  59. return ;
  60. }
  61. return -;
  62. }
  63. default:
  64. ALOGE("unknown code %d\n", txn->code);
  65. return -;
  66. }
  67.  
  68. bio_put_uint32(reply, );
  69. return ;
  70. }

7 查找service call by 6

  1. void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len, unsigned uid)
  2. {
  3. struct svcinfo *si;
  4. //最终的查找函数了
  5. si = find_svc(s, len);
  6.  
  7. // ALOGI("check_service('%s') ptr = %p\n", str8(s), si ? si->ptr : 0);
  8. if (si && si->ptr) {
  9. if (!si->allow_isolated) {
  10. // If this service doesn't allow access from isolated processes,
  11. // then check the uid to see if it is isolated.
  12. unsigned appid = uid % AID_USER;
  13. if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
  14. return ;
  15. }
  16. }
  17. return si->ptr;
  18. } else {
  19. return ;
  20. }
  21. }
 
 
8 最终的findservice动作是在这里结束 callby
7

  1. struct svcinfo *find_svc(uint16_t *s16, unsigned len)
  2. {
  3. struct svcinfo *si;//svcinfo就是一个链表的node数据结构,存放了service的信息
  4. //svclist存放了所有已经注册的了的 service,这里进行遍历,通过mencmp进行匹配
  5. for (si = svclist; si; si = si->next) {
  6. if ((len == si->len) &&
  7. !memcmp(s16, si->name, len * sizeof(uint16_t))) {
  8. return si;
  9. }
  10. }
  11. return ;
  12. }
 
9 注册服务 callby
6
 
  1. int do_add_service(struct binder_state *bs,
  2. uint16_t *s, unsigned len,
  3. void *ptr, unsigned uid, int allow_isolated)
  4. {
  5. struct svcinfo *si;
  6. //ALOGI("add_service('%s',%p,%s) uid=%d\n", str8(s), ptr,
  7. // allow_isolated ? "allow_isolated" : "!allow_isolated", uid);
  8.  
  9. if (!ptr || (len == ) || (len > ))
  10. return -;
  11. //验证UID是否有添加服务的权限。
  12. if (!svc_can_register(uid, s)) {
  13. ALOGE("add_service('%s',%p) uid=%d - PERMISSION DENIED\n",
  14. str8(s), ptr, uid);
  15. return -;
  16. }
  17. //判断服务是否存在,存在就不进行重复注册了。
  18. si = find_svc(s, len);
  19. if (si) {
  20. if (si->ptr) {
  21. ALOGE("add_service('%s',%p) uid=%d - ALREADY REGISTERED, OVERRIDE\n",
  22. str8(s), ptr, uid);
  23. svcinfo_death(bs, si);
  24. }
  25. si->ptr = ptr;
  26. } else {//不存在则为心注册的服务分配内存
  27. si = malloc(sizeof(*si) + (len + ) * sizeof(uint16_t));
  28. if (!si) {//分配内存失败
  29. ALOGE("add_service('%s',%p) uid=%d - OUT OF MEMORY\n",
  30. str8(s), ptr, uid);
  31. return -;
  32. }
  33. //为注册的服务的 scvinfo 结构体赋值,
  34. si->ptr = ptr;
  35. si->len = len;
  36. memcpy(si->name, s, (len + ) * sizeof(uint16_t));
  37. si->name[len] = '\0';
  38. si->death.func = svcinfo_death;
  39. si->death.ptr = si;
  40. si->allow_isolated = allow_isolated;
  41. //可见list的插入可以头插入法。
  42. si->next = svclist;
  43. svclist = si;
  44. }
  45.  
  46. binder_acquire(bs, ptr);
  47. binder_link_to_death(bs, ptr, &si->death);
  48. return ;
  49. }
 
 
10 判断当前uid是否具有注册service的权限,没有就拒绝 callby9
 
  1. int svc_can_register(unsigned uid, uint16_t *name)
  2. {
  3. unsigned n;
  4. if ((uid == ) || (uid == AID_SYSTEM))//uid=0为root用户, AID_SYSTEM为系统 service
  5. return ;
  6. //遍历允许注册service的进程数组
  7. for (n = ; n < sizeof(allowed) / sizeof(allowed[]); n++)
  8. if ((uid == allowed[n].uid) && str16eq(name, allowed[n].name))
  9. return ;
  10. return ;
  11. }

允许注册服务的进程列表(如果自定义rom自己增加系统服务,就可以在这里增加以获得权限啦)

  1. static struct {
  2. unsigned uid;
  3. const char *name;
  4. } allowed[] = {
  5. { AID_MEDIA, "media.audio_flinger" },
  6. { AID_MEDIA, "media.player" },
  7. { AID_MEDIA, "media.camera" },
  8. { AID_MEDIA, "media.audio_policy" },
  9. { AID_DRM, "drm.drmManager" },
  10. { AID_NFC, "nfc" },
  11. { AID_RADIO, "radio.phone" },
  12. { AID_RADIO, "radio.sms" },
  13. { AID_RADIO, "radio.phonesubinfo" },
  14. { AID_RADIO, "radio.simphonebook" },
  15. /* TODO: remove after phone services are updated: */
  16. { AID_RADIO, "phone" },
  17. { AID_RADIO, "sip" },
  18. { AID_RADIO, "isms" },
  19. { AID_RADIO, "iphonesubinfo" },
  20. { AID_RADIO, "simphonebook" },
  21. { AID_MEDIA, "common_time.clock" },
  22. { AID_MEDIA, "common_time.config" },
  23. };

  

Android Binder------ServiceManager启动分析的更多相关文章

  1. Android Zygote进程启动分析

    dvm,app进程,linux进程三者关系 DVM指 dalivk 的虚拟机.每一个 Android 应用程序都在它自己的进程中运行,都拥有一个独立的 Dalvik 虚拟机实例.而每一个 DVM 都是 ...

  2. 【转载】Android App应用启动分析与优化

    前言: 昨晚新版本终于发布了,但是还是记得有测试反馈app启动好长时间也没进入app主页,所以今天准备加个班总结一下App启动那些事! app的启动方式: 1.)冷启动  当启动应用时,后台没有该应用 ...

  3. 图解Android - Zygote, System Server 启动分析

    Init 是所有Linux程序的起点,而Zygote于Android,正如它的英文意思,是所有java程序的'孵化池'(玩过星际虫族的兄弟都晓得的).用ps 输出可以看到 >adb shell ...

  4. Android应用程序启动过程(二)分析

    本文依据Android6.0源码,从点击Launcher图标,直至解析到MainActivity#OnCreate()被调用. Launcher简析 Launcher也是个应用程序,不过是个特殊的应用 ...

  5. Android Binder分析二:Natvie Service的注冊

    这一章我们通过MediaPlayerService的注冊来说明怎样在Native层通过binder向ServiceManager注冊一个service,以及client怎样通过binder向Servi ...

  6. Android系统--Binder系统具体框架分析(二)Binder驱动情景分析

    Android系统--Binder系统具体框架分析(二)Binder驱动情景分析 1. Binder驱动情景分析 1.1 进程间通信三要素 源 目的:handle表示"服务",即向 ...

  7. Android ContentProvider 启动分析

    对于 ContentProvider 还不是很熟悉的同学,可以阅读上一篇 Android ContentProvider 基本原理和使用详解.本文主要是对 contentProvider 的源码进行分 ...

  8. Android Activity Deeplink启动来源获取源码分析

    一.前言 目前有很多的业务模块提供了Deeplink服务,Deeplink简单来说就是对外部应用提供入口. 针对不同的跳入类型,app可能会选择提供不一致的服务,这个时候就需要对外部跳入的应用进行区分 ...

  9. Android 4.2启动代码分析(一)

    Android系统启动过程分析 Android系统的框架架构图如下(来自网上):   Linux内核启动之后----->就到Android的Init进程 ----->进而启动Android ...

随机推荐

  1. POJ 1269 Intersecting Lines(几何)

    题目链接 题意 : 给你两条线段的起点和终点,一共四个点,让你求交点坐标,如果这四个点是共线的,输出“LINE”,如果是平行的就输出“NONE”. 思路 : 照着ZN留下的模板果然好用,直接套上模板了 ...

  2. NODE.JS的基本系统模块操作样例

    就练练手, 嘿嘿,说不定,写服务器脚本也可以哟. console.log('Currently executing file is ' + __filename); console.log('It i ...

  3. Android ViewPager的每个页面的显示与销毁的时机

    大家在用viewPager的时候要创建一个pagerAdapter对象,用于给viewPager设置页面的. viewPager里面有一个container容器. viewPager的容器缓存3个显示 ...

  4. c缺陷与陷阱笔记-第七章 可移植性代码

    1.移位运算符 如果被移位的对象长度是n位,那么移位计数必须>=0,并且<n,例如对于1个32位的数,移位运算n<<31和n<<0是OK的,n<<32和 ...

  5. APP,webapp 设计相关资料汇集区

    (1).@2x iPhone3GS时代,我们为一个应用提供图标(或按钮提供贴图),只需要icon.png.针对现在的iPhone4~6 Retina显示屏,需要制作额外的@2x高分辨率版本. 例如在i ...

  6. Java Web开发 之小张老师总结GET和POST区别

    get和post区别1.传输方式不同,get在request-line中传输(即在URL中传输).post在request-line及 request-body中传输(可认为隐藏传输)2.get传输长 ...

  7. H264码流解析及NALU

    ffmpeg 从mp4上提取H264的nalu http://blog.csdn.net/gavinr/article/details/7183499 639     /* bitstream fil ...

  8. CentOS7.1配置远程桌面

    网上看了很多资料,完全是乱的. 我使用的是CentOS7.1的系统.我的要求是windows的客户机可以远程访问CentOS系统. 1,首先需要检查一下服务器是否已经安装了VNC服务,检查服务器的是否 ...

  9. Servlet课程0426(十一)Servlet Cookie实现两周内不用重复登录

    Welcome.java //登录界面 package com.tsinghua; import javax.servlet.http.*; import java.io.*; import java ...

  10. 查看32bit的ARM(比如ARMv7)反汇编

    1.使用./arm-eabi-as test.S -o test.o编译 2.使用./arm-eabi-objdump -d test.o反汇编