5.2.3 等待接收并处理IPC通信请求

servicemanager本身也是一个可以处理Client请求的Server进程,在其成为context manager之后,便可以响应Service组件注册服务的请求和Client组件使用服务的请求。当Service组件向servicemanager注册服务时,Service组件所在的进程对于servicemanager就是Client。

Client请求随时都可能到来,因此servicemanager进入一个无限循环等待处理Client发起的IPC请求,代码如下:


void binder_loop(struct binder_state*bs, binder_handler func)

{

int res;

//BINDER_WRITE_READ指令需要接收一个binder_write_read类型的参数

struct binder_write_read bwr;

unsigned readbuf[32];

//write_size赋值为0,Binder驱动中需要判断这个变量

bwr.write_size=0;

bwr.write_consumed=0;

bwr.write_buffer=0;

//BCENTER_LOOPER是Binder协议中的Binder Command指令,以BC为前缀

readbuf[0]=BC_ENTER_LOOPER;

//关键步骤:binder_write

binder_write(bs, readbuf, sizeof(unsigned));

for(;){//进入一个无限循环处理请求

bwr.read_size=sizeof(readbuf);

bwr.read_consumed=0;

bwr.read_buffer=(unsigned)readbuf;

//调用ioctl,将进入Binder Driver的binder_ioctl函数

res=ioctl(bs->fd, BINDER_WRITE_READ,&bwr);

//从Binder Driver中返回,正常情况res应该是>=0的

if(res<0){

break;

}

//调用binder_parse处理Binder请求

res=binder_parse(bs,0,readbuf, bwr.read_consumed, func);

if(res==0){

break;

}

if(res<0){

break;

}

}

}


binder_loop方法主要由binder_write函数调用和一个for无限循环组成。下面分析这两部分内容。

1.binder_write

binder_loop在进入无限循环之前有一个关键步骤:binder_write。传入该函数的参数bs是binder_state类型的结构体,传入的参数readbuf存储了BC_ENTER_LOOPER指令。

binder_write函数位于frameworks/base/cmds/servicemanager/binder.c中,代码如下:


int binder_write(struct binder_statebs, voiddata, unsigned len)

{

struct binder_write_read bwr;

int res;

bwr.write_size=len;//len:sizeof(unsigned)

bwr.write_consumed=0;

bwr.write_buffer=(unsigned)data;

bwr.read_size=0;//注意这里read_size为0,Binder驱动中需要判断该值

bwr.read_consumed=0;

bwr.read_buffer=0;

//用到了binder_open返回的bs结构体

//传入Binder ioctl指令BINDER_WRITE_READ

res=ioctl(bs->fd, BINDER_WRITE_READ,&bwr);

if(res<0){//ioctl failed

}

return res;

}


在binder_write中需要处理Binder ioctl指令BINDER_WRITE_READ。ioctl系统调用将导致Binder驱动层的binder_ioctl函数被调用,这里只分析BINDER_WRITE_READ指令的处理分支,代码如下:


static long binder_ioctl(struct file*filp, unsigned int cmd,

unsigned long arg)

