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通信机制的架构后,整个过程还是比较好理解的。
- Android7.0 Binder通信(3) 客户进程查询和使用服务进程
- Android7.0 Binder通信(2) 服务进程的注册
- Android进程通信Binder(2)-Android系统服务与Binder
- Android 进程间通信binder使用心得
- Binder进程通信介绍
- Binder 进程通信
- 进程间通信IPC机制和Binder
- Android Binder服务进程
- 进程间通信 binder机制-添加自己的系统服务
- [Binder.0] Android进程间通信(IPC)机制Binder简要介绍和学习计划
- Linux FIFO 进程间通信 (服务进程-客户进程模型)
- Binder进程间通信机制的Client进程和Server进程的通信过程
- Android框架之Camera(3)透过Camera服务看Binder进程间通信
- Android进程通信Binder(1)-Binder进程通信的思想
- 进程间通信 binder机制
- android Binder 进程间通信
- Android 进程通信-- Binder机制
- Binder进程间通信系统
- 建议135: 考虑使用肯定性的短语命名布尔属性
- iOS基础1
- 风电机组状态监测系统(CMS)
- 管理状态栏和导航栏
- 移动端上传照片 预览(解决iOS等设备照片旋转90度的bug)
- Android7.0 Binder通信(3) 客户进程查询和使用服务进程
- 建议136:优先使用后缀表示已有类型的新版本
- Xamarin.iOS提供没有匹配的配置文件
- 输入一个整形数组,数组里有正数也有负数。数组中连续的一个或多个整数组成一个子数组,每个 子数组都有一个和。求所有子数组的和的最大值。要求时间复杂度为O(n)。
- FZU Problem 2214 Knapsack problem(01背包,超大背包)——第六届福建省大学生程序设计竞赛-重现赛
- 【Dev Club分享】基于RxJava的一种MVP实现
- C++内存管理
- CSS学习笔记之class选择器
- 判断手机屏幕旋转方向