使用 C++ 在 android 中理解和实现本机 Binder
Posted
技术标签:
【中文标题】使用 C++ 在 android 中理解和实现本机 Binder【英文标题】:Understanding and implementing native Binders in android using C++ 【发布时间】:2015-11-04 12:57:42 【问题描述】:我想在android中使用Binders实现一个简单的IPC机制。为此,我在网上搜索,发现this。我编译了它,它在我的 Android 设备上运行良好。我试图通过在 AOSP 上搜索每个课程来全面了解该程序,但一切都变得更加困难和混乱。任何人都可以解释一下(只是高级),也许通过添加更多的 cmets,这样它也可以帮助一些未来的访问者。这是从那里获取的代码:
#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
覆盖onTransact
方法,客户端只需调用android.os.Binder#transact
方法
如果您需要“hello world”Binder 示例,请告诉我,我会尝试找到一些东西
@pskink:感谢您的帮助。我在很大程度上理解了上面的例子。如果您可以再提供一个这样的示例,例如您所说的“hello world”,那肯定会有所帮助。
它将是java,而不是c++,但它认为你想了解高级,而不是实现/语言细节?
@pskink 我正在尝试将自定义活页夹从一个活动发送到下一个活动,但有问题。我在意图中额外发送活页夹。然后我得到 Parcelable 额外。将活页夹转换为我的自定义活页夹类型会触发转换异常。然后我尝试以同样的方式发送一个 android.os.Binder。转换为 android.os.Binder 会触发相同的异常。然后我测试 instanceof 以发现它只是 instanceof IBinder。使用 transact 方法永远不会调用我的自定义 onTransact 方法。然而,我注意到 Messenger 能够发送进程间消息。我怎样才能使我的活页夹工作。
【参考方案1】:
我知道这有点晚了,但请查看 Gabriel Burca 关于 Android IPC 机制 here 的惊人解释。您可以从同一作者here 找到一个非常简单的 C++ 代码的工作示例。此外,它有明确的说明如何编译并将其添加到您的 AOSP 源代码中。干杯!
【讨论】:
以上是关于使用 C++ 在 android 中理解和实现本机 Binder的主要内容,如果未能解决你的问题,请参考以下文章
带有静态库的 Android Studio 中的本机 C++ 代码
从 Android 中的本机 c++ 文件调用本机 opencv
Android Studio:使用本机 C++ 代码发布签名的 Bundle 将永远运行
调试不适用于 Android Studio 的 C++/本机库模块(使用 Cmake)
Android 11 - 本机 C++ 库的 System.loadLibrary 需要 60 多秒,在 Android 10 及更低版本上运行速度非常快