Android实战技术:理解Binder机制

http://blog.csdn.net/hitlion2008/article/details/9842289


Android中的RPC(IPC)是由Binder组件来实现的,虽然我们使用更多的还是AIDL,并不会直接使用Binder,但是了解了它能更有效帮助理解AIDL以及理解Android本身的一些原理和机制。

Binder的架构

与其他的Android系统的组件的架构类似,Binder也是由Java层封装,JNI,libbinder和driver组成。
Android实战技术:理解Binder机制_第1张图片
Binder的主要组成有三个IInterface, IBinder, Binder和BinderProxy。但是我们需要关注的仅是Binder对象和BinderProxy。其中BinderProxy是给客户端使用的,客户端通过调用其上的transact来marshalling数据,并且向底层发送消息;Binder是给服务端使用的,服务端要实现onTransact方法,以便处理客户端的方法调用请求并返回结果。IInterface接口主要是给系统使用的,用于在ServiceManager中查找对应的Service。它们之间的关系是:

Android实战技术:理解Binder机制_第2张图片

关键的对象就是BinderProxy和Binder,BinderProxy是给客户端使用的对象,它的工作就是marshalling,然后调用IBinder的transact方法把信息传递出去。而Binder对象则是服务端的对象,它实现了客户端所需要的方法。

Java层的源码:

  • ./frameworks/base/core/java/android/os/IInterface.java
  • ./frameworks/base/core/java/android/os/Binder.java
  • ./frameworks/base/core/java/android/os/IBinder.java
  • ./frameworks/base/core/java/android/os/Parcel.java
  • ./frameworks/base/core/java/android/os/Parcelable.java

JNI Wrapper层:

  • ./frameworks/base/core/jni/android_util_Binder.cpp
  • ./frameworks/base/core/jni/android_util_Binder.h

在Native层使用Binder

除了在Java层使用Binder进行RPC外,在Native层也是可以使用的,因为Java层是依赖于libbinder的,而libbinder,它仅是一个共享库而已,所以在Native层也是可以使用的。只是libbinder并没有在NDK中公开,甚至它没有包含在NDK中,所以只能是在Android系统源码中使用libbinder。Native层使用Binder进行RPC与Java层十分类似,仅是语言语法上面的区别,原理和机制都是一样的,毕竟Java层仅是多穿上一层衣服而已。

libbinder的代码:

  • ./frameworks/base/libs/binder/BpBinder.cpp
  • ./frameworks/base/libs/binder/Binder.cpp
  • ./frameworks/base/include/binder/BpBinder.h
  • ./frameworks/base/include/binder/IBinder.h
  • ./frameworks/base/include/binder/BinderService.h
  • ./frameworks/base/include/binder/Binder.h
  • ./frameworks/base/libs/binder/IInterface.cpp
  • ./frameworks/base/include/binder/IInterface.h
  • ./frameworks/base/libs/binder/Parcel.cpp
  • ./frameworks/base/include/binder/Parcel.h
这里有一个实例,使用libbinder实现一个client与server的通讯。
Android实战技术:理解Binder机制_第3张图片

注意:编译这个示例的方式是把这些文件放在packages/apps/里或者externals中,然后运行mm进行编译,编译好的文件在out/target/product/generic/system/bin下面。adb push到Android 模拟器,然后在adb shell中运行,需要打开二个adb shell一个运行nativeserver,另一个运行nativeclient,最好再用DDMS查看logcat,TAG是native_binder。

Android.mk:

[plain]  view plain copy print ?
  1. LOCAL_PATH := $(call my-dir)  
  2.   
  3. include $(CLEAR_VARS)  
  4. LOCAL_MODULE := nativeclient  
  5. LOCAL_MODULE_TAGS := optional  
  6. LOCAL_SRC_FILES := mathinterface.cpp \  
  7.     client.cpp  
  8.   
  9. LOCAL_SHARED_LIBRARIES := libutils libcutils libbinder  
  10. LOCAL_C_INCLUDES += frameworks/base/include system/core/include  
  11.   
  12. include $(BUILD_EXECUTABLE)  
  13.   
  14. include $(CLEAR_VARS)  
  15. LOCAL_MODULE := nativeserver  
  16. LOCAL_MODULE_TAGS := optional  
  17. LOCAL_SRC_FILES := mathinterface.cpp \  
  18.     server.cpp  
  19. LOCAL_SHARED_LIBRARIES := libutils libcutils libbinder  
  20. LOCAL_C_INCLUDES += frameworks/base/include system/core/include  
  21.   
  22. include $(BUILD_EXECUTABLE)  
The interface:

