Android native进程间通讯的实例 (原创)
前一段时间有一个需求,需要增加一个Native层的服务,做完之后,想总结下,加深些印象....
两个进程间通信,一般首先想到的就是Socket,这种哪种语言里都通用,不但可以跨语言,还可以跨平台。Android 里有自带的跨进程机制Binder通信,但其实实质上它还是一个Socket + 共享内存完成。进程间通讯也就是说两个进各程之间进行通讯,有一个服务端,有一个客户端。但服务端和客户端需要通过接口来调用,服务端适配接口方法并实现的具体功能,客户端需要调用这个接口,让服务端去做客户想要做的事情。那我们来看看接口的定义:
class IDemoService: public IInterface { public: DECLARE_META_INTERFACE(DemoService); virtual int DemoFunc() = 0; }
那里面有一个宏定义 DECLARE_META_INTERFACE , 这个是Binder库里的一个宏定义,省下了我们写其接口的过程, 那我们来看库里是怎么定义的:
#define DECLARE_META_INTERFACE(INTERFACE) \ static const android::String16 descriptor; \ static android::sp<I##INTERFACE> asInterface( \ const android::sp<android::IBinder>& obj); \ virtual const android::String16& getInterfaceDescriptor() const; \ I##INTERFACE(); \ virtual ~I##INTERFACE(); \
相当于定义了一个转化接口的函数和获取Descriptor(),这里面是与等会要出场的另一个宏定义对应的IMPLEMENT_META_INTERFACE。
那有了接口,我们看下服务端需在做什么工作,首先要实现BnDemoService里的onTransact方法:
status_t BnDemoService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){ switch(code){ case DEMO_FUNC: { CHECK_INTERFACE(IDemoService, data, reply); int result = DemoFunc(); reply->writeInt32(result); return NO_ERROR; }break; default: return BBinder::onTransact(code, data, reply, flags); } }
这里就要调用对应处理的函数了,DemoFunc(), 那我们看下服务端是怎么操作的。
class DemoService : public BnDemoService { public : DemoService(); int DemoFunc(){ ALOGD("this is DemoService DemoFunc"); } }
其实DemoService 是继承BnDemoService, 客户端通过Binder会调用服务端的onTransact(...)函数,那服务端看完了,那我们看服务是如何注册运行的。
int main(){
sp<IServiceManager> sm = defaultServiceManager();
sp<IDemoService> mDemoService = new DemoService();
status_t ret = sm->addService(Strint16("demo.DemoService"), mDemoService);
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool(true); }
可以看到通过IServiceManager的接口 把DemoService 对象注册成一个服务,通过调用startThreadPool() 在Binder线程池中启动一个线程,通过JoinThreadPool(true), 开启Binder的IPC通讯流程。
如想细节了解,可以参考http://gityuan.com/2016/10/29/binder-thread-pool/
那下面我们看看客户端是如何写的。
class BpDemoService : public BpInterface<IDemoService>{ public : BpDemoService(const sp<IBinder> impl) : BpInterface<IDemoService>(impl){ } int DemoFunc(){ Parcel data, reply; data.writeInterfaceToken(IDemoService::getInterfaceDescriptor); remote()->transact(DEMO_FUNC, data, &reply);
return reply.readInt32(); } };
IMPLEMENT_META_INTERFACE(DemoService, "android.demo.IDemoService");
BpInterace<xxx> 是BpBinder的接口,BpBinder 通过与/dev/Binder 驱动进行通讯。
刚才说的IMPLEMENT_META_INTERFACE的宏出场了,我们还是来看看实际指的啥:
#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME) \ const android::String16 I##INTERFACE::descriptor(NAME); \ const android::String16& \ I##INTERFACE::getInterfaceDescriptor() const { \ return I##INTERFACE::descriptor; \ } \ android::sp<I##INTERFACE> I##INTERFACE::asInterface( \ const android::sp<android::IBinder>& obj) \ { \ android::sp<I##INTERFACE> intr; \ if (obj != NULL) { \ intr = static_cast<I##INTERFACE*>( \ obj->queryLocalInterface( \ I##INTERFACE::descriptor).get()); \ if (intr == NULL) { \ intr = new Bp##INTERFACE(obj); \ } \ } \ return intr; \ } \ I##INTERFACE::I##INTERFACE() { } \ I##INTERFACE::~I##INTERFACE() { } \
其实相当于定义了实现了DECLARE_META_INTERFACE 相对应的函数 asInterface(...)。
客户端的功能函数写完了,那看怎么调用呢?
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> iBinder = sm->getService(String16("demo.DemoService"));
if(iBinder == NULL)
ALOGE("Client can't find Service");
sp<IDemoService> mIDemoService = interface_case<IDemoService>(iBinder);
mIDemoService->DemoFunc();
与Serice端一样,通过IServiceManager接口,通过getService(ServiceName)获取IBinder, 最后通过interface_case 转化成IDemoService, 最后调用DemoFunc() 就可以调用 DemoService里的DemoFunc()了。