上一篇,了解了一下Binder通信机制的基本框架。此篇将用一个示例来说明一个。非常感谢一位网上朋友的源码分享,博主还有更多精彩Android框架分析文章。
添加Test模块服务,方法姑且定义一个为test。
(1)程序构成
编译binder程序需要链接binder动态链接库,应用开发环境下使用ndk编程是不能链接binder动态链接库的,故此需要在源码开发环境下。本实例在vendor目录下建立了子目录shuame,然后把工程目录放在该目录下。
程序由2个部分组成,一个binder service程序,一个测试binder service的client程序,对应的Android.mk如下所示:
LOCAL_PATH := $(call my-dir) #生成binder service的服务端 include $(CLEAR_VARS) LOCAL_SHARED_LIBRARIES := \ libcutils \ libutils \ libbinder LOCAL_MODULE := TestServer LOCAL_SRC_FILES := \ ITestService.cpp \ TestServer.cpp LOCAL_MODULE_TAGS := optional include $(BUILD_EXECUTABLE) #生成binder service的测试client端 include $(CLEAR_VARS) LOCAL_SHARED_LIBRARIES := \ libcutils \ libutils \ libbinder LOCAL_MODULE := TestClient LOCAL_SRC_FILES := \ ITestService.cpp \ TestClient.cpp LOCAL_MODULE_TAGS := optional include $(BUILD_EXECUTABLE)
Test.h :包含需要用到的头文件,声明接口,定义操作枚举,声明binder引用类
ITestService.cpp: 接口类方法的实现
TestServer.cpp: 声明并实现binder实体类 ,启动binder服务,并在service manager里注册
TestClient.cpp: 声明并实现binder 引用类, 测试binder服务的client
1. 声明Service的接口ITestService(test.h)
// Binder Service 接口test声明 class ITestService : public IInterface { public: DECLARE_META_INTERFACE(TestService); // declare macro virtual void test()=0; }; // 客户端服务端通讯使用 enum { TEST = IBinder::FIRST_CALL_TRANSACTION, };2.完成BpTestService的声明,test实现
声明:
// BpXXX继承IXXX,完成test接口的实现,通过remote()->transact()远程调用到BnXXX::onTransaction(){ cast TEST: xxxx;} class BpTestService: public BpInterface<ITestService> { public: BpTestService(const sp<IBinder>& impl); virtual void test(); };实现:
IMPLEMENT_META_INTERFACE(TestService, "android.TestServer.ITestService"); void BpTestService::test() { printf("in the get Test\n"); Parcel data, reply; data.writeInterfaceToken(ITestService::getInterfaceDescriptor()); remote()->transact(TEST, data, &reply); printf("send Print %d\n", reply.readInt32()); }
3. 完成BnTestService接口类的声明,实现
声明:
class BnTestService: public BnInterface<ITestService> { public: virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); virtual void test() { printf("Now get test\n"); } };
实现onTransact()方法:
status_t BnTestService::onTransact(uint_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch (code) { case TEST: { printf("got the client msg\n"); CHECK_INTERFACE(ITest, data, reply); test(); reply->writeInt32(100); return NO_ERROR; } break; default: break; } return NO_ERROR; }4. 实现客户端Client
int main() { /*获取service manager引用*/ sp<IServiceManager> sm = defaultServiceManager(); /*获取test service的binder接口对象*/ sp<IBinder> binder = sm->getService(String16("service.testservice")); /*转为sp<ITestService>*/ sp<ITestService> cs = interface_cast<ITestService>(binder); /*通过binder引用调用test方法*/ cs->test(); return 0; }5.实现Server端
int main() { ProcessState::self(); //初始化单例 /*获取service manager的binder引用*/ sp<IServiceManager> sm = defaultServiceManager(); /*添加服务 注意字符串必须用String16类型*/ sm->addService(String16("service.testservice"), new BnTestService()); ProcessState::self()->startThreadPool(); //启动线程池 IPCThreadState::self()->joinThreadPool();//等待线程结束 return 0; }6.编译生成TestServer,TestClient,分别push到Andrlid设备中,修改权限,运行并测试
架构和Android上的多媒体播放框架有点不一样,完成播放接口能力放在了Client的类中,而整个多媒体服务MediaPlayerService则负责创建并管理这些Client客户端。
总之,XXXXX是继承BnXXXX,BnXXXX继承IXXXX,BnXXXX中继承IXXXX中的虚函数必须被实现后才能被实例化,通常是在XXXX中被实现,主要XXXX就可以被实例化。