[Android] Binder all-in-all

发布时间:2023年12月17日

前言:

Binder 是一种 IPC 机制,使用共享内存实现进程间通讯,既可以传递消息,也可以传递创建在共享内存中的对象,而Binder本身就是用共享内存实现的,因此遵循Binder写法的类是可以实例化后在进程间传递的。

Binder在Android架构中有很重的地位,各个模块都在重度使用它,从代码可读性角度看,在为熟悉之前的可读性较差。从整体架构的角度看,在各个模块中通过IPC分离接口和实现有效地提高了扩展性。

写法:

1.定义接口

这个接口需要 Client/Bp 和 Server/Bn?都要遵循,Client需要关注有哪些消息类型,即enum值,Server需要关注虚函数,主要任务是根据消息中的enum值判断不同的业务类型,然后调用相应的虚函数。

这里有两个宏?DECLARE_META_INTERFACE 和?IMPLEMENT_META_INTERFACE , DECLARE 需要写在 INTERFACE 里面,IMPLEMENT 需要写在 INTERFACE 外面,其中会指定一个字符串,这个字符串就是服务的唯一标识。这个字符串在注册服务的时候再次使用(或者注册服务时重新自定义),因此可以把这个字符串定义成全局变量,或者可以通过 INTERFACE::getInterfaceDescriptor() 方法来获取这个字符串。

/*
 * IDemo.h
*/

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);
};
 
// This implementation macro would normally go in a cpp file
IMPLEMENT_META_INTERFACE(Demo, "com.my.Demo");
#define DECLARE_META_INTERFACE(INTERFACE)                               \
    static const android::String16 descriptor;                          \
    static android::sp<I##INTERFACE> asInterface(                       \
            const android::sp<android::IBinder>& obj);                  \
    virtual const android::String16& getInterfaceDescriptor() const;    \
    I##INTERFACE();                                                     \
    virtual ~I##INTERFACE();                                            \
#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \
    const android::String16 I##INTERFACE::descriptor(NAME);             \
    const android::String16&                                            \
            I##INTERFACE::getInterfaceDescriptor() const {              \
        return I##INTERFACE::descriptor;                                \
    }                                                                   \
    android::sp<I##INTERFACE> I##INTERFACE::asInterface(                \
            const android::sp<android::IBinder>& obj)                   \
    {                                                                   \
        android::sp<I##INTERFACE> intr;                                 \
        if (obj != NULL) {                                              \
            intr = static_cast<I##INTERFACE*>(                          \
                obj->queryLocalInterface(                               \
                        I##INTERFACE::descriptor).get());               \
            if (intr == NULL) {                                         \
                intr = new Bp##INTERFACE(obj);                          \
            }                                                           \
        }                                                               \
        return intr;                                                    \
    }                                                                   \
    I##INTERFACE::I##INTERFACE() { }                                    \
    I##INTERFACE::~I##INTERFACE() { }                                   \

2.服务端实现

服务端需要继承 BnInterface<INTERFACE_NAME>,当前例子里需要继承 BnInferface<IDemo> , BnInterface 有一个纯虚函数onTransact需要实现。

/*
 * BnDemo.hpp
*/

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) {
 
    data.checkInterface(this);
 
    switch(code) {
        case ALERT: {
            alert();
            return NO_ERROR;
        } break;
        case PUSH: {
            int32_t inData = data.readInt32();
            push(inData);
            return NO_ERROR;
        } break;
        case ADD: {
            int32_t inV1 = data.readInt32();
            int32_t inV2 = data.readInt32();
            int32_t sum = add(inV1, inV2);
            reply->writeInt32(sum);
            return NO_ERROR;
        } break;
        default:
            return BBinder::onTransact(code, data, reply, flags);
    }
}

如果不希望把业务代码和Binder架构代码混到一起,那么就再定义一个类来实现业务层。

/*
 * Demo.hpp
*/

class Demo : public BnDemo {
    virtual void push(int32_t data) {
        // Do something with the data the client pushed
    }
    virtual void alert() {
        // Handle the alert
    }
    virtual int32_t add(int32_t v1, int32_t v2) {
        return v1 + v2;
    }
};

3.客户端实现

客户端需要继承BpInterface<INTERFACE_NAME>,然后就可以通过 BpInterface 的 remote()->transact 来给 服务端发送消息了。那么如何和服务端关联起来呢?这些工作是Binder内部自行关联的,我们只需要在定义Client的时候指定如下接收 IBinder 入参的构造函数即可。

/*
*  BpDemo.hpp
*/

class BpDemo : public BpInterface<IDemo> {
    public:
        BpDemo(const sp<IBinder>& impl) : BpInterface<IDemo>(impl) { }
 
        virtual void push(int32_t push_data) {
            Parcel data, reply;
            data.writeInterfaceToken(IDemo::getInterfaceDescriptor());
            data.writeInt32(push_data);
            remote()->transact(PUSH, data, &reply);
        }
 
        virtual void alert() {
            Parcel data, reply;
            data.writeInterfaceToken(IDemo::getInterfaceDescriptor());
            remote()->transact(ALERT, data, &reply, IBinder::FLAG_ONEWAY);
        }
 
        virtual int32_t add(int32_t v1, int32_t v2) {
            Parcel data, reply;
            data.writeInterfaceToken(IDemo::getInterfaceDescriptor());
            data.writeInt32(v1);
            data.writeInt32(v2);
            remote()->transact(ADD, data, &reply);
 
            int32_t res;
            status_t status = reply.readInt32(&res);
            return res;
        }
};

4.如何使用

服务端注册服务给系统的服务管理器。

defaultServiceManager()->addService(String16("com.my.Demo"), new Demo());

客户端在系统的服务管理器中根据 标识字符串 查找相应的服务,把返回的值cast 为 INTERFACE 实例使用即可。

p<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("com.my.Demo"));
sp<IDemo> demo = interface_cast<IDemo>(binder);
 
demo->alert();
demo->push(65);
int32_t sum = demo->add(453, 827);

注意:这两个接口里的字符串互相匹配即可完成配对,不需要和 IMPLEMENT 宏里面的字符串匹配。那么IMPLEMENT 宏?里面的字符串有什么用???

5.代码阅读

服务端如何查找service的标识字符串?

代码中搜索 addService

客户端如何查找连接了哪个Binder服务端?

代码中搜索 getService

记住上面两点,能够快速定位客户端和服务端的关联关系。

参考:

https://ebixio.com/blog/2012/07/07/using-android-ipc-binders-from-native-code/

文章来源:https://blog.csdn.net/ykun089/article/details/135003133
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。