Android 系统服务管家servicemanager启动过程详解
Android考虑到移动设备耗电以及跨进程通信效率等因素,基于OpenBinder专门为进程通信开发了一套框架:binder。例如,客户端程序需要获取WindowManager,TelephonyManager等系统服务时,就需要通过binder这个中介来负责数据与指令的传输。那么,Android提供了如此多的系统服务(可达上百个,可通过 adb shell service list
查看),又是谁在负责管理这些服务了?Android为此专门提供了一个系统管家servicemanager
。servicemanager
主要负责添加服务,获取服务,查找服务以及当某个服务意外终止时,对该服务的资源进行回收。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启动过程详解相关推荐
- Android init.rc文件解析过程详解(三)
Android init.rc文件解析过程详解(三) 三.相关结构体 1.listnode listnode结构体用于建立双向链表,这种结构广泛用于kernel代码中, android源代码中定义了l ...
- Android init.rc文件解析过程详解(一)
Android init.rc文件解析过程详解(一) 一.init.rc文件结构介绍 init.rc文件基本组成单位是section, section分为三种类型,分别由三个关键字(所谓关键字 ...
- php android 图片上传,android上传图片到PHP的过程详解
这篇文章主要介绍了android上传图片到PHP的过程详解,需要的朋友可以参考下 今天在做上传头像的时候,总是提交连接超时错误,报错信息如下:XXXXXXSokcetTimeOutXXXXXXXX 然 ...
- Android 系统服务 - PMS 的启动过程
相关文章链接: 1. Android Framework - 学习启动篇 2. Android 系统服务 - PMS 的启动过程 相关源码文件: frameworks/base/services/co ...
- 安卓 linux init.rc,[原创]Android init.rc文件解析过程详解(二)
Android init.rc文件解析过程详解(二) 3.parse_new_section代码如下: void parse_new_section(struct parse_state *state ...
- Linux开启动过程详解
Linux开启动过程详解 Linux启动过程 前言: Linux是一种自由和开放源代码的类UNIX操作系统.该操作系统的内核由林纳斯·托瓦兹在1991年10月5日首次发布.在加上用户空间的应用程序之后 ...
- centos7 启动流程图_Linux启动过程详解
Linux启动过程详解 作者:江远航 一.启动流程图如下 图1 Linux启动流程图 BIOS ---> MBR ---> Kernel---> Init 二.Linux启动顺序 一 ...
- Android init.rc文件解析过程详解(二)
Android init.rc文件解析过程详解(二) 3.parse_new_section代码如下: void parse_new_section(struct parse_state *state ...
- Delta3d框架学习--程序启动过程详解
一个Delta3d程序启动过程详解 一.初始化一个dtGame::GameApplication的实例,dtGame::GameApplication* app = new dtGame::GameA ...
最新文章
- Symbian错误查询
- 在Ubuntu下进行安卓开发遇到“insufficient permissions for device: user in plugdev group; ”问题的解决办法
- 配置vbox fedora虚拟机的VboxGuestAdditions
- Java并发教程–线程池
- mysql 获取昨天凌晨_MySQL慢日志体系建设
- FPGA同步复位与异步复位深度理解
- c++ 字符串合并_Python基础字符串处理
- IE下判断IE版本的语句...[if lte IE 8]……[endif]
- 神舟笔记本电脑更改启动盘顺序
- java实现PDF转tif格式并且设置颜色和dpi
- 【python+selenium】自动登陆学校青果教务网
- 店铺管理系统是智商税还是真有用?我们替你实测了最火的五个软件!市面上最火的五款店铺管理系统大测评!
- Pixelmator for Mac(全能图像编辑软件)
- layui upload上传携带额外参数
- Linux在sudo apt-get update或install时出现archive.ubuntu.com连接失败 [IP: 91.189.91.39 80]的错误解决方案
- 抓到Netty一个隐藏很深的内存泄露Bug | 详解Recycler对象池的精妙设计与实现
- 关闭VPN后,微信可以登录但是打不开网页的解决方案
- Redis(一)数据结构解析
- Xcode 真机调试失败:Errors were encountered while preparing your device for development
- 2021年工业软件行业研究报告
热门文章
- 【Edge游览器设置全局Dark模式】
- 设计师如何学习html_HTML5视频:设计师需要知道的10件事
- (Baseline)类定义LSTM识别imdb
- 脊髓横切面神经示意图,脊髓水平切面结构图
- smo算法matlab案例,SMO算法程序的使用
- android换机备份,安卓手机备份迁移指南
- Android适配 - 实现4.3以后NFC的CardReader模式
- SAP NetWeaver 7.01 SR1 SP3 ABAP Developer Edition 电驴下载
- WebPack实战 WebPack打包Vue项目
- HTML介绍 与基础操作