在Android中使用C++理解和实现本机Binder

3
我希望使用Android中的Binders来实现一个简单的IPC机制。为此,我在互联网上搜索并找到了这个。我编译它并在我的Android设备上运行良好。我试图通过在AOSP上搜索每个类来对程序有一个总体的理解,但是一切变得更加困难和混乱。请问有人能够解释一下(仅限高层次),或者添加更多注释,以便也能帮助一些未来的访问者。以下代码取自那里:
#define LOG_TAG "binder_demo"

#include <stdlib.h>
#include "utils/RefBase.h"
#include "utils/Log.h"
#include "utils/TextOutput.h"
#include <binder/IInterface.h>
#include <binder/IBinder.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
using namespace android;
#define INFO(...) \
    do { \
        printf(__VA_ARGS__); \
        printf("\n"); \
        LOGD(__VA_ARGS__); \
    } while(0)
void assert_fail(const char *file, int line, const char *func, const char *expr) {
    INFO("assertion failed at file %s, line %d, function %s:",
            file, line, func);
    INFO("%s", expr);
    abort();
}
#define ASSERT(e) \
    do { \
        if (!(e)) \
        assert_fail(__FILE__, __LINE__, __func__, #e); \
    } while(0)
// Where to print the parcel contents: aout, alog, aerr. alog doesn't seem to work.
#define PLOG aout
// Interface (our AIDL) - Shared by server and client
class IDemo : public IInterface {
    public:
        enum {
            ALERT = IBinder::FIRST_CALL_TRANSACTION,
            PUSH,
            ADD
        };
        // Sends a user-provided value to the service
        virtual void push(int32_t data) = 0;
        // Sends a fixed alert string to the service
        virtual void alert() = 0;
        // Requests the service to perform an addition and return the result
        virtual int32_t add(int32_t v1, int32_t v2) = 0;
        DECLARE_META_INTERFACE(Demo); // Expands to 5 lines below:
        //static const android::String16 descriptor;
        //static android::sp<IDemo> asInterface(const android::sp<android::IBinder>& obj);
        //virtual const android::String16& getInterfaceDescriptor() const;
        //IDemo();
        //virtual ~IDemo();
};
// Client
class BpDemo : public BpInterface<IDemo> {
    public:
        BpDemo(const sp<IBinder>& impl) : BpInterface<IDemo>(impl) {
            LOGD("BpDemo::BpDemo()");
        }
        virtual void push(int32_t push_data) {
            Parcel data, reply;
            data.writeInterfaceToken(IDemo::getInterfaceDescriptor());
            data.writeInt32(push_data);
            aout << "BpDemo::push parcel to be sent:\n";
            data.print(PLOG); endl(PLOG);
            remote()->transact(PUSH, data, &reply);
            aout << "BpDemo::push parcel reply:\n";
            reply.print(PLOG); endl(PLOG);
            LOGD("BpDemo::push(%i)", push_data);
        }
        virtual void alert() {
            Parcel data, reply;
            data.writeInterfaceToken(IDemo::getInterfaceDescriptor());
            data.writeString16(String16("The alert string"));
            remote()->transact(ALERT, data, &reply, IBinder::FLAG_ONEWAY); // asynchronous call
            LOGD("BpDemo::alert()");
        }
        virtual int32_t add(int32_t v1, int32_t v2) {
            Parcel data, reply;
            data.writeInterfaceToken(IDemo::getInterfaceDescriptor());
            data.writeInt32(v1);
            data.writeInt32(v2);
            aout << "BpDemo::add parcel to be sent:\n";
            data.print(PLOG); endl(PLOG);
            remote()->transact(ADD, data, &reply);
            LOGD("BpDemo::add transact reply");
            reply.print(PLOG); endl(PLOG);
            int32_t res;
            status_t status = reply.readInt32(&res);
            LOGD("BpDemo::add(%i, %i) = %i (status: %i)", v1, v2, res, status);
            return res;
        }
};
//IMPLEMENT_META_INTERFACE(Demo, "Demo");
// Macro above expands to code below. Doing it by hand so we can log ctor and destructor calls.
const android::String16 IDemo::descriptor("Demo");
const android::String16& IDemo::getInterfaceDescriptor() const {
    return IDemo::descriptor;
}
android::sp<IDemo> IDemo::asInterface(const android::sp<android::IBinder>& obj) {
    android::sp<IDemo> intr;
    if (obj != NULL) {
        intr = static_cast<IDemo*>(obj->queryLocalInterface(IDemo::descriptor).get());
        if (intr == NULL) {
            intr = new BpDemo(obj);
        }
    }
    return intr;
}
IDemo::IDemo() { LOGD("IDemo::IDemo()"); }
IDemo::~IDemo() { LOGD("IDemo::~IDemo()"); }
// End of macro expansion
// Server
class BnDemo : public BnInterface<IDemo> {
    virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
};
status_t BnDemo::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
    LOGD("BnDemo::onTransact(%i) %i", code, flags);
    data.checkInterface(this);
    data.print(PLOG); endl(PLOG);
    switch(code) {
        case ALERT: {
                        alert(); // Ignoring the fixed alert string
                        return NO_ERROR;
                    } break;
        case PUSH: {
                       int32_t inData = data.readInt32();
                       LOGD("BnDemo::onTransact got %i", inData);
                       push(inData);
                       ASSERT(reply != 0);
                       reply->print(PLOG); endl(PLOG);
                       return NO_ERROR;
                   } break;
        case ADD: {
                      int32_t inV1 = data.readInt32();
                      int32_t inV2 = data.readInt32();
                      int32_t sum = add(inV1, inV2);
                      LOGD("BnDemo::onTransact add(%i, %i) = %i", inV1, inV2, sum);
                      ASSERT(reply != 0);
                      reply->print(PLOG); endl(PLOG);
                      reply->writeInt32(sum);
                      return NO_ERROR;
                  } break;
        default:
                  return BBinder::onTransact(code, data, reply, flags);
    }
}
class Demo : public BnDemo {
    virtual void push(int32_t data) {
        INFO("Demo::push(%i)", data);
    }
    virtual void alert() {
        INFO("Demo::alert()");
    }
    virtual int32_t add(int32_t v1, int32_t v2) {
        INFO("Demo::add(%i, %i)", v1, v2);
        return v1 + v2;
    }
};
// Helper function to get a hold of the "Demo" service.
sp<IDemo> getDemoServ() {
    sp<IServiceManager> sm = defaultServiceManager();
    ASSERT(sm != 0);
    sp<IBinder> binder = sm->getService(String16("Demo"));
    // TODO: If the "Demo" service is not running, getService times out and binder == 0.
    ASSERT(binder != 0);
    sp<IDemo> demo = interface_cast<IDemo>(binder);
    ASSERT(demo != 0);
    return demo;
}
int main(int argc, char **argv) {
    if (argc == 1) {
        LOGD("We're the service");
        defaultServiceManager()->addService(String16("Demo"), new Demo());
        android::ProcessState::self()->startThreadPool();
        LOGD("Demo service is now ready");
        IPCThreadState::self()->joinThreadPool();
        LOGD("Demo service thread joined");
    } else if (argc == 2) {
        INFO("We're the client: %s", argv[1]);
        int v = atoi(argv[1]);
        sp<IDemo> demo = getDemoServ();
        demo->alert();
        demo->push(v);
        const int32_t adder = 5;
        int32_t sum = demo->add(v, adder);
        LOGD("Addition result: %i + %i = %i", v, adder, sum);
    }
    return 0;
}

在Java中,android.os.IBinder接口定义了如何处理可远程对象,唯一的实现是android.os.Binder。典型情况是一个Service返回一个自定义的android.os.Binder,该Binder覆盖了onTransact方法,客户端只需调用android.os.Binder#transact方法即可。 - pskink
如果你需要“hello world” Binder的例子,只要告诉我,我会尽量找到一些。 - pskink
@pskink:感谢您的帮助。我已经在很大程度上理解了上面的例子。如果您能再提供一个类似于“hello world”的例子,那肯定会很有帮助。 - Naveen
它将使用Java而不是C++,但我认为您想了解高层次的内容,而不是实现/语言细节? - pskink
检查哪些资源?我需要知道为什么我的自定义onTransact方法没有被调用。我在一个进程中调用transact,在另一个进程中没有收到onTransact调用。我需要做一些特殊的初始化吗?我只想直接使用我的绑定器,忘记AIDL和Messenger。 - user9599745
显示剩余13条评论
1个回答

3
我知道有点晚了,但请查看Gabriel Burca提供的关于Android进程间通信机制的精彩讲解,链接在这里。同一位作者还提供了一个非常简单的C++代码示例,链接在这里。此外,它还有明确的说明如何编译并将其添加到您的AOSP源码中。干杯!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接