532
查看binder @ 用cpp实现一个service的源代码
binder @ 用cpp实现一个service
0
←
binder @ 用cpp实现一个service
跳转至:
导航
、
搜索
因为以下原因,你没有权限编辑本页:
你被禁止执行你刚才请求的操作。
您可以查看并复制此页面的源代码:
== 一、前言 == binder,是android中随处可见的IPC机制。 关于其设计思想及设计原理可以认真研读一下这篇文章,写得很好:http://disanji.net/2011/02/28/android-bnder-design/ 不过在这里,我们不会去深研其实现原理,而是以一个应用开发者的角度,看一下如何使用它。 IPC,即进程间通信,作用是使一个进程能够访问另一个并行进程的数据。而binder,从直观的角度上看来,更为简单,就是在一个进程中能够调用另一个进程的函数,就好像调用本地函数一样。 == 二、概述 == 为了实现上面所说的“从一个进程‘调用’另一个进程的函数”,binder首先要求客户端和服务端都要定义一些相同的接口,然后给服务编号,在客户端要访问服务端某一服务时就通过这个编号来指定,同时在传递这个编号时也带有数据(int32、string、pointer)作为参数,数据的交换就通过这些参数实现。 上面这些都很好理解,不过这还是没有说明核心——IPC的部分在哪?其实这部分和linux已有的IPC机制类似,就是将数据从用户空间通过linux driver写虚拟文件(/dev/binder)的方式,在内核空间实现。不过binder使用mmap将空间映射的方式作了优化,避免了内存分配、减少数据拷贝次数,具体可以查看上第一章推荐的那篇文章,里面有详细的描述。 而对于“binder首先要求客户端和服务端都要定义一些相同的接口”的实现,相信有过面向对象基础的朋友们已经猜到了... ——没错,正是采用继承共同的父类的方式实现! 各类继承关系图如下: [[Image:binder_class.emf]] 这里所实现的service是模拟一个火炮,所提供的服务有“开火”、“检查剩余炮弹”和“装弹”。 == 三、用C++实现一个service== === 1、实现共同父类IMyBinder === 这个类除了要定义上面所说的函数外,还要定义一些binder内部使用的函数和变量。 <pre class="prettyprint"> //IMyBinder.h #ifndef I_MY_BINDER_H #define I_MY_BINDER_H #include <binder/IInterface.h> #include <binder/IPermissionController.h> #include <utils/Vector.h> #include <utils/String16.h> namespace android { class IMyBinder : public IInterface { public: DECLARE_META_INTERFACE(MyBinder); virtual bool loadBomb(const int num) = 0; virtual int checkBomb(void) = 0; virtual bool fire(void) = 0; enum { LOAD_BOMB_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, CHECK_BOMB_TRANSACTION, FIRE_TRANSACTION }; }; } #endif /* I_MY_BINDER_H */ </pre> <pre class="prettyprint"> //IMyBinder.cpp #include <IMyBinder.h> #include <BpMyBinder.h> namespace android { IMPLEMENT_META_INTERFACE(MyBinder, "IMyBinder"); } </pre> === 2、实现BnMyBinder === Bn中的首个字母B是代表binder,那第二字母代表什么意思呢?答案就是native,即表示这个类是在真正实现对应功能的进程中创建的。相对应的,下面将会说到的BpMyBinder中的p则是proxy的首字母,为代理的意思。 在BnMyBinder中必须要实现的函数是 onTransact,因为所有的IPC服务调用都是通过这个函数、根据服务编号完成分发实现的。 <pre class="prettyprint"> //BnMyBinder.h #ifndef BN_MY_BINDER_H #define BN_MY_BINDER_H #include <IMyBinder.h> namespace android { class BnMyBinder : public BnInterface<IMyBinder> { public: virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); }; } #endif /* BN_MY_BINDER */ </pre> <pre class="prettyprint"> //BnMyBinder.cpp #define LOG_TAG "BnMyBinder" /*#include <binder/IPCThreadState.h> #include <utils/Log.h> #include <private/android_filesystem_config.h> #include <sys/time.h> #include <sys/resource.h> #include <signal.h> #include <stdio.h> #include <unistd.h>*/ #include <BnMyBinder.h> #include <utils/Debug.h> #include <utils/Log.h> #include <binder/Parcel.h> namespace android { status_t BnMyBinder::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { switch(code) { case LOAD_BOMB_TRANSACTION: { CHECK_INTERFACE(IMyBinder, data, reply); bool err = const_cast<BnMyBinder*>(this)->loadBomb(data.readInt32()); reply->writeInt32(err); } return NO_ERROR; break; case CHECK_BOMB_TRANSACTION: { CHECK_INTERFACE(IMyBinder, data, reply); int restBomb = const_cast<BnMyBinder*>(this)->checkBomb(); reply->writeInt32(restBomb); } return NO_ERROR; break; case FIRE_TRANSACTION: { CHECK_INTERFACE(IMyBinder, data, reply); bool err = const_cast<BnMyBinder*>(this)->fire(); reply->writeInt32(err); } return NO_ERROR; break; default: return BBinder::onTransact(code, data, reply, flags); } } } </pre> === 3、实现BpMyBinder === 如上面所说,BpMyBinder是“代理”,那它是什么代表的是什么呢? ——其实所代理就是IPC服务的提供者,使得在android的所有进程中均能通过这些代理调用其他进程的服务/函数,就像调用本地的服务/函数一样。 为了提供这些服务,BpMyBinder必然要定义使用这些服务的函数(或者说方法),另外,由于BpMyBinder也是继承自IMyBinder,所以就能保证这些函数名和BnMyBinder(同样继承自IMyBinder)中保持一致,方便设计者的使用和查看。 <pre class="prettyprint"> //BpMyBinder.h #ifndef BP_MY_BINDER_H #define BP_MY_BINDER_H #include <IMyBinder.h> namespace android { class BpMyBinder : public BpInterface<IMyBinder> { public: BpMyBinder(const sp<IBinder>& impl) //indispensable : BpInterface<IMyBinder>(impl) { } virtual bool loadBomb(const int num); virtual int checkBomb(void); virtual bool fire(void); }; } #endif /* BP_MY_BINDER_H */ </pre> <pre class="prettyprint"> //BpMyBinder.cpp #include <binder/Parcel.h> #include <BpMyBinder.h> namespace android { bool BpMyBinder::loadBomb(const int num) { Parcel data, reply; data.writeInterfaceToken(IMyBinder::getInterfaceDescriptor()); data.writeInt32(num); remote()->transact(LOAD_BOMB_TRANSACTION, data, &reply); return reply.readInt32(); } int BpMyBinder::checkBomb(void) { Parcel data, reply; data.writeInterfaceToken(IMyBinder::getInterfaceDescriptor()); remote()->transact(CHECK_BOMB_TRANSACTION, data, &reply); return reply.readInt32(); } bool BpMyBinder::fire(void) { Parcel data, reply; data.writeInterfaceToken(IMyBinder::getInterfaceDescriptor()); remote()->transact(FIRE_TRANSACTION, data, &reply); return reply.readInt32(); } } </pre> === 4、实现MyBinder === MyBinder继承自BnMyBinder,这里主要是在native实现IMyBinder中所定义的纯虚函数,从而使得 BnMyBinder.onTransact的功能分发得以实现。 <pre class="prettyprint"> //MyBinder.h #include <BnMyBinder.h> namespace android { class MyBinder : public BnMyBinder { public: virtual bool loadBomb(const int num); virtual int checkBomb(void); virtual bool fire(void); }; } </pre> <pre class="prettyprint"> //MyBinder.cpp #include <sys/types.h> #include <unistd.h> #include <grp.h> #include <binder/IPCThreadState.h> #include <binder/ProcessState.h> #include <binder/IServiceManager.h> #include <utils/Log.h> #include <utils/RefBase.h> #include <MyBinder.h> using namespace android; //namespace android { static int restBomb = 0; bool MyBinder::loadBomb(const int num) { restBomb+=num; return true; } int MyBinder::checkBomb(void) { return restBomb; } bool MyBinder::fire(void) { if(0 < restBomb) { restBomb--; return true; } else { return false; } } //} </pre> === 5、Makefile === 由于上面这些文件要同时被Server和Client进程引用,同时也不能直接运行,所以应该编译成库,方便其他可执行程序的引用。 <pre class="prettyprint"> //Android.mk LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= IMyBinder.cpp BnMyBinder.cpp BpMyBinder.cpp MyBinder.cpp LOCAL_MODULE_TAGS := optional LOCAL_MODULE:= libMyBinder LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES) LOCAL_SHARED_LIBRARIES := libcutils libutils libbinder #LOCAL_SHARED_LIBRARIES := libutils include $(BUILD_SHARED_LIBRARY) </pre> == 四、验证== 上面的工作是完成了MyBinder这个service的运行模型,但到目前为此是不能运行的,原因是这些仅仅是一些“类”,还未实例化!因此,为了对其进行验证,我们必须创建其实例。 由于是IPC服务,自然我们要创建服务器和客户端,并使其运行在不同的进程中。 === 1、创建server === 这里主要是为MyBinder这个service创建一个实例,并加入线程池中(实际是让其线程进行监听): <pre class="prettyprint"> //MyServer.cpp #include <sys/types.h> #include <unistd.h> #include <grp.h> #include <binder/IPCThreadState.h> #include <binder/ProcessState.h> #include <binder/IServiceManager.h> #include <utils/Log.h> #include <utils/RefBase.h> #include <MyBinder.h> using namespace android; int main(int argc, char** argv) { sp<ProcessState> proc(ProcessState::self()); sp<IServiceManager> sm = defaultServiceManager(); sm->addService(String16("service.MyBinder"), new MyBinder()); //MyBinder::instantiate(); ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); return 0; } </pre> mk文件,让其编译成可执行文件;另外,由于要新建MyBinder,所以要包含MyBinder中的头文件和MyBinder库文件: <pre class="prettyprint"> #Android.mk LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_C_INCLUDES:= $(LOCAL_PATH)/../MyBinder/ LOCAL_SRC_FILES:= MyServer.cpp LOCAL_MODULE_TAGS := optional LOCAL_MODULE:= MyServer LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES) LOCAL_SHARED_LIBRARIES := libcutils libutils libbinder libMyBinder #LOCAL_SHARED_LIBRARIES := libutils include $(BUILD_EXECUTABLE) </pre> === 2、创建client === 在client进程中,根据用户输入的口令,获取"MyBinder"服务,然跨进程“调用”函数,完成“装弹”、“开炮”等任务。 <pre class="prettyprint"> //MyClient.cpp #define LOG_TAG "MyClient" #include <sys/types.h> #include <unistd.h> #include <grp.h> #include <binder/IPCThreadState.h> #include <binder/ProcessState.h> #include <binder/IServiceManager.h> #include <utils/Log.h> #include <utils/RefBase.h> #include <../MyBinder/IMyBinder.h> #define ALOGD printf #define ALOGW printf #define ALOGE printf using namespace android; static void help() { printf("USAGE:\n\tMyClient fire\n\tMyClient loadBomb <bomb number>\n\tMyClient checkBomb\n"); } int main(int argc, char** argv) { //ALOGD("argv[0]=%s, argv[1] = %s, argv[2] = %s\n", *argv, *(argv+1), *(argv+2)); if(argc < 2) { help(); exit(0); } char *cmd = *(argv+1); char *arg = *(argv+2); sp<IBinder> binder = defaultServiceManager()->getService(String16("service.MyBinder")); sp<IMyBinder> service = interface_cast<IMyBinder>(binder); if (service.get() == NULL) { ALOGW("Cannot connect to the service.MyBinder"); return -1; } //ALOGD("get service.MyBinder sucess.\n"); if(!strcmp(cmd, "fire")) { if(true == service->fire()) { ALOGD("Bang!\n"); } else { ALOGW("no bomb..\n"); } } else if(!strcmp(cmd, "loadBomb")) { if(NULL != arg) { if(true == service->loadBomb((char)*arg-48)) { ALOGD("loadBomb sucess.\n"); } else { ALOGE("loadBomb error.\n"); } } else { ALOGE("bomb number should be given.\n"); } } else if(!strcmp(cmd, "checkBomb")) { ALOGD("rest bomb:%d\n", service->checkBomb()); } else { help(); } return 0; } </pre> mk文件: <pre class="prettyprint"> #Android.mk LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_C_INCLUDES:= $(LOCAL_PATH)/../MyBinder/ LOCAL_SRC_FILES:= MyClient.cpp LOCAL_MODULE_TAGS := optional LOCAL_MODULE:= MyClient LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES) LOCAL_SHARED_LIBRARIES := libcutils libutils libbinder libMyBinder #LOCAL_SHARED_LIBRARIES := libutils include $(BUILD_EXECUTABLE) </pre> === 3、验证结果 === 将上面的文件编译,将分别得到一个库文件和二个可执行文件,即这些文件push到手机中就可以开始验证了。 (1)在火炮未准备就绪的情况下(即server未运行),“开炮” C:\DaS\tel123> adb shell MyClient fire 结果(均为通过 adb logcat -v time | egrep "MyClient|MyBinder" 命令查看): <pre> 01-02 11:44:50.558 W/ADB_SERVICES( 4504): create_local_service_socket() name=shell:MyClient fire 01-02 11:44:50.577 I/ServiceManager( 4529): Waiting for service service.MyBinder... 01-02 11:44:51.578 I/ServiceManager( 4529): Waiting for service service.MyBinder... 01-02 11:44:52.578 I/ServiceManager( 4529): Waiting for service service.MyBinder... 01-02 11:44:53.579 I/ServiceManager( 4529): Waiting for service service.MyBinder... 01-02 11:44:54.579 I/ServiceManager( 4529): Waiting for service service.MyBinder... 01-02 11:44:55.579 W/MyClient( 4529): Cannot connect to the service.MyBinder </pre> (2) 准备火炮: C:\DaS\tel123> adb shell MyServer 再开炮: C:\DaS\tel123> adb shell MyClient fire 结果: 01-02 11:45:03.247 W/MyClient( 4534): no bomb.. 没炮弹了?查看一下: C:\DaS\tel123> adb shell MyClient checkBomb 结果: 01-02 11:45:21.359 D/MyClient( 4536): rest bomb:0 还真是!装弹: C:\DaS\tel123> adb shell MyClient loadBomb 2 结果显示装弹成功: 01-02 11:45:29.909 D/MyClient( 4538): loadBomb sucess. 保险起见,再检查一下: C:\DaS\tel123> adb shell MyClient checkBomb 返回所剩炮弹: 01-02 11:45:33.128 D/MyClient( 4540): rest bomb:2 好吧,可以开炮了吧: C:\DaS\tel123> adb shell MyClient fire 结果: 01-02 11:45:41.779 D/MyClient( 4542): Bang! 再来: C:\DaS\tel123> adb shell MyClient fire 结果: 01-02 11:45:45.202 D/MyClient( 4544): Bang! 兴起!再来!: C:\DaS\tel123> adb shell MyClient fire 额,又没炮弹了?: 01-02 11:45:54.152 W/MyClient( 4546): no bomb.. 对,好像刚是只装了两发: C:\DaS\tel123> adb shell MyClient checkBomb 结果: 01-02 11:45:56.566 D/MyClient( 4548): rest bomb:0 上述源码可从[http://www.hovercool.com/upload/en/code/MyBinder.rar 这里]打包下载. 参考资料: http://disanji.net/2011/02/28/android-bnder-design/ http://blog.csdn.net/a345017062/article/details/6175519 http://www.cnblogs.com/innost/archive/2011/01/09/1931456.html
返回
binder @ 用cpp实现一个service
。
导航菜单
个人工具
   
个人维基
注册
登录
名字空间
页面
变换
查看
阅读
查看源代码
统计
查看历史
操作
搜索
导航
首页
Ubuntu
Android
C&CPP
Java
Python
大杂烩
最近更改
工具箱
所有页面
文件列表
特殊页面