Android 10 启动之servicemanager源码解析
作者:格子里的梦
正文
上一篇文章:
在前文提到,init进程会在在Trigger 为init的Action中,启动servicemanager服务,这篇文章我们就来具体分析一下servicemanager服务,它到底做了哪些事情。
servicemanager服务的源码位于/frameworks/native/cmds/servicemanager/service_manager.c
,我们将从这个类的入口开始看起。
int main(int argc, char** argv) { struct binder_state *bs; union selinux_callback cb; char *driver; if (argc > 1) { driver = argv[1]; } else { //启动时默认无参数,走这个分支 driver = "/dev/binder"; } //打开binder驱动,并设置mmap的内存大小为128k bs = binder_open(driver, 128*1024); ... if (binder_become_context_manager(bs)) { ALOGE("cannot become context manager (%s)\n", strerror(errno)); return -1; } cb.func_audit = audit_callback; selinux_set_callback(SELINUX_CB_AUDIT, cb); #ifdef VENDORSERVICEMANAGER cb.func_log = selinux_vendor_log_callback; #else cb.func_log = selinux_log_callback; #endif selinux_set_callback(SELINUX_CB_LOG, cb); #ifdef VENDORSERVICEMANAGER sehandle = selinux_android_vendor_service_context_handle(); #else sehandle = selinux_android_service_context_handle(); #endif selinux_status_open(true); if (sehandle == NULL) { ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n"); abort(); } if (getcon(&service_manager_context) != 0) { ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n"); abort(); } /* binder_loop已封装如下步骤: while (1) { /* read data */ /* parse data, and process */ /* reply */ } */ binder_loop(bs, svcmgr_handler); return 0; }
从main函数中可以看出,它主要做了三件事情:
- 打开/dev/binder设备,并在内存中映射128K的空间。
- 通知Binder设备,把自己变成context_manager,其他用户进程都通过0号句柄访问ServiceManager。
- 进入循环,不停的去读Binder设备,看是否有对service的请求,如果有的话,就去调用svcmgr_handler函数回调处理请求。
我们再来看看svcmgr_handler函数的实现:
int svcmgr_handler(struct binder_state *bs, struct binder_transaction_data_secctx *txn_secctx, 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; uint32_t dumpsys_priority; struct binder_transaction_data *txn = &txn_secctx->transaction_data; 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, (const char*) txn_secctx->secctx); 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; dumpsys_priority = bio_get_uint32(msg); if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority, txn->sender_pid, (const char*) txn_secctx->secctx)) return -1; break; case SVC_MGR_LIST_SERVICES: { uint32_t n = bio_get_uint32(msg); uint32_t req_dumpsys_priority = bio_get_uint32(msg); if (!svc_can_list(txn->sender_pid, (const char*) txn_secctx->secctx, txn->sender_euid)) { ALOGE("list_service() uid=%d - PERMISSION DENIED\n", txn->sender_euid); return -1; } si = svclist; // walk through the list of services n times skipping services that // do not support the requested priority while (si) { if (si->dumpsys_priority & req_dumpsys_priority) { if (n == 0) break; n--; } 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; }
我们先来认识一下binder的数据传输载体binder_transaction_data
:
struct binder_transaction_data { union { /* 当binder_transaction_data是由用户空间的进程发送给Binder驱动时, handle是该事务的发送目标在Binder驱动中的信息,即该事务会交给handle来处理; handle的值是目标在Binder驱动中的Binder引用。*/ __u32 handle; /* 当binder_transaction_data是有Binder驱动反馈给用户空间进程时, ptr是该事务的发送目标在用户空间中的信息,即该事务会交给ptr对应的服务来处理; ptr是处理该事务的服务的服务在用户空间的本地Binder对象。*/ binder_uintptr_t ptr; } target; // 该事务的目标对象(即,该事务数据包是给该target来处理的) // 只有当事务是由Binder驱动传递给用户空间时,cookie才有意思,它的值是处理该事务的ServerC++层的本地Binder对象 binder_uintptr_t cookie; // 事务编码。如果是请求,则以BC_开头;如果是回复,则以BR_开头。 __u32 code; /* General information about the transaction. */ __u32 flags; //表示事务发起者的pid和uid。 pid_t sender_pid; uid_t sender_euid; // 数据大小 binder_size_t data_size; //数据偏移量 binder_size_t offsets_size; //data是一个共用体,当通讯数据很小的时,可以直接使用buf[8]来保存数据。当够大时,只能用指针buffer来描述一个申请的数据缓冲区。 union { struct { /* transaction data */ binder_uintptr_t buffer; binder_uintptr_t offsets; } ptr; __u8 buf[8]; } data; };
可以看到,svcmgr_handler函数中对binder data的事务编码进行了判断,并分别对SVC_MGR_GET_SERVICE(SVC_MGR_CHECK_SERVICE)
、SVC_MGR_ADD_SERVICE
、SVC_MGR_LIST_SERVICES
三种类型的事务编码做了业务处理。
获取服务
case SVC_MGR_CHECK_SERVICE: s = bio_get_string16(msg, &len); ptr = do_find_service(bs, s, len); if (!ptr) break; bio_put_ref(reply, ptr); return 0;
do_find_service函数中主要执行service的查找,并把找到的服务句柄写入reply,返回给客户端。
uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid, const char* sid) { struct svcinfo *si = find_svc(s, len); ... return si->handle; }
我们继续看find_svc函数:
struct svcinfo *find_svc(const uint16_t *s16, size_t len) { struct svcinfo *si; for (si = svclist; si; si = si->next) { if ((len == si->len) && !memcmp(s16, si->name, len * sizeof(uint16_t))) { return si; } } return NULL; }
svclist 是一个单向链表,储存了所有向servicemanager注册的服务信息。find_svc遍历svclist链表,通过服务名称作为索引条件,最终找到符合条件的服务。
注册服务
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; dumpsys_priority = bio_get_uint32(msg); if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority, txn->sender_pid, (const char*) txn_secctx->secctx)) return -1;
我们继续看do_add_service函数中做了哪些事情。
在该函数中,首先会去检查客户端是否有权限注册service,如果没有权限就直接返回,不能注册。
if (!svc_can_register(s, len, spid, sid, uid)) { ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n", str8(s, len), handle, uid); return -1; }
然后会去检查该service是否已经注册过了,如果已经注册过,那么就不能再注册了。
si = find_svc(s, len); if (si) { if (si->handle) { ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n", str8(s, len), handle, uid); svcinfo_death(bs, si); } si->handle = handle; }
再判断内存是否足够。
si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t)); if (!si) { ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n", str8(s, len), handle, uid); return -1; }
如果都没什么问题,会注册该service,并加入到svcList链表中。
综上所述,servicemanager主要负责查询和注册其他的系统服务,是系统服务的管理者。
文章的最后,留给大家一个问题进行思考:
为什么Android需要设计servicemanager做中转来添加和获取系统服务,而不直接让客户端去获取服务端句柄?
更多关于Android 10 启动之servicemanager的资料请关注脚本之家其它相关文章!