http://blog.youkuaiyun.com/hitlion2008/article/details/9842289
Android中的RPC(IPC)是由Binder组件来实现的,虽然我们使用更多的还是AIDL,并不会直接使用Binder,但是了解了它能更有效帮助理解AIDL以及理解Android本身的一些原理和机制。
Binder的架构
与其他的Android系统的组件的架构类似,Binder也是由Java层封装,JNI,libbinder和driver组成。Binder的主要组成有三个IInterface, IBinder, Binder和BinderProxy。但是我们需要关注的仅是Binder对象和BinderProxy。其中BinderProxy是给客户端使用的,客户端通过调用其上的transact来marshalling数据,并且向底层发送消息;Binder是给服务端使用的,服务端要实现onTransact方法,以便处理客户端的方法调用请求并返回结果。IInterface接口主要是给系统使用的,用于在ServiceManager中查找对应的Service。它们之间的关系是:
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
注意:编译这个示例的方式是把这些文件放在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:
- LOCAL_PATH := $(call my-dir)
- include $(CLEAR_VARS)
- LOCAL_MODULE := nativeclient
- LOCAL_MODULE_TAGS := optional
- LOCAL_SRC_FILES := mathinterface.cpp \
- client.cpp
- LOCAL_SHARED_LIBRARIES := libutils libcutils libbinder
- LOCAL_C_INCLUDES += frameworks/base/include system/core/include
- include $(BUILD_EXECUTABLE)
- include $(CLEAR_VARS)
- LOCAL_MODULE := nativeserver
- LOCAL_MODULE_TAGS := optional
- LOCAL_SRC_FILES := mathinterface.cpp \
- server.cpp
- LOCAL_SHARED_LIBRARIES := libutils libcutils libbinder
- LOCAL_C_INCLUDES += frameworks/base/include system/core/include
- include $(BUILD_EXECUTABLE)
- /**
- * Demonstrate how to us Binder in Native C++ codes.
- *
- * The interface describes the RPC calls.
- *
- * Based on BinderDemo: https://github.com/gburca/BinderDemo/blob/master/binder.cpp
- */
- #ifndef _MATH_INTERFACE_H
- #define _MATH_INTERFACE_H
- #define LOG_TAG "native_binder"
- #include <stdlib.h>
- #include <binder/IBinder.h>
- #include <utils/Log.h>
- #include <utils/TextOutput.h>
- using namespace android;
- #define INFO(...) \
- do { \
- printf(__VA_ARGS__); \
- printf("\n"); \
- LOGD(__VA_ARGS__); \
- } while (0)
- /**
- * The interface describing the RPC methods.
- *
- * RefBase is the base class for smart pointer.
- */
- class MathInterface : public RefBase {
- public:
- enum {
- PRINT = IBinder::FIRST_CALL_TRANSACTION,
- ADD
- };
- virtual void print(const char *msg) = 0;
- virtual int32_t add(int32_t a, int32_t b) = 0;
- static const String16 DESCRIPTOR;
- MathInterface();
- virtual ~MathInterface();
- };
- #endif
- /**
- * Demonstrate how to us Binder in Native C++ codes.
- *
- * The interface describes the RPC calls.
- *
- * Based on BinderDemo: https://github.com/gburca/BinderDemo/blob/master/binder.cpp
- */
- #include "mathinterface.h"
- const String16 MathInterface::DESCRIPTOR("MathInterface");
- MathInterface::MathInterface() {
- INFO("MathInterface::MathInterface()");
- }
- MathInterface::~MathInterface() {
- INFO("MathInterface::~MathInterface()");
- }
- /**
- * Demonstrate how to us Binder in Native C++ codes.
- *
- * The interface describes the RPC calls.
- *
- * Based on BinderDemo: https://github.com/gburca/BinderDemo/blob/master/binder.cpp
- */
- #include <stdlib.h>
- #include <binder/IBinder.h>
- #include <binder/IServiceManager.h>
- #include <binder/Parcel.h>
- #include <utils/TextOutput.h>
- #include "mathinterface.h"
- using namespace android;
- /**
- * The proxy used for client side.
- */
- class MathBinderProxy : public MathInterface {
- private:
- sp<IBinder> remote;
- public:
- MathBinderProxy(const sp<IBinder>& impl);
- void print(const char *msg);
- int32_t add(int32_t a, int32_t b);
- };
- MathBinderProxy::MathBinderProxy(const sp<IBinder>& impl) {
- INFO("MathBinderProxy::MathBinderProxy()");
- remote = impl;
- }
- void MathBinderProxy::print(const char *msg) {
- Parcel data, reply;
- data.writeInterfaceToken(MathInterface::DESCRIPTOR);
- data.writeString16(String16(msg));
- aout << "MathBinderProxy::print parcel to be sent:\n";
- data.print(aout);
- endl(aout);
- remote->transact(MathInterface::PRINT, data, &reply, IBinder::FLAG_ONEWAY);
- INFO("MathBinderProxy::print() is returned");
- }
- int32_t MathBinderProxy::add(int32_t a, int32_t b) {
- Parcel data, reply;
- data.writeInterfaceToken(MathInterface::DESCRIPTOR);
- data.writeInt32(a);
- data.writeInt32(b);
- aout << "MathBinderProxy::add parcel to be sent:\n";
- data.print(aout);
- endl(aout);
- remote->transact(MathInterface::ADD, data, &reply);
- INFO("MathBinderProxy::add transact reply");
- reply.print(aout);
- endl(aout);
- int32_t res;
- status_t status = reply.readInt32(&res);
- INFO("MathBinderProxy::add(%i, %i) = %i(status: %i)",
- a, b, res, status);
- return res;
- }
- static sp<MathInterface> getMathServer(const char *msg) {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder = sm->getService(String16(msg));
- if (binder == NULL) {
- INFO("getmath server, cannot find server '%s'", msg);
- return NULL;
- }
- sp<MathInterface> svr = new MathBinderProxy(binder);
- return svr;
- }
- int main(int argc, char **argv) {
- INFO("we are the client");
- const char *native = "MathServer";
- const char *java = "JavaServerService";
- sp<MathInterface> svc = getMathServer(java);
- if (svc == NULL) {
- INFO("failed to find service");
- return -1;
- }
- svc->print("Hello, welcome to the world of native binder");
- int32_t s = svc->add(2013, 3102);
- INFO("Addition result: %i + %i = %i", 2013, 3102, s);
- return 0;
- }
- /**
- * Demonstrate how to us Binder in Native C++ codes.
- *
- * The interface describes the RPC calls.
- *
- * Based on BinderDemo: https://github.com/gburca/BinderDemo/blob/master/binder.cpp
- */
- #include <stdlib.h>
- #include <binder/IPCThreadState.h>
- #include <binder/IServiceManager.h>
- #include <utils/Log.h>
- #include <utils/TextOutput.h>
- #include "mathinterface.h"
- using namespace android;
- /**
- * The remote binder or the server.
- */
- class MathBinder : public BBinder {
- protected:
- virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
- public:
- virtual void print(const char *msg);
- virtual int32_t add(int32_t a, int32_t b);
- };
- status_t MathBinder::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
- INFO("MathBinder::onTransact(%i) %i", code, flags);
- /*
- * Before executing actual method, check whether the RPC are from expected client.
- * Client will write interface token, to identify interface to which those methods
- * belong.
- */
- if (!data.enforceInterface(MathInterface::DESCRIPTOR)) {
- INFO("failed to check Interface, you might call wrong service, this is for '%s'",
- String8(MathInterface::DESCRIPTOR).string());
- return BAD_TYPE;
- }
- data.print(aout);
- endl(aout);
- switch(code) {
- case MathInterface::PRINT: {
- String16 msg = data.readString16();
- print(String8(msg).string());
- return NO_ERROR;
- }
- case MathInterface::ADD: {
- int32_t a = data.readInt32();
- int32_t b = data.readInt32();
- int32_t sum = add(a, b);
- INFO("MathBinder:onTransact add(%i, %i) = %i", a, b, sum);
- reply->print(aout); endl(aout);
- reply->writeInt32(sum);
- return NO_ERROR;
- }
- default:
- INFO("MathBinder, bad requesting code, no match found");
- }
- return BBinder::onTransact(code, data, reply, flags);
- }
- void MathBinder::print(const char *msg) {
- INFO("MathBinder::print, msg is '%s'", msg);
- }
- int32_t MathBinder::add(int32_t a, int32_t b) {
- return a + b;
- }
- int main(int argc, char **argv) {
- INFO("We're the service");
- defaultServiceManager()->addService(String16("MathServer"),
- new MathBinder());
- ProcessState::self()->startThreadPool();
- INFO("Math server is running now");
- IPCThreadState::self()->joinThreadPool();
- INFO("Math server thread joined");
- return 0;
- }
Binder实现的是RPC,它与具体语言无关,所以理论上,基于Binder可以让Native的进程与Android Java层的应用程序通讯。最关键的,也是最麻烦点就在于客户端如何获取服务端的Service的IBinder对象,但也非不可能,要通过JNI和ClassLoader等一系列方式可以获得Java层的对象,其实Java层API的实现也是以这样子的方式,具体的可以参考这篇文章。