Binder NDK接口介绍

一 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<IFoo> 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<IFoo> foo;
};

void* IFoo_Class_onCreate(void* args) {
    IFoo_Class_Data* foo = static_cast<IFoo_Class_Data*>(args);
    // This is a foo, but we're currently not verifying that. So, the method newLocalBinder is
    // coupled with this.
    return static_cast<void*>(foo);
}

void IFoo_Class_onDestroy(void* userData) {
    delete static_cast<IFoo_Class_Data*>(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<IFoo> foo = static_cast<IFoo_Class_Data*>(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<void*>(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> 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<IFoo> ret = new BpFoo(binder);  // takes ownership of binder
        return ret;
    }

    IFoo_Class_Data* data = static_cast<IFoo_Class_Data*>(AIBinder_getUserData(binder));

    CHECK(data != nullptr);  // always created with non-null data

    sp<IFoo> 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<IFoo> foo = new MyTestFoo;
    EXPECT_EQ(STATUS_OK, foo->addService(kInstanceName));

    sp<IFoo> 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.
    原文作者:Little熊猫
    原文地址: https://www.jianshu.com/p/17ed1dd6712a
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