Practical android technology: Understanding the Binder Mechanism

Source: Internet
Author: User

RPC (IPC) in Android is implemented by the binder component. Although we use more aidl, we will not directly use binder, however, it can help you better understand aidl and the principles and mechanisms of Android.

Binder Architecture

Similar to the architecture of other android components, the binder is also composed of Java-layer encapsulation, JNI, libbinder, and driver.

The main components of the binder include three iinterfaces, ibinder, binder, and binderproxy. However, we only need to focus on the binder object and binderproxy. Here, binderproxy is used by the client. The client calls the transact on it to invoke alling data and send messages to the underlying layer. The binder is used by the server, and the server must implement the ontransact method, in order to process client method call requests and return results. The iinterface is mainly used by the system to find the corresponding service in servicemanager. The relationship between them is:

The key objects are binderproxy and binder. binderproxy is the object used for the client. Its job is to perform alling, and then the ibinder's transact method is called to transfer the information. The binder object is the server object, which implements the methods required by the client.

Source code of the Java layer:

  • ./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 layer:

  • ./Frameworks/base/CORE/JNI/android_util_binder.cpp
  • ./Frameworks/base/CORE/JNI/android_util_binder.h
Use Binder on the native Layer

In addition to using Binder for RPC in the Java layer, it can also be used in the native layer, because the Java layer depends on libbinder and libbinder is only a shared library, so it can also be used in the native layer. Libbinder is not disclosed in ndk, or even not included in ndk, so it can only be used in the Android system source code. The native layer uses Binder for RPC, which is very similar to the Java layer. It is only the difference in language syntax. The principle and mechanism are the same. After all, the Java layer only needs to wear one more layer of clothing.

Libbinder code:

  • ./Frameworks/base/libs/binder/bpbinder. cpp
  • ./Frameworks/base/libs/binder. cpp
  • ./Frameworks/base/include/binder/bpbinder. h
  • ./Frameworks/base/include/binder/ibinder. h
  • ./Frameworks/base/include/binder/binderservice. h
  • ./Frameworks/base/include/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

Here is an instance that uses libbinder to implement communication between a client and a server.

Note:This example is compiled by placing these files in packages/apps/or externals, and then running mm for compilation, the compiled file is under out/target/product/generic/system/bin. ADB pushes to the android simulator and then runs in the ADB shell. You need to enable two ADB shells to run nativeserver and the other to run nativeclient. You 'd better use ddms to view logcat. The tag is native_binder.

Android. mk:

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODULE := nativeclientLOCAL_MODULE_TAGS := optionalLOCAL_SRC_FILES := mathinterface.cpp \client.cppLOCAL_SHARED_LIBRARIES := libutils libcutils libbinderLOCAL_C_INCLUDES += frameworks/base/include system/core/includeinclude $(BUILD_EXECUTABLE)include $(CLEAR_VARS)LOCAL_MODULE := nativeserverLOCAL_MODULE_TAGS := optionalLOCAL_SRC_FILES := mathinterface.cpp \server.cppLOCAL_SHARED_LIBRARIES := libutils libcutils libbinderLOCAL_C_INCLUDES += frameworks/base/include system/core/includeinclude $(BUILD_EXECUTABLE)

The interface:

/** * 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()");}

Client:

/** * 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;}

Server:

/** * 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 implements RPC, which has nothing to do with the specific language. Therefore, theoretically, based on Binder, native processes can communicate with Android Java applications. The most critical and troublesome point is how the client obtains the ibinder object of the service on the server side, but it is not impossible to obtain the objects at the Java layer through a series of methods such as JNI and classloader, in fact, the implementation of Java-layer APIS is also in this way. For details, refer to this article.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.