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

来源:互联网 发布:马士兵java教程下载 编辑:程序博客网 时间:2024/06/05 20:28

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

0 0
原创粉丝点击