源码基于:Android R
0. 前言
在之前的几篇博文中,对Android binder 的通信原理进行的深入的剖析,这些博文包括:binder 简介、servicemanager启动、service注册、service获取、Java 端的service 注册和获取。本文在之前的基础上,以实例的形式进一步的分析 native 下的 C-S 通信。
1. server 端
main.cpp
int main(int argc, char** argv)
{
sp <IBinder> binder = defaultServiceManager()->checkService(String16(IPC_SERVICE_NAME));
if (binder != 0) {
printf("%s has been registered.\n", IPC_SERVICE_NAME);
return 0;
}
if (IPCService::instantiate() < 0) {
printf("regitster %s failed.\n", IPC_SERVICE_NAME);
return -1;
}
printf("register %s successfully.\n", IPC_SERVICE_NAME);
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
return 0;
}
在server 端运行的 main() 函数中,需要执行:
- 通过 defaultServiceManager() 获取到 sp<IServiceManager>,即 ServiceManager 的client 端代理;
- 通过 sp<IServiceManager> 调用函数 checkService(),并传入 service name,确定该 service 是否已经启动中,如果启动中,可以通过 service name 在 ServiceManager 中的 mNameToService map 中查找到,详细可以查看《Android Binder通信原理(三):service获取》第 2.3 节 和 《Android Binder通信原理(三):service注册》第 4.1.1 节;
- 如果该 server 已经启动,会根据 service name 返回该 server 的代理,如果该 server 没有启动,则返回的代理为 NULL;
- 当通过 checkService() 发现该 server 没有启动时,需要调用 addService() 接口进行注册。该实例中用 IPCService::instantiate() 接口进行封装,后面会补充代码;
- 另外,这里最重要的两个函数是需要执行的。
- ProcessState::self()->startThreadPool(); 函数其实是卵生 IPCThreadState 的初始化函数,调用该函数后binder 之后的卵生工作就可以正常进行。详细可以查看《servicemanager 启动》一文第 4.5 节;
- IPCThreadState::self()->joinThreadPool(); 启动一个循环,等待与binder 驱动的交互;
service.cpp
int IPCService::instantiate()
{
ALOGD("register ipc service .");
android::status_t ret = defaultServiceManager()->addService(String16(IPC_SERVICE_NAME), new IPCService());
if (ret != android::OK) {
ALOGE("Couldn't register %s!, ret = %d", IPC_SERVICE_NAME, ret);
return ret;
}
return 0;
}
这个就是上面说的封装函数,当server 没有启动时,通过addService() 接口将该 service 添加到 servicemanager 中。
2. Client 端
const sp<IIPCService> IIPCDeathNotifier::getIPCService()
{
JMutex::Autolock _l(mServiceLock);
if (mIPCService.get() == 0 || !IInterface::asBinder(mIPCService)->isBinderAlive()) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
binder = sm->getService(String16(IPC_SERVICE_NAME));
if (binder != 0) {
break;
}
ALOGE("IPC service is not published, waiting...");
usleep(500000); // 0.5 s
} while (true);
if (mDeathNotifier == NULL) {
mDeathNotifier = new DeathNotifier();
}
binder->linkToDeath(mDeathNotifier);
mIPCService = interface_cast<IIPCService>(binder);
ALOGD("IPC SERVICE %p", mIPCService.get());
}
if (mIPCService == NULL) {
ALOGE("wrong... can't get ipc service.");
}
return mIPCService;
}
- 在 Client 有一个成员变量 mIPCService 来存储 server 的代理,最开始check 一下该值是否为 null,并且确认该 server 是否处于 alive 状态;
- 接着,通过 defaultServiceManager() 接口获取 servicemanager 的代理,接着通过该代理查询 servcie name 对应的server 的代理 binder,如果获取失败,则每隔0.5 秒retry 一次;
- 如果server 的代理获取成功,则通过 linkToDeath() 注册个监听,用以监听 server 是否die 掉;
- 最后,将代理 binder 通过 interface_case<> 强制转换给想要的类型的代理,并进行存储;
3. BpBinder 和 BBinder 的创建
当 client 端通过 getService() 获取到 server 端的代理后,就可以进行binder 通信。这就涉及到了 BpBinder 和 BBinder 的创建。
加入我们创建 IPCService 接口的头文件,命名为 IIPCService.h
#ifndef IPC_BINDER_IIPCSERVICE_H_
#define IPC_BINDER_IIPCSERVICE_H_
#include <binder/IInterface.h>
#include <binder/Parcel.h>
namespace shift {
enum {
FOCUS_STOP = 1,
};
class IIPCService : public IInterface
{
public:
DECLARE_META_INTERFACE (IPCService);
virtual int focusStop() = 0;
}; //end class IIPCService
class BnIPCService : public BnInterface<IIPCService>
{
public:
virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
}; //end class BnIPCService
} //end namespace
#endif
头文件中创建了普通的 IIPCService 类,该类继承自 IInterface,定义了DECLARE_META_INTERFACE(),并指定 interface name 为 IPCService。该类是BpBinder 和BBinder 的依赖父类。
头文件中还定义了 BnIPCService 类,这就是 BBinder。
下面来看下 BpBinder 和 BBinder 的实现,文件名为 IIPCService.cpp
#include "IIPCService.h"
#include <binder/IInterface.h>
#include <binder/Parcel.h>
using namespace shift;
class BpIPCService : public BpInterface<IIPCService>
{
public:
BpIPCService(const sp<IBinder> &impl) : BpInterface<IIPCService>(impl) {}
virtual int focusStop()
{
Parcel data, reply;
data.writeInterfaceToken(IIPCService::getInterfaceDescriptor());
int ret = remote()->transact(FOCUS_STOP, data, &reply);
if (ret != NO_ERROR) {
return -1;
}
return reply.readInt32();
}
}; //end class BpIPCService
IMPLEMENT_META_INTERFACE(IPCService, "my.IPCService");
//----------------------------------------------------------------------------------------
status_t BnIPCService::onTransact(
uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags)
{
switch (code) {
case FOCUS_STOP: {
CHECK_INTERFACE(IIPCService, data, reply);
int ret = focusStop();
reply->writeInt32(ret);
return NO_ERROR;
}
return NO_ERROR;
}
至此,native 下 C-S 的实例已经基本说明完毕,结合实际操作可以更好的理解 binder 的通信。