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函数! 复制代码
int main(int argc, char **argv){//记录serviceManager的状态struct binder_state *bs;void *svcmgr = BINDER_SERVICE_MANAGER;//用于打开binder设备 用于打开设备 后把设备映射到内存时申请的内存大小128*1024bs = binder_open(128*1024);//注册自身为上下文管理者(context_manager)if (binder_become_context_manager(bs)) {ALOGE("cannot become context manager (%s)\n", strerror(errno));return -1;}svcmgr_handle = svcmgr;//loop无线循环,等待接收IPC同请求binder_loop(bs, svcmgr_handler);return 0;}
复制代码

 

  2 bind_open函数。用来打开binder设备。 call by1
复制代码
struct binder_state *binder_open(unsigned mapsize){struct binder_state *bs;bs = malloc(sizeof(*bs));if (!bs) {errno = ENOMEM;return 0;}bs->fd = open("/dev/binder", O_RDWR);//打开binder设备if (bs->fd < 0) {fprintf(stderr,"binder: cannot open device (%s)\n",strerror(errno));goto fail_open;}bs->mapsize = mapsize;//bs是用来保存open 和mmap的返回信息bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);//进行内存映射,返回的映射区的起始地址给bs->mappedif (bs->mapped == MAP_FAILED) {//映射失败吹里逻辑fprintf(stderr,"binder: cannot map device (%s)\n",strerror(errno));goto fail_map;}/* TODO: check version */return bs;fail_map://映射失败的 goto处。close(bs->fd);fail_open://打开设备失败的goto处。free(bs);return 0;
复制代码

 

    3.设置上下文Manager call by1
int binder_become_context_manager(struct binder_state *bs){return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);//直接用ioctl函数( 提供了一种获得设备信息和向设备发送控制参数的手段)来让设备Binder设置上下文} 
  4.进入loop。 call by 1   复制代码
void binder_loop(struct binder_state *bs, binder_handler func){int res;struct binder_write_read bwr;unsigned readbuf[32];bwr.write_size = 0;bwr.write_consumed = 0;bwr.write_buffer = 0;//设置事务类型,Binder Command 为 BC_ENTER_LOOPERreadbuf[0] = BC_ENTER_LOOPER;//在binder_write中调用了ioctl函数,调用Binder设备的函数,标志serviceManager进入的Loop 状态。binder_write(bs, readbuf, sizeof(unsigned));for (;;) {bwr.read_size = sizeof(readbuf);bwr.read_consumed = 0;bwr.read_buffer = (unsigned) readbuf;//每次循环都进入Binder设备的缓冲区中,看看是否有IPC请求。res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);if (res < 0) {ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));break;}//对获取的结果进行解析。res = binder_parse(bs, 0, readbuf, bwr.read_consumed, func);if (res == 0) {ALOGE("binder_loop: unexpected reply?!\n");break;}if (res < 0) {ALOGE("binder_loop: io error %d %s\n", res, strerror(errno));break;}}}
复制代码

 

  5.把返回的数据进行解析 call by 4   复制代码
int binder_parse(struct binder_state *bs, struct binder_io *bio,uint32_t *ptr, uint32_t size, binder_handler func){int r = 1;uint32_t *end = ptr + (size / 4);while (ptr < end) {uint32_t cmd = *ptr++;#if TRACEfprintf(stderr,"%s:\n", cmd_name(cmd));#endifswitch(cmd) {case BR_NOOP:break;case BR_TANSACTION_COMPLETE:break;Rcase BR_INCREFS:case BR_ACQUIRE:case BR_RELEASE:case BR_DECREFS:#if TRACEfprintf(stderr," %08x %08x\n", ptr[0], ptr[1]);#endifptr += 2;break;case BR_TRANSACTION: {struct binder_txn *txn = (void *) ptr;if ((end - ptr) * sizeof(uint32_t) < sizeof(struct binder_txn)) {ALOGE("parse: txn too small!\n");return -1;}binder_dump_txn(txn);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);//fun函数中会进行事务最终的处理,add Service find service 注册 serviceres = func(bs, txn, &msg, &reply);binder_send_reply(bs, &reply, txn->data, res);}ptr += sizeof(*txn) / sizeof(uint32_t);break;}case BR_REPLY: {struct binder_txn *txn = (void*) ptr;if ((end - ptr) * sizeof(uint32_t) < sizeof(struct binder_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) / sizeof(uint32_t));r = 0;break;
复制代码

 

  6 在该函数中会对事务进行相应的出路 callby 5
复制代码
int svcmgr_handler(struct binder_state *bs,struct binder_txn *txn,struct binder_io *msg,struct binder_io *reply){struct svcinfo *si;uint16_t *s;unsigned len;void *ptr;uint32_t strict_policy;int allow_isolated;// ALOGI("target=%p code=%d pid=%d uid=%d\n",// txn->target, txn->code, txn->sender_pid, txn->sender_euid);if (txn->target != svcmgr_handle)return -1;// Equivalent to Parcel::enforceInterface(), reading the RPC// header with the strict mode policy mask and the interface name.// Note that we ignore the strict_policy and don't propagate it// further (since we do no outbound RPCs anyway).strict_policy = bio_get_uint32(msg);s = bio_get_string16(msg, &len);if ((len != (sizeof(svcmgr_id) / 2)) ||memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {fprintf(stderr,"invalid id %s\n", str8(s));return -1;}switch(txn->code) {case SVC_MGR_GET_SERVICE:case SVC_MGR_CHECK_SERVICE:s = bio_get_string16(msg, &len);//查找相应的serviceptr = do_find_service(bs, s, len, txn->sender_euid);//call 7if (!ptr)break;bio_put_ref(reply, ptr);return 0;case SVC_MGR_ADD_SERVICE:s = bio_get_string16(msg, &len);ptr = bio_get_ref(msg);allow_isolated = bio_get_uint32(msg) ? 1 : 0;//add service 进行service的注册。if (do_add_service(bs, s, len, ptr, txn->sender_euid, allow_isolated))return -1;break;case SVC_MGR_LIST_SERVICES: {unsigned n = bio_get_uint32(msg);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;} 
复制代码

 

7 查找service call by 6

复制代码
void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len, unsigned uid){struct svcinfo *si;//最终的查找函数了si = find_svc(s, len);// ALOGI("check_service('%s') ptr = %p\n", str8(s), si ? si->ptr : 0);if (si && si->ptr) {if (!si->allow_isolated) {// If this service doesn't allow access from isolated processes,// then check the uid to see if it is isolated.unsigned appid = uid % AID_USER;if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {return 0;}}return si->ptr;} else {return 0;}}
复制代码

 

    8 最终的findservice动作是在这里结束 callby 7
复制代码
struct svcinfo *find_svc(uint16_t *s16, unsigned len){struct svcinfo *si;//svcinfo就是一个链表的node数据结构,存放了service的信息//svclist存放了所有已经注册的了的 service,这里进行遍历,通过mencmp进行匹配for (si = svclist; si; si = si->next) {if ((len == si->len) &&!memcmp(s16, si->name, len * sizeof(uint16_t))) {return si;}}return 0;}
复制代码

 

  9 注册服务 callby 6   复制代码
int do_add_service(struct binder_state *bs,uint16_t *s, unsigned len,void *ptr, unsigned uid, int allow_isolated){struct svcinfo *si;//ALOGI("add_service('%s',%p,%s) uid=%d\n", str8(s), ptr,// allow_isolated ? "allow_isolated" : "!allow_isolated", uid);if (!ptr || (len == 0) || (len > 127))return -1;//验证UID是否有添加服务的权限。if (!svc_can_register(uid, s)) {ALOGE("add_service('%s',%p) uid=%d - PERMISSION DENIED\n",str8(s), ptr, uid);return -1;}//判断服务是否存在,存在就不进行重复注册了。si = find_svc(s, len);if (si) {if (si->ptr) {ALOGE("add_service('%s',%p) uid=%d - ALREADY REGISTERED, OVERRIDE\n",str8(s), ptr, uid);svcinfo_death(bs, si);}si->ptr = ptr;} else {//不存在则为心注册的服务分配内存si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));if (!si) {//分配内存失败ALOGE("add_service('%s',%p) uid=%d - OUT OF MEMORY\n",str8(s), ptr, uid);return -1;}//为注册的服务的 scvinfo 结构体赋值,si->ptr = ptr;si->len = len;memcpy(si->name, s, (len + 1) * sizeof(uint16_t));si->name[len] = '\0';si->death.func = svcinfo_death;si->death.ptr = si;si->allow_isolated = allow_isolated;//可见list的插入可以头插入法。si->next = svclist;svclist = si;}binder_acquire(bs, ptr);binder_link_to_death(bs, ptr, &si->death);return 0;}
复制代码

 

    10 判断当前uid是否具有注册service的权限,没有就拒绝 callby9   复制代码
int svc_can_register(unsigned uid, uint16_t *name){unsigned n;if ((uid == 0) || (uid == AID_SYSTEM))//uid=0为root用户, AID_SYSTEM为系统 servicereturn 1;//遍历允许注册service的进程数组for (n = 0; n < sizeof(allowed) / sizeof(allowed[0]); n++)if ((uid == allowed[n].uid) && str16eq(name, allowed[n].name))return 1;return 0;}
复制代码

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

?
static  struct  { unsigned uid; const  char  *name; } allowed[] = { { AID_MEDIA, "media.audio_flinger"  }, { AID_MEDIA, "media.player"  }, { AID_MEDIA, "media.camera"  }, { AID_MEDIA, "media.audio_policy"  }, { AID_DRM, "drm.drmManager"  }, { AID_NFC, "nfc"  }, { AID_RADIO, "radio.phone"  }, { AID_RADIO, "radio.sms"  }, { AID_RADIO, "radio.phonesubinfo"  }, { AID_RADIO, "radio.simphonebook"  }, /* TODO: remove after phone services are updated: */ { AID_RADIO, "phone"  }, { AID_RADIO, "sip"  }, { AID_RADIO, "isms"  }, { AID_RADIO, "iphonesubinfo"  }, { AID_RADIO, "simphonebook"  }, { AID_MEDIA, "common_time.clock"  }, { AID_MEDIA, "common_time.config"  }, };

更多相关文章

  1. 通过ua检测浏览页面的设备是phone还是tablet
  2. Android中ImageButton自定义按钮的按下效果的代码实现方法,附网上
  3. Android下intent的setdata、settype和setdataandtype函数
  4. Android使用okhttp框架实现带参数Get和Post请求(附服务端完整代码
  5. C基础—函数指针,联合体,枚举,结构体和结构体指针
  6. Android ListView 滚动条的设置详解及实例代码
  7. Android NDK c调用java代码

随机推荐

  1. android popupwindow 动画 特效 案例
  2. EditText的属性说明
  3. android之微信分享图片
  4. Android(安卓)简单通用的基类
  5. Android(安卓)Studio 中的maven仓库使用
  6. Android三种网络通讯机制介绍及区别
  7. Android高仿360安全卫士--布局篇
  8. Android(安卓)OKHTTP3.4版本封装
  9. 判断手机是否支持google play服务
  10. Android画画板的制作方法