一 binder NDK接口使用
从android Q开始,binder添加了ndk使用的接口,相关使用接口示例如下:
iface.h
class IFoo : public virtual ::android::RefBase {
public:
static const char* kSomeInstanceName;
static const char* kInstanceNameToDieFor;
static AIBinder_Class* kClass;
// Takes ownership of IFoo
binder_status_t addService(const char* instance);
static ::android::sp getService(const char* instance, AIBinder** outBinder = nullptr);
enum Call {
DOFOO = FIRST_CALL_TRANSACTION + 0,
DIE = FIRST_CALL_TRANSACTION + 1,
};
virtual ~IFoo();
virtual binder_status_t doubleNumber(int32_t in, int32_t* out) = 0;
virtual binder_status_t die() = 0;
private:
// this variable is only when IFoo is local (since this test combines 'IFoo' and 'BnFoo'), not
// for BpFoo.
AIBinder_Weak* mWeakBinder = nullptr;
};
iface.cpp
truct IFoo_Class_Data {
sp foo;
};
void* IFoo_Class_onCreate(void* args) {
IFoo_Class_Data* foo = static_cast(args);
// This is a foo, but we're currently not verifying that. So, the method newLocalBinder is
// coupled with this.
return static_cast(foo);
}
void IFoo_Class_onDestroy(void* userData) {
delete static_cast(userData);
}
binder_status_t IFoo_Class_onTransact(AIBinder* binder, transaction_code_t code, const AParcel* in,
AParcel* out) {
binder_status_t stat = STATUS_FAILED_TRANSACTION;
sp foo = static_cast(AIBinder_getUserData(binder))->foo;
CHECK(foo != nullptr) << "Transaction made on already deleted object";
switch (code) {
case IFoo::DOFOO: {
int32_t valueIn;
int32_t valueOut;
stat = AParcel_readInt32(in, &valueIn);
if (stat != STATUS_OK) break;
stat = foo->doubleNumber(valueIn, &valueOut);
if (stat != STATUS_OK) break;
stat = AParcel_writeInt32(out, valueOut);
break;
}
case IFoo::DIE: {
stat = foo->die();
break;
}
}
return stat;
}
AIBinder_Class* IFoo::kClass = AIBinder_Class_define(kIFooDescriptor, IFoo_Class_onCreate,
IFoo_Class_onDestroy, IFoo_Class_onTransact);
class BpFoo : public IFoo {
public:
explicit BpFoo(AIBinder* binder) : mBinder(binder) {}
virtual ~BpFoo() { AIBinder_decStrong(mBinder); }
virtual binder_status_t doubleNumber(int32_t in, int32_t* out) {
binder_status_t stat = STATUS_OK;
AParcel* parcelIn;
stat = AIBinder_prepareTransaction(mBinder, &parcelIn);
if (stat != STATUS_OK) return stat;
stat = AParcel_writeInt32(parcelIn, in);
if (stat != STATUS_OK) return stat;
::ndk::ScopedAParcel parcelOut;
stat = AIBinder_transact(mBinder, IFoo::DOFOO, &parcelIn, parcelOut.getR(), 0 /*flags*/);
if (stat != STATUS_OK) return stat;
stat = AParcel_readInt32(parcelOut.get(), out);
if (stat != STATUS_OK) return stat;
return stat;
}
virtual binder_status_t die() {
binder_status_t stat = STATUS_OK;
AParcel* parcelIn;
stat = AIBinder_prepareTransaction(mBinder, &parcelIn);
::ndk::ScopedAParcel parcelOut;
stat = AIBinder_transact(mBinder, IFoo::DIE, &parcelIn, parcelOut.getR(), 0 /*flags*/);
return stat;
}
private:
// Always assumes one refcount
AIBinder* mBinder;
};
IFoo::~IFoo() {
AIBinder_Weak_delete(mWeakBinder);
}
binder_status_t IFoo::addService(const char* instance) {
AIBinder* binder = nullptr;
if (mWeakBinder != nullptr) {
// one strong ref count of binder
binder = AIBinder_Weak_promote(mWeakBinder);
}
if (binder == nullptr) {
// or one strong refcount here
binder = AIBinder_new(IFoo::kClass, static_cast(new IFoo_Class_Data{this}));
if (mWeakBinder != nullptr) {
AIBinder_Weak_delete(mWeakBinder);
}
mWeakBinder = AIBinder_Weak_new(binder);
}
binder_status_t status = AServiceManager_addService(binder, instance);
// Strong references we care about kept by remote process
AIBinder_decStrong(binder);
return status;
}
sp IFoo::getService(const char* instance, AIBinder** outBinder) {
AIBinder* binder = AServiceManager_getService(instance); // maybe nullptr
if (binder == nullptr) {
return nullptr;
}
if (!AIBinder_associateClass(binder, IFoo::kClass)) {
AIBinder_decStrong(binder);
return nullptr;
}
if (outBinder != nullptr) {
AIBinder_incStrong(binder);
*outBinder = binder;
}
if (AIBinder_isRemote(binder)) {
sp ret = new BpFoo(binder); // takes ownership of binder
return ret;
}
IFoo_Class_Data* data = static_cast(AIBinder_getUserData(binder));
CHECK(data != nullptr); // always created with non-null data
sp ret = data->foo;
AIBinder* held = AIBinder_Weak_promote(ret->mWeakBinder);
CHECK(held == binder);
AIBinder_decStrong(held);
AIBinder_decStrong(binder);
return ret;
}
使用
class MyTestFoo : public IFoo {
binder_status_t doubleNumber(int32_t in, int32_t* out) override {
*out = 2 * in;
LOG(INFO) << "doubleNumber (" << in << ") => " << *out;
return STATUS_OK;
}
binder_status_t die() override {
ADD_FAILURE() << "die called on local instance";
return STATUS_OK;
}
};
TEST(NdkBinder, GetServiceInProcess) {
static const char* kInstanceName = "test-get-service-in-process";
sp foo = new MyTestFoo;
EXPECT_EQ(STATUS_OK, foo->addService(kInstanceName));
sp getFoo = IFoo::getService(kInstanceName);
EXPECT_EQ(foo.get(), getFoo.get());
int32_t out;
EXPECT_EQ(STATUS_OK, getFoo->doubleNumber(1, &out));
EXPECT_EQ(2, out);
}
二 binder ndk引入的原因
为什么要引入binder ndk的接口呢? 答案很简单就是使用简单。像iface.h和iface.cpp 这两个文件完全可以通过aidl文件自动生成,接口使用简单,ABI稳定。谷歌相关的commit log
Initial C library for libbinder.
This creates a simple wrapper around libbinder with a stable C ABI. It
also embeds the concept of an IBinder and IBinder transactions into the
ABI so that parts of their transactions can be changed and considered
implementation details of libbinder. With this basic class, you can
create a service, use it with primitive data types, but it does not yet
suppport the entire range of binder objects.