5.4 Client端使用服务代理对象

上节分析了AudioFlinger服务的创建和注册过程,本节分析该服务的Client端和服务代理对象的实现。Client端需要调用服务代理对象的接口才能跨进程访问Server端提供的服务。

frameworks/av/media/libmedia/AudioSystem. cpp中定义了一个get_audio_flinger方法使用到AudioFlinger服务,其使用服务的核心代码如下:


const sp<IAudioFlinger>&AudioSystem:get_audio_flinger()

{

Mutex:Autolock_l(gLock);

if(gAudioFlinger==0){

sp<IServiceManager>sm=defaultServiceManager();

sp<IBinder>binder;

do{

binder=sm->getService(String16("media.audio_flinger"));

if(binder!=0)

break;

//getService返回NULL,此时认为AudioFlinger服务还未注册,等待0.5s

usleep(500000);//0.5 s

}while(true);

if(gAudioFlingerClient==NULL){

gAudioFlingerClient=new AudioFlingerClient();

}else{

if(gAudioErrorCallback){

gAudioErrorCallback(NO_ERROR);

}

}

binder->linkToDeath(gAudioFlingerClient);

gAudioFlinger=interface_cast<IAudioFlinger>(binder);

gAudioFlinger->registerClient(gAudioFlingerClient);

}

return gAudioFlinger;

}


前面章节已经分析过,defaultServiceManager返回的是BpServiceManager,接着以AudioFlinger的服务名为参数调用其getService方法,代码如下:


virtual sp<IBinder>getService(const String16&name)const

{

unsigned n;

for(n=0;n<5;n++){//最多尝试5次,每次等待1毫秒

sp<IBinder>svc=checkService(name);

if(svc!=NULL)return svc;

sleep(1);

}

return NULL;

}

virtual sp<IBinder>checkService(const String16&name)const

{

Parcel data, reply;

data.writeInterfaceToken(//"android.os.IServiceManager"

IServiceManager:getInterfaceDescriptor());

data.writeString16(name);//"media.audio_flinger"

//与addService方法类似,只是参数变成了CHECK_SERVICE_TRANSACTION

remote()->transact(CHECK_SERVICE_TRANSACTION, data,&reply);

return reply.readStrongBinder();//读取返回数据

}


remote()方法返回的是BpBinder(0),调用其transact方法会进入IPCThreadState的transact方法参与Binder通信,最终在IPCThreadState的talkWithDriver方法中,通过ioctl BINDER_WRITE_READ指令将BC_TRANSACION发送给Binder驱动程序。Binder驱动程序收到客户端的BC_TRANSACION指令,会检索到servicemanager的Binder node,然后向servicemanager发送BR_TRANSACTION,并携带SVC_MGR_CHECK_SERVICE指令。servicemanager接收到Binder驱动发送过来的BR_TRANSACTION后,会执行binder_parse方法switch代码块的BR_TRANSACTION分支,然后进入svcmgr_handler方法switch代码块的SVC_MGR_CHECK_SERVICE分支,在该分支中会调用do_find_service方法中根据Client传递的服务名从svclist中检索该服务的信息。这部分内容在addService已经分析过,这里直接从svcmgr_handler开始分析,代码如下:


int svcmgr_handler(struct binder_statebs, struct binder_txntxn,

struct binder_iomsg, struct binder_ioreply)

……

switch(txn->code){

case SVC_MGR_GET_SERVICE:

case SVC_MGR_CHECK_SERVICE:

s=bio_get_string16(msg,&len);

//从svclist中查找指定服务

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

if(!ptr)

break;

bio_put_ref(reply, ptr);//将服务注册信息存入reply中

return 0;


svcmgr_handler找到指定的服务注册信息后,将其存入reply中,然后返回到binder_parse函数中,在该函数中继续调用binder_send_reply将reply返回给Binder驱动程序。

binder_send_reply其实是通过Binder ioctl指令BINDER_WRITE_READ向Binder驱动程序发送了BC_REPLY指令和返回数据。Binder驱动程序收到该指令后,会根据返回数据中存储的服务注册信息找到具体的服务对象,在本例是AudioFlinger。驱动程序找到所请求的服务后,会将该服务的引用handler传递回Client, Binder驱动程序会向Client发送一个BR_REPLY指令,这样Client便在waitForResponse的switch代码块的BR_REPLY分支接收返回数据reply。

服务引用handler返回后,即checkService的remote()->transact返回,接下来调用reply上的readStrongBinder方法,该方法会以返回的handler引用为参数创建BpBinder对象。

BpBinder对象创建完成后,会以该对象为参数调用interface_cast<IAudioFlinger>(binder)。已知interface_cast是一个宏定义,其等价于以下语句:


IAudioFlinger:asInterface(new BpBinder)


而asInterface可以由IMPLEMENT_META_INTERFACE宏实现,其代码如下:


android:sp<IAudioFlinger>IAudioFlinger:asInterface(

const android:sp<android:IBinder>&obj)

{

android:sp<IAudioFlinger>intr;

//obj为BpBinder(handler)

if(obj!=NULL){

intr=static_cast<IAudioFlinger*>(

obj->queryLocalInterface(//该方法返回NULL

IAudioFlinger:descriptor).get());

if(intr==NULL){

//将BpBinder封装成BpAudioFlinger

intr=new BpAudioFlinger(obj);

}

}

return intr;

}


由以上分析可知,getService最终返回给Client的是所请求服务的Proxy对象,在本例中是BpAudioFlinger,这个代理对象持有Server中Service的handler信息。通过该信息,Binder驱动程序可以找到对应的Service,进而可以调用Service上的指定方法。