Android7.0 Binder通信(3) 客户进程查询和使用服务进程

前面的博客分析了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通信机制的架构后,整个过程还是比较好理解的。

你可能感兴趣的:(android)