[cpp]  view plain copy print ?
  1. /** 
  2.  * Demonstrate how to us Binder in Native C++ codes. 
  3.  * 
  4.  * The interface describes the RPC calls. 
  5.  * 
  6.  * Based on BinderDemo: https://github.com/gburca/BinderDemo/blob/master/binder.cpp 
  7.  */  
  8. #ifndef _MATH_INTERFACE_H  
  9. #define _MATH_INTERFACE_H  
  10.   
  11. #define LOG_TAG "native_binder"  
  12.   
  13. #include <stdlib.h>  
  14. #include <binder/IBinder.h>  
  15. #include <utils/Log.h>  
  16. #include <utils/TextOutput.h>  
  17.   
  18. using namespace android;  
  19.   
  20. #define INFO(...) \  
  21.     do { \  
  22.         printf(__VA_ARGS__); \  
  23.         printf("\n"); \  
  24.         LOGD(__VA_ARGS__); \  
  25.     } while (0)  
  26.   
  27. /** 
  28.  * The interface describing the RPC methods. 
  29.  * 
  30.  * RefBase is the base class for smart pointer. 
  31.  */  
  32. class MathInterface : public RefBase {  
  33. public:  
  34.     enum {  
  35.         PRINT = IBinder::FIRST_CALL_TRANSACTION,  
  36.         ADD  
  37.     };  
  38.   
  39.     virtual void print(const char *msg) = 0;  
  40.   
  41.     virtual int32_t add(int32_t a, int32_t b) = 0;  
  42.   
  43.     static const String16 DESCRIPTOR;  
  44.   
  45.     MathInterface();  
  46.   
  47.     virtual ~MathInterface();  
  48. };  
  49.   
  50. #endif  
[cpp]  view plain copy print ?
  1. /** 
  2.  * Demonstrate how to us Binder in Native C++ codes. 
  3.  * 
  4.  * The interface describes the RPC calls. 
  5.  * 
  6.  * Based on BinderDemo: https://github.com/gburca/BinderDemo/blob/master/binder.cpp 
  7.  */  
  8. #include "mathinterface.h"  
  9.   
  10. const String16 MathInterface::DESCRIPTOR("MathInterface");  
  11.   
  12. MathInterface::MathInterface() {  
  13.     INFO("MathInterface::MathInterface()");  
  14. }  
  15.   
  16. MathInterface::~MathInterface() {  
  17.     INFO("MathInterface::~MathInterface()");  
  18. }  
Client:

[cpp]  view plain copy print ?
  1. /** 
  2.  * Demonstrate how to us Binder in Native C++ codes. 
  3.  * 
  4.  * The interface describes the RPC calls. 
  5.  * 
  6.  * Based on BinderDemo: https://github.com/gburca/BinderDemo/blob/master/binder.cpp 
  7.  */  
  8.   
  9. #include <stdlib.h>  
  10. #include <binder/IBinder.h>  
  11. #include <binder/IServiceManager.h>  
  12. #include <binder/Parcel.h>  
  13. #include <utils/TextOutput.h>  
  14.   
  15. #include "mathinterface.h"  
  16.   
  17. using namespace android;  
  18.   
  19. /** 
  20.  * The proxy used for client side. 
  21.  */  
  22. class MathBinderProxy : public MathInterface {  
  23. private:  
  24.     sp<IBinder> remote;  
  25. public:  
  26.     MathBinderProxy(const sp<IBinder>& impl);  
  27.   
  28.     void print(const char *msg);  
  29.   
  30.     int32_t add(int32_t a, int32_t b);  
  31. };  
  32.   
  33. MathBinderProxy::MathBinderProxy(const sp<IBinder>& impl) {  
  34.     INFO("MathBinderProxy::MathBinderProxy()");  
  35.     remote = impl;  
  36. }  
  37.   
  38. void MathBinderProxy::print(const char *msg) {  
  39.     Parcel data, reply;  
  40.     data.writeInterfaceToken(MathInterface::DESCRIPTOR);  
  41.     data.writeString16(String16(msg));  
  42.   
  43.     aout << "MathBinderProxy::print parcel to be sent:\n";  
  44.     data.print(aout);  
  45.     endl(aout);  
  46.     remote->transact(MathInterface::PRINT, data, &reply, IBinder::FLAG_ONEWAY);  
  47.     INFO("MathBinderProxy::print() is returned");  
  48. }  
  49.   
  50. int32_t MathBinderProxy::add(int32_t a, int32_t b) {  
  51.     Parcel data, reply;  
  52.     data.writeInterfaceToken(MathInterface::DESCRIPTOR);  
  53.     data.writeInt32(a);  
  54.     data.writeInt32(b);  
  55.   
  56.     aout << "MathBinderProxy::add parcel to be sent:\n";  
  57.     data.print(aout);  
  58.     endl(aout);  
  59.   
  60.     remote->transact(MathInterface::ADD, data, &reply);  
  61.     INFO("MathBinderProxy::add transact reply");  
  62.     reply.print(aout);  
  63.     endl(aout);  
  64.     int32_t res;  
  65.     status_t status = reply.readInt32(&res);  
  66.     INFO("MathBinderProxy::add(%i, %i) = %i(status: %i)",  
  67.             a, b, res, status);  
  68.     return res;  
  69. }  
  70.   
  71. static sp<MathInterface> getMathServer(const char *msg) {  
  72.     sp<IServiceManager> sm = defaultServiceManager();  
  73.     sp<IBinder> binder = sm->getService(String16(msg));  
  74.     if (binder == NULL) {  
  75.         INFO("getmath server, cannot find server '%s'", msg);  
  76.         return NULL;  
  77.     }  
  78.     sp<MathInterface> svr = new MathBinderProxy(binder);  
  79.     return svr;  
  80. }  
  81.   
  82. int main(int argc, char **argv) {  
  83.     INFO("we are the client");  
  84.     const char *native = "MathServer";  
  85.     const char *java = "JavaServerService";  
  86.     sp<MathInterface> svc = getMathServer(java);  
  87.     if (svc == NULL) {  
  88.         INFO("failed to find service");  
  89.         return -1;  
  90.     }  
  91.     svc->print("Hello, welcome to the world of native binder");  
  92.     int32_t s = svc->add(2013, 3102);  
  93.     INFO("Addition result: %i + %i = %i", 2013, 3102, s);  
  94.   
  95.     return 0;  
  96. }  
