【问题标题】:Send custom object using Android native Binder使用 Android 原生 Binder 发送自定义对象
【发布时间】:2016-08-05 17:20:05
【问题描述】:

我只能找到有关 Parcelable 的 Java 示例。 我的目标是在原生 C++(不是 NDK)中创建一个简单的服务和客户端,它将使用 Binder 来接收和发送序列化的自定义对象。

MyClass
+ std::string
+ enum
+ int
+ bool

【问题讨论】:

  • 如果没有 NDK,你会介意什么?是否允许使用JNI?
  • 看来 Parcelable.h 接口可用于 Android 6.0 及更高版本,我使用的是 5.1。
  • 我认为没有办法让 C++ 代码在没有 NDK 的情况下在 android 中工作。它是用于使代码工作的工具链/交叉编译器。它还包括(几乎总是需要的)stl。

标签: android c++ android-ndk java-native-interface android-binder


【解决方案1】:

由于您使用的是 Android 5.1,因此我将坚持使用 Lollipop 上可用的内容。有更好的工具,如 aidl-cpp 来完成此任务,从而节省了大量手动滚动样板代码的麻烦。

首先,为IFooService.h 中的服务制作接口。

class IFooService: public IInterface {
    public:
        DECLARE_META_INTERFACE(FooService);
        virtual int myFunc(const String8& str, int enumParam, int intParam, int boolParam) = 0;

};

然后为服务编写编组代码,按照问题中的要求实现一个功能

class BnFooService: public BnInterface<IFooService>
{
public:
    virtual status_t    onTransact( uint32_t code,
                                    const Parcel& data,
                                    Parcel* reply,
                                    uint32_t flags = 0);
};

enum {
    MY_FUNC = IBinder::FIRST_CALL_TRANSACTION,
};

/* BinderProxy code, for clients of the service to call into the service and have
   the paremeters marshalled properly across the Binder interface. Executes in the
   client process context
 
*/
class BpFooService: public BpInterface<IFooService> {
public:
    virtual int myFunc(const String8& str, int enumParam, int intParam, int boolParam) {
        //2 Parcel objects, 1 to write the data to and another to receive it in
        Parcel data, reply;
        //This serves as the token for the Binder framework for a sanity check
        data.writeInterfaceToken(IFooService::getInterfaceDescriptor());
        data.writeString8(str);
        data.writeInt32(enumParam);
        data.writeInt32(intParam);
        data.writeInt32(boolParam);
        return remote()->transact(MY_FUNC, data, &reply);
    }
}

IMPLEMENT_META_INTERFACE(MediaPlayerService, "com.somedomain.IFooService");

/* Actual Binder implementation of the service which unpacks the data from the
   incoming Parcel and handles the call accordingly     
*/
status_t BnFooService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
    switch (code) {
        case MY_FUNC: {
            //The same token is checked
            CHECK_INTERFACE(IFooService, data, reply);
            //Read off in exact same order as written to the data Parcel above
            String8 str = data.readString8();
            int enumParam = data.readInt32();
            int intParam = data.readInt32();
            int boolParam = data.readInt32();
            reply->writeInt32(myFunc(str, enumParam, intParam, boolParam));
            return NO_ERROR;
        }
        break;
    default:
        
}

然后使用如下代码创建main_foo.cpp,作为服务进程的入口点:

int main() {
    if(!FooService::publish()) { //Call into your code to register with ServiceManager
        ALOGE("Can't instantiate FooService! Exiting");
        return 1;
    }
    ProcessState::self()->startThreadPool(); //Required for the binder threads
    IPCThreadState::self()->joinThreadPool(); //Infinite loop that waits for inbound connections
}

最后,实现FooService.cpp中的服务接口

bool FooService::publish() {
    defaultServiceManager()->addService(String16("foo_service"), new FooService());
    sp<IBinder> binder = defaultServiceManager()->checkService(String16("foo_service"));
    while(binder == NULL && /*some upper time limit*/){
        ALOGI("Waiting for foo_service");
    }
    return binder != NULL;
}

int FooService::myFunc(const String8& str, int enumParam, int intParam, int boolParam) {
    //business logic
    return 0;
}

请注意,这不是适用于普通应用程序开发人员的代码,而是适用于在 Android 框架中运行的原生服务,例如 @987654329 @、SurfaceFlinger 等。此代码需要框架头文件,如 Parcel.hIInterface.h 等,这些文件在 SDK 中不可用。

【讨论】:

    猜你喜欢
    • 2015-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-14
    • 2014-11-14
    • 1970-01-01
    相关资源
    最近更新 更多