多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
上面提到的switch/case语句,将实现IServiceManager中定义的各个业务函数,我们重点看do_add_service这个函数,它最终完成了对addService请求的处理实现,代码如下所示: **Service_manager.c** ~~~ int do_add_service(struct binder_state *bs,uint16_t*s, unsigned len, void*ptr, unsigned uid) { structsvcinfo *si; if (!ptr|| (len == 0) || (len > 127)) return -1; //svc_can_register函数比较注册进程的uid和名字。 if(!svc_can_register(uid, s)) { return -1; ...... ~~~ 将上面的函数暂时放一下,先介绍svc_can_register函数。 1. 不是什么都可以注册的 do_add_service函数中的svc_can_register,是用来判断注册服务的进程是否有权限的,代码如下所示: **Service_manager.c** ~~~ int svc_can_register(unsigned uid, uint16_t *name) { unsignedn; //如果用户组是root用户或者system用户,则权限够高,允许注册 if ((uid== 0) || (uid == AID_SYSTEM)) return 1; for (n =0; n < sizeof(allowed) / sizeof(allowed[0]); n++) if((uid == allowed[n].uid) && str16eq(name, allowed[n].name)) return 1; return 0; } ~~~ allowed结构数组,控制那些权限达不到root和system的进程,它的定义如下所示: ~~~ static struct { unsigneduid; constchar *name; } allowed[] = { #ifdef LVMX {AID_MEDIA, "com.lifevibes.mx.ipc" }, #endif {AID_MEDIA, "media.audio_flinger" }, {AID_MEDIA, "media.player" }, {AID_MEDIA, "media.camera" }, {AID_MEDIA, "media.audio_policy" }, {AID_RADIO, "radio.phone" }, {AID_RADIO, "radio.sms" }, {AID_RADIO, "radio.phonesubinfo" }, {AID_RADIO, "radio.simphonebook" }, {AID_RADIO, "phone" }, {AID_RADIO, "isms" }, {AID_RADIO, "iphonesubinfo" }, {AID_RADIO, "simphonebook" }, }; ~~~ 所以,如果Server进程权限不够root和system,那么请记住要在allowed中添加相应的项。 2. 添加服务项 再回到我们的do_add_service,如下所示: **Service_manager.c** ~~~ int do_add_service(struct binder_state *bs,uint16_t*s, unsigned len, void *ptr, unsigned uid){ ...... //接前面的代码 si =find_svc(s, len); if (si) { if(si->ptr) { return -1; } si->ptr = ptr; } else { si =malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t)); if(!si) { return -1; } //ptr是关键数据,可惜为void*类型。只有分析驱动的实现才能知道它的真实含义了。 si->ptr = ptr; si->len = len; memcpy(si->name, s, (len + 1) * sizeof(uint16_t)); si->name[len] = '\0'; si->death.func = svcinfo_death;//service退出的通知函数 si->death.ptr = si; //这个svclist是一个list,保存了当前注册到ServiceManager中的信息。 si->next = svclist; svclist = si; } binder_acquire(bs,ptr); /* 我们希望当服务进程退出后,ServiceManager能有机会做一些清理工作,例如释放前面malloc出来的si。 binder_link_to_death完成这项工作,每当有服务进程退出时,ServiceManager都会得到来自 Binder设备的通知。 */ binder_link_to_death(bs, ptr, &si->death); return 0; } ~~~ 至此,服务注册分析完毕。可以知道,ServiceManager不过就是保存了一些服务的信息。那么,这样做又有什么意义呢?