Server:

[cpp]  view plain copy print ?
  1. /** 
  2.  * Demonstrate how to us Binder in Native C++ codes. 
  3.  * 
  4.  * The interface describes the RPC calls. 
  5.  * 
  6.  * Based on BinderDemo: https://github.com/gburca/BinderDemo/blob/master/binder.cpp 
  7.  */  
  8. #include <stdlib.h>  
  9. #include <binder/IPCThreadState.h>  
  10. #include <binder/IServiceManager.h>  
  11. #include <utils/Log.h>  
  12. #include <utils/TextOutput.h>  
  13.   
  14. #include "mathinterface.h"  
  15.   
  16. using namespace android;  
  17.   
  18. /** 
  19.  * The remote binder or the server. 
  20.  */  
  21. class MathBinder : public BBinder {  
  22. protected:  
  23.     virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);  
  24. public:  
  25.     virtual void print(const char *msg);  
  26.     virtual int32_t add(int32_t a, int32_t b);  
  27. };  
  28.   
  29. status_t MathBinder::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {  
  30.     INFO("MathBinder::onTransact(%i) %i", code, flags);  
  31.     /* 
  32.      * Before executing actual method, check whether the RPC are from expected client. 
  33.      * Client will write interface token, to identify interface to which those methods 
  34.      * belong. 
  35.      */  
  36.     if (!data.enforceInterface(MathInterface::DESCRIPTOR)) {  
  37.         INFO("failed to check Interface, you might call wrong service, this is for '%s'",  
  38.                 String8(MathInterface::DESCRIPTOR).string());  
  39.         return BAD_TYPE;  
  40.     }  
  41.     data.print(aout);  
  42.     endl(aout);  
  43.   
  44.     switch(code) {  
  45.     case MathInterface::PRINT: {  
  46.         String16 msg = data.readString16();  
  47.         print(String8(msg).string());  
  48.         return NO_ERROR;  
  49.     }  
  50.     case MathInterface::ADD: {  
  51.         int32_t a = data.readInt32();  
  52.         int32_t b = data.readInt32();  
  53.         int32_t sum = add(a, b);  
  54.         INFO("MathBinder:onTransact add(%i, %i) = %i", a, b, sum);  
  55.         reply->print(aout); endl(aout);  
  56.         reply->writeInt32(sum);  
  57.         return NO_ERROR;  
  58.     }  
  59.     default:  
  60.         INFO("MathBinder, bad requesting code, no match found");  
  61.     }  
  62.     return BBinder::onTransact(code, data, reply, flags);  
  63. }  
  64.   
  65. void MathBinder::print(const char *msg) {  
  66.     INFO("MathBinder::print, msg is '%s'", msg);  
  67. }  
  68.   
  69. int32_t MathBinder::add(int32_t a, int32_t b) {  
  70.     return a + b;  
  71. }  
  72.   
  73. int main(int argc, char **argv) {  
  74.     INFO("We're the service");  
  75.       
  76.     defaultServiceManager()->addService(String16("MathServer"),  
  77.             new MathBinder());  
  78.     ProcessState::self()->startThreadPool();  
  79.     INFO("Math server is running now");  
  80.     IPCThreadState::self()->joinThreadPool();  
  81.     INFO("Math server thread joined");  
  82.   
  83.     return 0;  
  84. }  

Binder实现的是RPC,它与具体语言无关,所以理论上,基于Binder可以让Native的进程与Android Java层的应用程序通讯。最关键的,也是最麻烦点就在于客户端如何获取服务端的Service的IBinder对象,但也非不可能,要通过JNI和ClassLoader等一系列方式可以获得Java层的对象,其实Java层API的实现也是以这样子的方式,具体的可以参考这篇文章。

你可能感兴趣的:(Android实战技术:理解Binder机制)