Android考虑到移动设备耗电以及跨进程通信效率等因素,基于OpenBinder专门为进程通信开发了一套框架:binder。例如,客户端程序需要获取WindowManager,TelephonyManager等系统服务时,就需要通过binder这个中介来负责数据与指令的传输。那么,Android提供了如此多的系统服务(可达上百个,可通过 adb shell service list查看),又是谁在负责管理这些服务了?Android为此专门提供了一个系统管家servicemanagerservicemanager主要负责添加服务,获取服务,查找服务以及当某个服务意外终止时,对该服务的资源进行回收。ServiceManager跨越了两个框架层:Java层、C++层。这篇文章先看一看native(C)层的具体实现原理。

源码路径:

  • C++: /android/frameworks/native/cmds/servicemanager/
  • Java: /android/frameworks/base/core/java/android/os/

servicemanager的启动

Android在init进程启动以后,通过脚本init.rc,启动ServiceManager:

    service servicemanager /system/bin/servicemanagerclass coreuser systemgroup systemcriticalonrestart restart healthdonrestart restart zygoteonrestart restart mediaonrestart restart surfaceflingeronrestart restart keystore

service_manager.c中找到对应的main()函数,这是servicemanager启动的入口:

    int main(){struct binder_state *bs;// 打开binderbs = binder_open(128*1024);if (!bs) {ALOGE("failed to open binder driver\n");return -1;}// 成为系统服务的管家if (binder_become_context_manager(bs)) {ALOGE("cannot become context manager (%s)\n", strerror(errno));return -1;}....// 进入binder循环binder_loop(bs, svcmgr_handler);return 0;}

main函数里主要做了三件事:一是打开binder文件节点,并分配IPC所需的内存;二让ServiceManager成为系统服务的管家(context manager);三开启相应的工作线程,并循环处理IPC请求。

binder_open

函数binder_open()主要作用:(1)打开binder设备文件,获取到对应的文件描述符,(2)从Binder驱动获取binder版本号,(3)接着创建一个binder内存区域,用于跨进程数据的交换(这里大小为128K)。

    struct binder_state *binder_open(size_t mapsize){struct binder_state *bs;struct binder_version vers;// 为binder_state分配内存空间bs = malloc(sizeof(*bs));if (!bs) {errno = ENOMEM;return NULL;}// 打开Binder驱动对应的文件节点,最终调用驱动函数binder_openbs->fd = open("/dev/binder", O_RDWR | O_CLOEXEC);// 获取当前Binder版本号if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||(vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {fprintf(stderr,"binder: kernel driver version (%d) differs from user space version (%d)\n",vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION);goto fail_open;}//分配一块只读内存区域,用于IPC交换数据,最终调用binder驱动接口binder_mmapbs->mapsize = mapsize;bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);if (bs->mapped == MAP_FAILED) {fprintf(stderr,"binder: cannot map device (%s)\n",strerror(errno));goto fail_map;}return bs;fail_map:close(bs->fd);fail_open:free(bs);return NULL;}

binder相关的ioctl指令定义在 /android/kernel/drivers/staging/android/uapi/binder.h

    #define BINDER_WRITE_READ       _IOWR('b', 1, struct binder_write_read)#define BINDER_SET_IDLE_TIMEOUT     _IOW('b', 3, __s64)#define BINDER_SET_MAX_THREADS      _IOW('b', 5, __u32)#define BINDER_SET_IDLE_PRIORITY    _IOW('b', 6, __s32)#define BINDER_SET_CONTEXT_MGR      _IOW('b', 7, __s32)#define BINDER_THREAD_EXIT      _IOW('b', 8, __s32)#define BINDER_VERSION          _IOWR('b', 9, struct binder_version)

binder驱动提供了诸如ioctl,mmap,open,flush等操作,在驱动初始化时会将其注册到系统中

    static const struct file_operations binder_fops = {.owner = THIS_MODULE,.poll = binder_poll,.unlocked_ioctl = binder_ioctl,.compat_ioctl = binder_ioctl,.mmap = binder_mmap,.open = binder_open,.flush = binder_flush,.release = binder_release,};static struct miscdevice binder_miscdev = {.minor = MISC_DYNAMIC_MINOR,.name = "binder",.fops = &binder_fops};

binder_become_context_manager

    int binder_become_context_manager(struct binder_state *bs){// 系统调用,告知binder驱动,ServiceManager将成为系统服务管家,对应的handle为0return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);}

系统调用ioctl最终会调用binder驱动对应的操作函数。查看binder驱动的代码,在/android/kernel/drivers/staging/android/binder.c中有一个函数binder_ioctl,这就是用于处理kernel系统调用ioctl对应的指令,找到请求BINDER_SET_CONTEXT_MGR对应的代码,在设置系统服务管家完成后,返回对应的结果。

    static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){int ret;struct binder_proc *proc = filp->private_data;struct binder_thread *thread;unsigned int size = _IOC_SIZE(cmd);void __user *ubuf = (void __user *)arg;ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);// 加锁binder_lock(__func__);thread = binder_get_thread(proc);switch (cmd) {....// 设置服务管家case BINDER_SET_CONTEXT_MGR:ret = binder_ioctl_set_ctx_mgr(filp);if (ret)goto err;break;....// 查询Binder版本case BINDER_VERSION: {struct binder_version __user *ver = ubuf;if (put_user_preempt_disabled(BINDER_CURRENT_PROTOCOL_VERSION, &ver->protocol_version)) {ret = -EINVAL;goto err;}break;}default:ret = -EINVAL;goto err;}ret = 0;....}

binder_loop

    void binder_loop(struct binder_state *bs, binder_handler func){int res;struct binder_write_read bwr;uint32_t readbuf[32];bwr.write_size = 0;bwr.write_consumed = 0;bwr.write_buffer = 0;readbuf[0] = BC_ENTER_LOOPER;// 让ServiceManager线程进入循环binder_write(bs, readbuf, sizeof(uint32_t));for (;;) {bwr.read_size = sizeof(readbuf);bwr.read_consumed = 0;bwr.read_buffer = (uintptr_t) readbuf;// 读取 driver中的数据res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);// 解析读取到的数据,并通过svcmgr_handler进行处理res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);....}}

读取到binder驱动缓冲区域里的数据后,解析之:

    int binder_parse(struct binder_state *bs, struct binder_io *bio,uintptr_t ptr, size_t size, binder_handler func){int r = 1;uintptr_t end = ptr + (uintptr_t) size;while (ptr < end) {uint32_t cmd = *(uint32_t *) ptr;ptr += sizeof(uint32_t);switch(cmd) {case BR_NOOP:break;case BR_TRANSACTION_COMPLETE:break;case BR_INCREFS:case BR_ACQUIRE:case BR_RELEASE:case BR_DECREFS:ptr += sizeof(struct binder_ptr_cookie);break;case BR_TRANSACTION: {struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;....if (func) {unsigned rdata[256/4];struct binder_io msg;struct binder_io reply;int res;bio_init(&reply, rdata, sizeof(rdata), 4);bio_init_from_txn(&msg, txn);// 处理客户端请求,func就是函数svcmgr_handlerres = func(bs, txn, &msg, &reply);if (txn->flags & TF_ONE_WAY) {binder_free_buffer(bs, txn->data.ptr.buffer);} else {// 发送回复给客户端binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);}}ptr += sizeof(*txn);break;}case BR_REPLY: {struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;if ((end - ptr) < sizeof(*txn)) {ALOGE("parse: reply too small!\n");return -1;}binder_dump_txn(txn);if (bio) {bio_init_from_txn(bio, txn);bio = 0;} else {/* todo FREE BUFFER */}ptr += sizeof(*txn);r = 0;break;}case BR_DEAD_BINDER: {struct binder_death *death = (struct binder_death *)(uintptr_t) *(binder_uintptr_t *)ptr;ptr += sizeof(binder_uintptr_t);death->func(bs, death->ptr);break;}case BR_FAILED_REPLY:r = -1;break;....default:ALOGE("parse: OOPS %d\n", cmd);return -1;}}return r;}

svcmgr_handler处理客户端的请求,如添加服务,查找服务以及获取服务等。

    int svcmgr_handler(struct binder_state *bs,struct binder_transaction_data *txn,struct binder_io *msg,struct binder_io *reply){struct svcinfo *si;uint16_t *s;size_t len;uint32_t handle;uint32_t strict_policy;int allow_isolated;if (txn->target.ptr != BINDER_SERVICE_MANAGER)return -1;if (txn->code == PING_TRANSACTION)return 0;   ....switch(txn->code) {case SVC_MGR_GET_SERVICE:case SVC_MGR_CHECK_SERVICE:s = bio_get_string16(msg, &len);if (s == NULL) {return -1;}handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);if (!handle)break;bio_put_ref(reply, handle);return 0;case SVC_MGR_ADD_SERVICE:s = bio_get_string16(msg, &len);if (s == NULL) {return -1;}handle = bio_get_ref(msg);allow_isolated = bio_get_uint32(msg) ? 1 : 0;if (do_add_service(bs, s, len, handle, txn->sender_euid,allow_isolated, txn->sender_pid))return -1;break;case SVC_MGR_LIST_SERVICES: {uint32_t n = bio_get_uint32(msg);if (!svc_can_list(txn->sender_pid, txn->sender_euid)) {ALOGE("list_service() uid=%d - PERMISSION DENIED\n",txn->sender_euid);return -1;}si = svclist;while ((n-- > 0) && si)si = si->next;if (si) {bio_put_string16(reply, si->name);return 0;}return -1;}default:ALOGE("unknown code %d\n", txn->code);return -1;}bio_put_uint32(reply, 0);return 0;}

这里总结下ServiceManager进程启动的过程,其流程简图如下:

  • binder_open(): 打开驱动设备节点,并为进程分配一个128K大小的内存区域用于IPC数据交换;
  • binder_become_context_manager(): 使servicemanager称为系统服务的管家;
  • binder_loop(): 进入线程执行状态,等待客户端程序的请求

参考文献

  • http://gityuan.com/android/

Android 系统服务管家servicemanager启动过程详解相关推荐

  1. Android init.rc文件解析过程详解(三)

    Android init.rc文件解析过程详解(三) 三.相关结构体 1.listnode listnode结构体用于建立双向链表,这种结构广泛用于kernel代码中, android源代码中定义了l ...

  2. Android init.rc文件解析过程详解(一)

        Android init.rc文件解析过程详解(一) 一.init.rc文件结构介绍 init.rc文件基本组成单位是section, section分为三种类型,分别由三个关键字(所谓关键字 ...

  3. php android 图片上传,android上传图片到PHP的过程详解

    这篇文章主要介绍了android上传图片到PHP的过程详解,需要的朋友可以参考下 今天在做上传头像的时候,总是提交连接超时错误,报错信息如下:XXXXXXSokcetTimeOutXXXXXXXX 然 ...

  4. Android 系统服务 - PMS 的启动过程

    相关文章链接: 1. Android Framework - 学习启动篇 2. Android 系统服务 - PMS 的启动过程 相关源码文件: frameworks/base/services/co ...

  5. 安卓 linux init.rc,[原创]Android init.rc文件解析过程详解(二)

    Android init.rc文件解析过程详解(二) 3.parse_new_section代码如下: void parse_new_section(struct parse_state *state ...

  6. Linux开启动过程详解

    Linux开启动过程详解 Linux启动过程 前言: Linux是一种自由和开放源代码的类UNIX操作系统.该操作系统的内核由林纳斯·托瓦兹在1991年10月5日首次发布.在加上用户空间的应用程序之后 ...

  7. centos7 启动流程图_Linux启动过程详解

    Linux启动过程详解 作者:江远航 一.启动流程图如下 图1 Linux启动流程图 BIOS ---> MBR ---> Kernel---> Init 二.Linux启动顺序 一 ...

  8. Android init.rc文件解析过程详解(二)

    Android init.rc文件解析过程详解(二) 3.parse_new_section代码如下: void parse_new_section(struct parse_state *state ...

  9. Delta3d框架学习--程序启动过程详解

    一个Delta3d程序启动过程详解 一.初始化一个dtGame::GameApplication的实例,dtGame::GameApplication* app = new dtGame::GameA ...

最新文章

  1. Symbian错误查询
  2. 在Ubuntu下进行安卓开发遇到“insufficient permissions for device: user in plugdev group; ”问题的解决办法
  3. 配置vbox fedora虚拟机的VboxGuestAdditions
  4. Java并发教程–线程池
  5. mysql 获取昨天凌晨_MySQL慢日志体系建设
  6. FPGA同步复位与异步复位深度理解
  7. c++ 字符串合并_Python基础字符串处理
  8. IE下判断IE版本的语句...[if lte IE 8]……[endif]
  9. 神舟笔记本电脑更改启动盘顺序
  10. java实现PDF转tif格式并且设置颜色和dpi
  11. 【python+selenium】自动登陆学校青果教务网
  12. 店铺管理系统是智商税还是真有用?我们替你实测了最火的五个软件!市面上最火的五款店铺管理系统大测评!
  13. Pixelmator for Mac(全能图像编辑软件)
  14. layui upload上传携带额外参数
  15. Linux在sudo apt-get update或install时出现archive.ubuntu.com连接失败 [IP: 91.189.91.39 80]的错误解决方案
  16. 抓到Netty一个隐藏很深的内存泄露Bug | 详解Recycler对象池的精妙设计与实现
  17. 关闭VPN后,微信可以登录但是打不开网页的解决方案
  18. Redis(一)数据结构解析
  19. Xcode 真机调试失败:Errors were encountered while preparing your device for development
  20. 2021年工业软件行业研究报告

热门文章

  1. 【Edge游览器设置全局Dark模式】
  2. 设计师如何学习html_HTML5视频:设计师需要知道的10件事
  3. (Baseline)类定义LSTM识别imdb
  4. 脊髓横切面神经示意图,脊髓水平切面结构图
  5. smo算法matlab案例,SMO算法程序的使用
  6. android换机备份,安卓手机备份迁移指南
  7. Android适配 - 实现4.3以后NFC的CardReader模式
  8. SAP NetWeaver 7.01 SR1 SP3 ABAP Developer Edition 电驴下载
  9. WebPack实战 WebPack打包Vue项目
  10. HTML介绍 与基础操作