前面的博客分析了Binder通信机制中,ServiceManager和服务进程的主要流程。
现在我们看看客户进程是如何查询到服务进程的,以及查询到服务进程后如何使用。
其实在了解了整个Binder通信机制的架构后,剩下的内容就比较好理解了。
我们以MediaServer进程中的MediaPlayerService为例,看看其客户端进程如何通过ServiceManager进行查询。
获取MediaPlayerService的接口定义于IMediaDeathNotifier.cpp中:
const sp<IMediaPlayerService>
IMediaDeathNotifier::getMediaPlayerService()
{
.........
if (sMediaPlayerService == 0) {
//前面博客分析过,通过defaultServiceManager将获取到BpServiceManager
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
//利用BpServiceManager的getService函数,获取与MediaPlayerService通信的BpBinder
binder = sm->getService(String16("media.player"));
if (binder != 0) {
break;
}
ALOGW("Media player service not published, waiting...");
usleep(500000); // 0.5 s
} while (true);
...........
//之前的博客已经分析过,这里将利用IInterface的继承体系,用BpBinder构建出BpMediaPlayerService
sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
}
.............
return sMediaPlayerService;
}
1 查询服务
从上面的代码可以看出,查询服务是通过BpServiceManager的getService函数来完成的,传入参数为待获取服务的名称:
virtual sp<IBinder> getService(const String16& name) const
{
unsigned n;
//每次调用都重试5次
for (n = 0; n < 5; n++){
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(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
//调用BpBinder的transact函数
remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
//利用返回的信息,构建BpBinder
return reply.readStrongBinder();
}
之后BpBinder将调用IPCThreadState函数的transact函数,利用ioctl将请求写入到Binder设备中。这一部分内容之前的博客已经分析,此处不再赘述。
当ServiceManager收到数据后,利用svcmgr_handler进行处理。
int svcmgr_handler(....) {
........
switch(txn->code) {
case SVC_MGR_GET_SERVICE:
case SVC_MGR_CHECK_SERVICE:
//取出待查找服务的名称
s = bio_get_string16(msg, &len);
.......
//得到对应服务的handle
handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);
......
//将handle写入到reply中
bio_put_ref(reply, handle);
return 0;
.......
}
.......
}
跟进一下do_find_service:
uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid)
{
struct svcinfo *si = find_svc(s, len);
.........
return si->handle;
}
struct svcinfo *find_svc(const uint16_t *s16, size_t len)
{
struct svcinfo *si;
for (si = svclist; si; si = si->next) {
if ((len == si->len) &&
!memcmp(s16, si->name, len * sizeof(uint16_t))) {
return si;
}
}
return NULL;
}
从上面的代码可以看出,获取服务和注册服务的过程是完全对应的。
回忆一下,MediaPlayerService注册服务时,通过Binder机制将对应的信息发送给ServiceManager;ServiceManager利用收到的信息,构建对应的服务对象加入到svclist中。
现在客户端进程想要获取服务,同样利用Binder机制将请求发送给ServiceManager;ServiceManager收到请求后,从svclist中找到对应服务对象,并返回handle。
2 使用服务
获取BpBinder构建出BpMediaPlayerService后,就能够使用任何IMediaPlayerService定义的业务接口了。
我们以addBatteryData接口为例,看看客户发送的请求是如何被服务进程处理的。
virtual void addBatteryData(uint32_t params) {
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
data.writeInt32(params);
remote()->transact(ADD_BATTERY_DATA, data, &reply);
}
从上面的代码可以看出,调用BpMediaPlayerService中的接口,实际上也是通过BpBinder将请求发往服务端进程。
那么服务端是如何处理这些请求的呢?
已知MediaPlayerService运行在MediaServer进程中,MediaServer进程中有两个IPCThreadState在处理Binder设备的发来的数据。
因此,服务进程处理客户端请求的流程,肯定也是从IPCThreadState接收数据开始的。
在前面的博客中提到,在MediaServer进程main函数的最后,调用了IPCThreadState的joinThreadPool方法:
void IPCThreadState::joinThreadPool(bool isMain)
{
........
do {
.......
//无限循环调用getAndExecuteCommand处理数据
result = getAndExecuteCommand();
.......
}while(result != -ECONNREFUSED && result != -EBADF);
........
}
status_t IPCThreadState::getAndExecuteCommand()
{
.......
//ioctl收发数据
result = talkWithDriver();
if (result >= NO_ERROR) {
......
//这里就是服务进程,处理客户端请求的地方
result = executeCommand(cmd);
......
}
.......
}
我们跟进executeCommand:
status_t IPCThreadState::executeCommand(int32_t cmd)
{
switch ((uint32_t)cmd) {
........
case BR_TRANSACTION:
{
binder_transaction_data tr;
result = mIn.read(&tr, sizeof(tr));
............
//创建BpBinder时,指定了服务的handle
//BpBinder传输时,handle被写入到tr.target中
if (tr.target.ptr) {
.......
//按照前一篇博客中提到的Binder通信继承体系,我们知道服务端的BnMediaPlayerService将继承BBinder
//因此这里应该是调用BnMediaPlayerService的transact函数
error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,
&reply, tr.flags);
.......
} else {
.......
}
...........
}
break;
........
}
........
}
BnMediaPlayerService的transact函数,实际上由其父类BBinder实现,定义与Binder.cpp中:
status_t BBinder::transact(....) {
........
switch (code) {
case PING_TRANSACTION:
reply->writeInt32(pingBinder());
break;
default:
//调用子类的onTransact函数,此时从请求从通信层,真正进入到业务层
err = onTransact(code, data, reply, flags);
break;
}
........
}
跟进BnMediaPlayerService中的onTransact函数:
status_t BnMediaPlayerService::onTransact(.....) {
switch (code) {
case CREATE:
.......
case ADD_BATTERY_DATA: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
uint32_t params = data.readInt32();
//根据前面博客中Binder的继承体系,我们知道实际的MediaPlayerService继承BnMediaPlayerService
//故此处将调用MediaPlayerService的addBatteryData
addBatteryData(params);
return NO_ERROR;
} break;
...........
}
}
以上就是客户端进程查询和使用服务进程的主要流程,当了解整个Binder通信机制的架构后,整个过程还是比较好理解的。