something about binder and service

来源:互联网 发布:会计核算软件 怎么填 编辑:程序博客网 时间:2024/05/20 12:48

       Binder是一种架构,这种架构提供了服务端接口、Binder驱动、客户端接口三个模块。

       服务端:一个Binder服务端实际上就是一个Binder类的对象,该对象一旦创建,内部就启动一个隐藏线程。该线程接下来会接收Binder驱动发送的消息,收到消息后,会执行到Binder对象中的onTransact()函数,并按照该函数的参数执行不同的服务代码。因此,要实现一个Binder服务,就必须重载onTransact()方法。重载onTransact()函数的主要内容是把onTransact()函数的参数转换为服务函数的参数,而onTransact()函数的参数来源是客户端调用transact()函数时输入的,因此,如果transact()有固定格式的输入,那么onTransact()就会有固定格式的输出。

       

Binder驱动:任意一个服务端Binder对象被创建时,同时会在Binder驱动中创建一个mRemote对象,该对象的类型也是Binder类。客户端要访问远程服务时,都是通过mRemote对象。


       客户端:客户端要想访问远程服务,必须获取远程服务在Binder对象中对应的mRemote引用,至于如何获取,下面将会介绍。获得该mRemote对象后,就可以调用其transact()方法


而在Binder驱动中,mRemote对象也重载了transact()方法,重载的内容主要包括以下几项

 以线程间消息通信的模式,向服务端发送客户端传递过来的参数。

  •  挂起当前线程,当前线程正是客户端线程,并等待服务端线程执行完指定服务函数后通知(notify)。
  •  接收到服务端线程的通知,然后继续执行客户端线程,并返回到客户端代码区。

在C++层通过引入Binder进程间通信机制可以实现跨进程访问匿名共享内存。

我们知道Android匿名共享内存的设计本身就是为了实现进程间共享大量数据,

当源进程开辟一块匿名共享内存并把这块匿名共享内存映射到当前进程的虚拟地址空间

从而使当前进程可以直接访问这块匿名共享内存后,如何让目标进程共享访问这块匿名共享内存呢?

这就需要利用Binder进程间通信方式将匿名共享内存的文件描述符传输给目标进程,

目标进程才能将得到的匿名共享内存文件描述符映射到本进程地址空间中,

只有这样目标进程才能访问源进程创建的这块匿名共享内存。

将Binder进程间通信方式与匿名共享内存相结合实现小数据量传输换来大数据量共享。


如何实现一个native service
要点如下:
a、核心服务通常在独立的进程 (Process) 里执行。
b、必须提供 IBinder 接口,让其它程序可以进行跨进程的绑定 (Binding) 和呼叫。
c、因为共享,所以必须确保多线程安全 (Thread-safe) 。
d、以 C++ 类别定义,诞生其对象,透过 SM 之协助,将该对象参考值传给 IServiceManager::addService() 函数,就加入到 Binder Driver 里了。
e、应用程序可透过 SM 之协助而远距绑定该核心服务,此时 SM 会回传 IBinder 接口给应用程序。
f、应用程序可透过 IBinder::transact() 函数来与核心服务互传数据。


a、编写服务进程serviceTestA.h 头文件定义:#ifndef __SERVICE_TEST_A__#define __SERVICE_TEST_A__#include <utils/RefBase.h>#include <binder/IInterface.h>#include <binder/Parcel.h>#include <utils/threads.h>namespace android{//继承BBinder类,从而提供IBinder 接口class serviceTestA:public BBinder{public:      serviceTestA();virtual ~serviceTestA();static int instantiate(); //建立唯一类实例virtual status_t onTransact(uint32_t, const Parcel&, Parcel*, uint32_t);private:// protected by mLock 多线程安全               mutable Mutex mLock;};}#endif /* __SERVICE_TEST_A__ */serviceTestA.cpp 实现文件:#include <cutils/log.h>#include <cutils/properties.h>#include <binder/IServiceManager.h>#include <binder/IPCThreadState.h>#include <serviceTestA/serviceTestA.h>namespace android {enum{CALCULATE_MUL_NUM = 0,CALCULATE_DIV_NUM ,};int serviceTestA::instantiate() {LOGI("serviceTestA instantiate");int r = defaultServiceManager()->addService(String16("service.TestA"),new serviceTestA());LOGI("serviceTestA r = %d/n", r);return r;}serviceTestA::serviceTestA() {LOGI("serviceTestA created");}serviceTestA::~serviceTestA(){LOGI("serviceTestA destroyed");}status_t serviceTestA::onTransact(uint32_t code, const Parcel&data, Parcel*reply, uint32_t flags){LOGI("serviceTestA::onTransact code = %d",code);Mutex::Autolock _l(mLock);switch(code){case CALCULATE_MUL_NUM:{int a = data.readInt32();int b = data.readInt32();int sum = a * b ;LOGI("sum mul value = %d",sum);reply->writeInt32(sum);return NO_ERROR;}break;case CALCULATE_DIV_NUM:{int a = data.readInt32();int b = data.readInt32();int sum = a / b ;LOGI("sum div value = %d",sum);reply->writeInt32(sum);return NO_ERROR;}break;default:return BBinder::onTransact(code, data, reply, flags);}return 0;}}