{

int ret;

//binder_open返回的proc

struct binder_proc*proc=filp->private_data;

struct binder_thread*thread;

unsigned int size=_IOC_SIZE(cmd);

//arg表示进程空间的binder_write_read结构体,位于用户空间,需要转化

voiduser*ubuf=(voiduser*)arg;

ret=wait_event_interruptible(binder_user_error_wait,

binder_stop_on_user_error<2);

if(ret)

return ret;

mutex_lock(&binder_lock);

//从proc中获取当前线程,即servicemanager的main线程

thread=binder_get_thread(proc);

//匹配传入的ioctl指令

switch(cmd){

case BINDER_WRITE_READ:{

struct binder_write_read bwr;

……

//从用户空间复制bwr

if(copy_from_user(&bwr, ubuf, sizeof(bwr))){

ret=-EFAULT;

goto err;

}

//write_size在用户空间赋值为sizeof(unsigned)

if(bwr.write_size>0){

ret=binder_thread_write(proc, thread,

(void__user*)bwr.write_buffer,

bwr.write_size,&bwr.write_consumed);

……

}

//read_size在用户空间赋值为0

if(bwr.read_size>0){//省略该分支

}

if(copy_to_user(ubuf,&bwr, sizeof(bwr))){

ret=-EFAULT;

goto err;

}

break;

}

……

ret=0;

err:

……

return ret;

}


本次binder_ioctl调用会根据进程在用户空间设置的bwr.write_size值进入binder_thread_write函数,代码如下:


int binder_thread_write(struct binder_procproc, struct binder_threadthread,

void__userbuffer, int size, signed longconsumed)

{

uint32_t cmd;

void__userptr=buffer+consumed;

void__user*end=buffer+size;

while(ptr<end&&thread->return_error==BR_OK){

if(get_user(cmd,(uint32_t__user*)ptr))

return-EFAULT;

……

switch(cmd){

case BC_ENTER_LOOPER:

if(thread->looper&BINDER_LOOPER_STATE_REGISTERED)

{//错误状态

thread->looper|=BINDER_LOOPER_STATE_INVALID;

}

//设置BINDER_LOOPER_STATE_ENTERED标记

thread->looper|=BINDER_LOOPER_STATE_ENTERED;

break;


本次binder_thread_write调用进入BC_ENTER_LOOPER指令的处理分支,在该分支中将当前线程的looper标记设置为BINDER_LOOPER_STATE_ENTERED,该标记表示当前线程进入Binder Looper状态,即servicemanager马上要进入binder_looper函数的无限循环开始处理IPC请求。binder_thread_write执行完毕后,binder_ioctl函数便返回到用户空间的binder_write函数,接着进入binder_looper的无限循环中,此时当前线程真正进入Binder Looper状态。

2.Binder Looper状态

进入Looper状态后,首先在无限循环中发送一次Binder ioctl的BINDER_WRITE_READ指令;然后,再一次进入Binder驱动层的binder_ioctl函数。不过这次传入的binder_write_read结构体参数的write_size成员为0,read_size成员大于0。在binder_ioctl函数中依然匹配BINDER_WRITE_READ分支,但这次要调用的却不是binder_thread_write,而是binder_thread_read,代码如下:


switch(cmd){

case BINDER_WRITE_READ:{

struct binder_write_read bwr;

……//省略从用户空间复制binder_write_read结构体

if(bwr.write_size>0){//write_size为0

}

if(bwr.read_size>0){//read_size>0

ret=binder_thread_read(proc, thread,

(void__user*)bwr.read_buffer,

bwr.read_size,&bwr.read_consumed,

filp->f_flags&O_NONBLOCK);

if(!list_empty(&proc->todo))

wake_up_interruptible(&proc->wait);

if(ret<0){//错误处理

}

}

if(copy_to_user(ubuf,&bwr, sizeof(bwr))){

ret=-EFAULT;

goto err;

}

break;

}


在binder_looper的for循环中,每发送一次Binder ioctl指令最终都将调用Binder驱动层的binder_thread_read函数,该函数用于从Binder驱动中读取IPC请求数据。

当ioctl从驱动层返回后,便通过binder_parse方法解析返回数据。Binder驱动层可以返回多种BR指令给servicemanager,其中BR_TRANSACTION指令用于注册和检索Service。

binder_parse的代码如下:


int binder_parse(struct binder_statebs, struct binder_iobio,

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++;//读取BR指令

switch(cmd){

……

case BR_TRANSACTION:{

struct binder_txntxn=(void)ptr;

if((end-ptr)*sizeof(uint32_t)<sizeof(struct binder_txn)){

return-1;

}

binder_dump_txn(txn);

if(func){

unsigned rdata[256/4];

struct binder_io msg;//Binder驱动发送给当前进程的IPC数据

struct binder_io reply;//要写入Binder驱动的IPC数据

int res;

//初始化IPC数据

bio_init(&reply, rdata, sizeof(rdata),4);

bio_init_from_txn(&msg, txn);

//调用func处理BC_TRANSACTION指令,处理结果保存在reply中

res=func(bs, txn,&msg,&reply);

//将处理结果返回给Binder驱动程序

binder_send_reply(bs,&reply, txn->data, res);

}

ptr+=sizeof(*txn)/sizeof(uint32_t);

break;

}

……

default:

return-1;

}

}

return r;

}


servicemanager传入binder_loop的func参数由svcmgr_handler指定,Binder驱动发送给servicemanager的BR_TRANSACTION指令便由该函数处理,其代码如下:


int svcmgr_handler(struct binder_statebs, struct binder_txntxn,

struct binder_iomsg, struct binder_ioreply)

{

struct svcinfo*si;

uint16_t*s;

unsigned len;

void*ptr;

uint32_t strict_policy;

int allow_isolated;

//检查Binder驱动传递的txn-target是否为本函数

if(txn->target!=svcmgr_handle)

return-1;

//读取并校验传递过来的IPC数据

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))){

return-1;

}

//Binder驱动程序在接收到添加或者检索Service的请求后,会在txn的code中写入相应的请求指令

switch(txn->code){

case SVC_MGR_GET_SERVICE://对应Client的getService

case SVC_MGR_CHECK_SERVICE:

s=bio_get_string16(msg,&len);//与Parcel的处理方式类似

//响应上述两条指令,其处理方式一致

ptr=do_find_service(bs, s,len, txn->sender_euid);

if(!ptr)

break;

bio_put_ref(reply, ptr);

return 0;

case SVC_MGR_ADD_SERVICE://对应Client的addService

s=bio_get_string16(msg,&len);

ptr=bio_get_ref(msg);

allow_isolated=bio_get_uint32(msg)?1:0;

if(do_add_service(bs, s,len, ptr, txn->sender_euid, allow_isolated))

return-1;

break;

case SVC_MGR_LIST_SERVICES:{//遍历服务

……

}

default:

return-1;

}

bio_put_uint32(reply,0);

return 0;

}


可见,servicemanager接收到Binder驱动层的BR_TRANSACTION指令后,对应的操作有do_find_service和do_add_service,分别对应于Client端的getService和addService方法。接下来分析这两个方法。

(1)do_add_service

do_add_service完成了addService请求。其代码如下:


int do_add_service(struct binder_statebs, uint16_ts, unsigned len,

void*ptr, unsigned uid, int allow_isolated)

{

struct svcinfo*si;

if(!ptr||(len==0)||(len>127))

return-1;

//验证该UID是否具备添加服务的权限(PERMISSION DENIED)

if(!svc_can_register(uid, s)){

return-1;

}

//从服务列表svclist中查询是否已经存在该服务的注册信息

si=find_svc(s, len);

if(si){

if(si->ptr){//已经注册过

svcinfo_death(bs, si);

}

si->ptr=ptr;

}else{

//为新注册的服务分配内存

si=malloc(sizeof(si)+(len+1)sizeof(uint16_t));

if(!si){//溢出

return-1;

}

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;

si->next=svclist;

svclist=si;//将新注册的服务信息存入svclist链表

}

//服务异常退出后,接收Binder设备发送的服务退出通知,这样可以清理一些资源

binder_acquire(bs, ptr);

binder_link_to_death(bs, ptr,&si->death);

return 0;

}


do_add_service首先需要检查发起请求的进程是否有权限注册服务,该功能由svc_can_register函数完成,其代码如下:


int svc_can_register(unsigned uid, uint16_t*name)

{

unsigned n;

//uid为0表示root用户,为AID_SYSTEM表示system用户,这两个用户可以注册服务

if((uid==0)||(uid==AID_SYSTEM))

return 1;

//如果不是root和system用户,则要遍历allowed数组,该数组定义了允许注册服务的UID列表

for(n=0;n<sizeof(allowed)/sizeof(allowed[0]);n++)

if((uid==allowed[n].uid)&&str16eq(name, allowed[n].name))

return 1;

return 0;

}


可见,并不是所有进程都有权限注册服务的。有权限注册服务的除了root和system用户外,还可以在allowed结构体数组中定义,代码如下:


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"},

};


可见Android系统通过UID限制可注册服务的Server,系统开发者可以在allowed数组中添加自定义Server,让其具备可注册Service的权限。Service注册后,会被添加到servicemanager中的svclist列表。接下来分析如何检索Service。

(2)do_find_service

do_find_service对应的是Client的getService方法,其代码如下:


voiddo_find_service(struct binder_statebs, uint16_t*s, unsigned len, unsigned uid)

{

struct svcinfo*si;

si=find_svc(s, len);//从svclist链表检索已注册服务信息

if(si&&si->ptr){

if(!si->allow_isolated){

unsigned appid=uid%AID_USER;

if(appid>=AID_ISOLATED_START&&appid<=AID_ISOLATED_END){

return 0;

}

}

return si->ptr;

}else{

return 0;

}

}


检索Service的方法很简单,只是从svclist列表中查找指定服务并返回。

servicemanager进程相当于C/S体系结构的Server端,其运行了检索Service、添加Service的服务功能,接下来分析其客户端的机制与实现。