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的服务功能,接下来分析其客户端的机制与实现。