Android.mk 文件:LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_SRC_FILES:= serviceTestA.cppLOCAL_SHARED_LIBRARIES:= libutils libutils libbinderLOCAL_C_INCLUDES := $(TOP)/frameworks/base/includeLOCAL_MODULE:= libServiceTestALOCAL_PRELINK_MODULE:= falseinclude $(BUILD_SHARED_LIBRARY)
编写独立的进程程序:它的用途是:诞生一个 serviceTestA 类别之对象,然后将该对象参考存入 Binder Driver 里。
#include <sys/types.h>#include <unistd.h>#include <cutils/log.h>#include <binder/IServiceManager.h>#include <binder/IPCThreadState.h>#include <serviceTestA/serviceTestA.h>using namespace android;int main(int argc,char *argv[]){sp<ProcessState> proc(ProcessState::self());sp<IServiceManager> sm = defaultServiceManager();LOGI("ServiceManager: %p", sm.get());serviceTestA::instantiate(); // 这是重点。。。。ProcessState::self()->startThreadPool();IPCThreadState::self()->joinThreadPool();return 0;}Android.mk 文件:LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_SRC_FILES:= main.cppLOCAL_SHARED_LIBRARIES:= libutils libServiceTestALOCAL_MODULE:= serviceTestAinclude $(BUILD_EXECUTABLE)
这里最重要的是调用:serviceTestA::instantiate();其先执行到 new serviceTestA() ,就诞生一个 serviceTestA 类别之对象;接着,呼叫 defaultServiceManager() 函数取得 SM 的 IServiceManager 接口;再呼叫 IServiceManager::addService() 将该对象参考存入 Binder Driver 里,并且同时存入到ServiceManager中注册并管理,如此其它进程才能通过ServiceManager::getService找到相应服务进程以上代码同理,serviceTestB服务进程也一样的这样建立,不再复述。b、测试服务进程testService.cpp编写:#include <cutils/log.h>#include <cutils/properties.h>#include <binder/IServiceManager.h>#include <binder/IPCThreadState.h>#include <serviceTestA/serviceTestA.h>#include <serviceTestB/serviceTestB.h>using namespace android;enum{CALCULATE_ADD_NUM = 0,CALCULATE_SUB_NUM ,};enum{CALCULATE_MUL_NUM = 0,CALCULATE_DIV_NUM ,};int main(int argc,char *argv[]){sp<IBinder> TestAbinder;sp<IBinder> TestBbinder;Parcel data, reply;int sum=0;LOGI("testService main is call...");sp<IServiceManager> sm = defaultServiceManager();while(1){TestAbinder = sm->getService(String16("service.TestA"));LOGE("TestA::getAddService %p/n",sm.get());if (TestAbinder == 0) {LOGE("TestAService not published, waiting...");usleep(1000000);continue;}else{LOGI("TestA::getAddService success...");break;}}while(1){TestBbinder = sm->getService(String16("service.TestB"));LOGE("TestB::getAddService %p/n",sm.get());if (TestBbinder == 0) {LOGE("TestBService not published, waiting...");usleep(1000000);continue;}else{LOGI("TestB::getAddService success...");break;}}//测试两个service中的函数data.writeInt32(1000);data.writeInt32(200);LOGI("BpAddService::create remote()->transact()/n");TestAbinder->transact(CALCULATE_MUL_NUM,data,&reply);sum = reply.readInt32();LOGI("CALCULATE_ADD_NUM value = %d",sum);data.writeInt32(1000);data.writeInt32(200);LOGI("BpAddService::create remote()->transact()/n");TestAbinder->transact(CALCULATE_DIV_NUM,data,&reply);sum = reply.readInt32();LOGI("CALCULATE_SUB_NUM value = %d",sum);data.writeInt32(1000);data.writeInt32(200);LOGI("BpAddService::create remote()->transact()/n");TestBbinder->transact(CALCULATE_ADD_NUM,data,&reply);sum = reply.readInt32();LOGI("CALCULATE_MUL_NUM value = %d",sum);data.writeInt32(1000);data.writeInt32(200);LOGI("BpAddService::create remote()->transact()/n");TestBbinder->transact(CALCULATE_SUB_NUM,data,&reply);sum = reply.readInt32();LOGI("CALCULATE_DIV_NUM value = %d",sum);return 0;}这里最重要的就是通过defaultServiceManager得到默认的sm,然后通过getService得到sp<IBinder>对象,即可操作相应服务进程的接口函数,整个过程还是相当清晰的。最后附上测试的结果打印:# ./TestService./TestService# logcatlogcat--------- beginning of /dev/log/mainI/        ( 1379): testService main is call...E/        ( 1379): TestA::getAddService 0xa680/nI/        ( 1379): TestA::getAddService success...E/        ( 1379): TestB::getAddService 0xa680/nI/        ( 1379): TestB::getAddService success...I/        ( 1379): BpAddService::create remote()->transact()/nI/        ( 1371): serviceTestA::onTransact code = 0I/        ( 1371): sum mul value = 200000I/        ( 1379): CALCULATE_MUL_NUM value = 200000I/        ( 1379): BpAddService::create remote()->transact()/nI/        ( 1371): serviceTestA::onTransact code = 1I/        ( 1371): sum div value = 5I/        ( 1379): CALCULATE_DIV_NUM value = 5I/        ( 1379): BpAddService::create remote()->transact()/nI/        ( 1374): serviceTestB::onTransact code = 0I/        ( 1374): sum add value = 1200I/        ( 1379): CALCULATE_ADD_NUM value = 1200I/        ( 1379): BpAddService::create remote()->transact()/nI/        ( 1374): serviceTestB::onTransact code = 1I/        ( 1374): sum sub value = 800I/        ( 1379): CALCULATE_SUB_NUM value = 800结果表明完全正确


http://blog.csdn.net/andyhuabing/article/details/7245058

0 0
原创粉丝点击