• Android Binder通信机制学习(二)


    新人阿彡的Android多媒体学习之路

    🚄🚄🚄 第一章 Android Binder通信机制学习之Binder基本原理
    🚄🚄🚄 第二章 Android Binder通信机制学习之Binder基本架构
    🚄🚄🚄 第三章 Android Binder通信机制学习之ServiceManager流程分析
    🚄🚄🚄 第四章 Android Binder通信机制学习之addService服务注册流程

    0、前言

    主要参考:https://paul.pub/android-binder-driver/

    作为一名新步入Android领域的职场老鸟,奈何最近环境不好,整体越来越卷的大背景下,本老鸟又新进入Android开发这个领域,后续工作基本应该是主攻Android Framework层的开发,辅助Android Applicatios层的开发,在这里记录一下个人的学习之旅,一方面方便自己学习总结,另一方面也方便后续的查漏补缺。整体学习基于Android 12 版本的代码。

    1、Binder整体架构

    先来一张经典的Binder架构图
    在这里插入图片描述

    Binder机制从架构上大致可以分为三层:

    1. 驱动层,我们知道Android系统是基于Linux内核的,Binder驱动层则位于Linux内核中。Binder 驱动会将自己注册为一个misc device,并向上层提供一个dev/binder节点(此Binder节点并不会对应真实的硬件设备)。Binder驱动运行在内核态,提供了最底层的数据传递,对象标识,线程管理,调用过程控制等功能,是Binder实现跨进程通信的核心。
    2. Framework C++层,以驱动层为基础,Binder机制C++的封装实现。
    3. Framework Java层,Binder机制的Java层的封装实现,采用JNI调用复用C++层的实现。

    开发者可以在Framework之上利用Binder提供的机制来进行具体的业务逻辑开发。其实不仅仅是第三方开发者,Android系统中本身也包含了很多系统服务都是基于Binder框架开发的。既然是“进程间”通讯就至少牵涉到两个进程,Binder框架是典型的C/S架构。在下文中,我们把服务的请求方称之为Client,服务的实现方称之为Server。Client对于Server的请求会经由Binder框架由上至下传递到内核的Binder驱动中,请求中包含了Client将要调用的命令和参数。请求到了Binder驱动之后,在确定了服务的提供方之后,会再从下至上将请求传递给具体的服务。整个调用过程如下图所示:
    在这里插入图片描述

    2、Binder相关类继承关系

    这里以MediaPlayer为例子展示一下Binder相关的各个类之间的关系
    在这里插入图片描述

    3、IBinder类

    IBinder是负责binder通信机制的基类,它有两个子类——BpBinder和BBinder。BpBinder代表着proxy,而BBinder代表着service。

    transact函数

    virtual status_t transact(uint32_t code,
                              const Parcel& data,
                              Parcel* reply,
                              uint32_t flags = 0) = 0;
    
    • 1
    • 2
    • 3
    • 4

    这是个纯虚函数,它肩负着binder数据传输的重任,从函数的名字就可以看出其重要性,子类Bpbinder和BBinder负责它的具体实现。BpBinder的此函数负责传输数据,而BBinder的此函数是负责接收数据。关于此函数的参数的解释如下:

    • code:函数码值,每一个服务接口类中声明的虚函数都对应一个码值,proxy端通过将码值传递给service端,从而告知service端请求执行的函数。
    • data:Parcel是Android中的容器类,用于装载数据。每个Parcel都对应一块内存buffer,用于存放数据。data中保存的是执行函数所需要的参数,proxy端把数据打包传递到service端,service端按照顺序读取参数,然后传递给对应的函数去执行。
    • reply:指向Parcel对象的指针,和data不同的是,它是用来装载service执行函数后返回的结果。 proxy可以从此Parcel中读取service的返回值,比如service的函数执行完毕之后返回一个int值,那么就可以调用reply->readInt32()获得这个int值。
    • flags:表示函数是同步调用还是异步调用。默认是同步调用,如果需要异步调用,flags会被赋值为IBinder::FLAG_ONEWAY。同步调用是阻塞的,必须等待service执行完毕返回执行结果之后proxy的执行流才得以继续,否则执行函数调用的线程就一直处于wait状态。

    localBinder函数、remoteBinder函数

    /* 返回一个BBinder对象 */
    virtual BBinder* localBinder();
    /* 返回一个BpBinder对象 */
    virtual BpBinder* remoteBinder();
    
    • 1
    • 2
    • 3
    • 4

    默认的实现都是返回NULL。在BBinder中实现了localBinder,在BpBinder中实现了remoteBinder。所以,如果要区分一个IBinder对象是local binder还是remote binder,那么调用IBinder对象的上述两个函数,对结果进行check就可以知道了。如果localBinder返回非空,那么就是一个local binder,如果remoteBinder返回非空,那么就是一个remote binder。在binder通信中,究竟什么是local binder,什么是remote binder呢?首先,继承自IBinder类的对象,都是binder对象。BBinder因为生存在服务进程中,所以称之为local binder,而BpBinder所对应的实体在另外一个进程中,所以称之为remote binder。BpBinder和BBinder对应关系可以参见下图:
    在这里插入图片描述

    linkToDeath函数

    virtual status_t linkToDeath(const sp<DeathRecipient>& recipient,
                                 void* cookie = nullptr,
                                 uint32_t flags = 0) = 0;
    
    • 1
    • 2
    • 3

    这个函数是用来为BBinder注册死亡通知的。在客户端进程中,持有一个BpBinder,它对应着服务进程中的某个BBinder。如果服务进程crash了,那么BBinder也就不存在了,BpBinder就无法再和BBinder通信了。因为BBinder的死亡客户端是没法主动知道的,所以需要注册个死亡通知:当BBinder不存在了,死亡通知就会被派发,以便客户端进程能做一些善后的工作。这个函数只在BpBinder中实现了——很显然,BBinder不需要为自己注册死亡通知。 DeathRecipient是IBinder的一个内部类,它有一个纯虚函数的方法,需要用户自己去实现。

    4、IInterface类

    从抽象的角度来将,基类IBinder实现的是通信数据的传输。这些通信数据来自于顶层服务接口类,所以还需要为服务接口类IXXXService定义一个基类——IInterface。每一个服务接口类IXXXService都需要继承IInterface,IInterface.h中定义了一些和服务相关的变量和函数。 首先看看IInterface的定义:

    class IInterface : public virtual RefBase
    {
    public:
                IInterface();
                static sp<IBinder>  asBinder(const IInterface*);
                static sp<IBinder>  asBinder(const sp<IInterface>&);
    
    protected:
        virtual                     ~IInterface();
        virtual IBinder*            onAsBinder() = 0;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    IInterface类相对于IBinder而言,简单了许多。值得关注的是函数asBinder,它返回了一个IBinder的指针。asBinder函数内部实际上是调用的虚函数virtual IBinder * onAsBinder() = 0,由之前的“全家福”可知,这个纯虚函数是由子类BpInterface和BnInterface实现。由此可知,可以从一个IInterfcae获得一个IBinder对象。下面看看两个模板类的不同实现:

    // static
    sp<IBinder> IInterface::asBinder(const IInterface* iface)
    {
        if (iface == nullptr) return nullptr;
        return sp<IBinder>::fromExisting(const_cast<IInterface*>(iface)->onAsBinder());
    }
    
    // static
    sp<IBinder> IInterface::asBinder(const sp<IInterface>& iface)
    {
        if (iface == nullptr) return nullptr;
        return sp<IBinder>::fromExisting(iface->onAsBinder());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    template<typename INTERFACE>
    IBinder* BnInterface<INTERFACE>::onAsBinder()
    {
        return this;
    }
    
    template<typename INTERFACE>
    inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote)
        : BpRefBase(remote)
    {
    }
    
    template<typename INTERFACE>
    inline IBinder* BpInterface<INTERFACE>::onAsBinder()
    {
        return remote();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    BnInterfce的onAsBinder函数是直接返回的this指针,因为BnInterfce是由IBinder继承而来;BpInterface的onAsBinder函数调用基类BpRefBase的remote函数,返回BpRefBase内部的mRemote指针,这个指针指向的是IBinder对象,后面我们会讲到这个对象实际上是一个BpBinder对象。

    两个宏定义:DECLARE_META_INTERFACEIMPLEMENT_META_INTERFACE

    #define DECLARE_META_INTERFACE(INTERFACE)                                                         \
    public:                                                                                           \
        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();                                                                      \
        static bool setDefaultImpl(::android::sp<I##INTERFACE> impl);                                 \
        static const ::android::sp<I##INTERFACE>& getDefaultImpl();                                   \
                                                                                                      \
    private:                                                                                          \
        static ::android::sp<I##INTERFACE> default_impl;                                              \
                                                                                                      \
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    // Macro to be used by both IMPLEMENT_META_INTERFACE and IMPLEMENT_META_NESTED_INTERFACE
    #define DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE0(ITYPE, INAME, BPTYPE)                     \
        const ::android::String16& ITYPE::getInterfaceDescriptor() const { return ITYPE::descriptor; } \
        ::android::sp<ITYPE> ITYPE::asInterface(const ::android::sp<::android::IBinder>& obj) {        \
            ::android::sp<ITYPE> intr;                                                                 \
            if (obj != nullptr) {                                                                      \
                intr = ::android::sp<ITYPE>::cast(obj->queryLocalInterface(ITYPE::descriptor));        \
                if (intr == nullptr) {
                    /* 以 ServiceManager 为例子,这里创建的是BpServiceManager */                           \
                    intr = ::android::sp<BPTYPE>::make(obj);                                           \
                }                                                                                      \
            }                                                                                          \
            return intr;                                                                               \
        }                                                                                              \
        ::android::sp<ITYPE> ITYPE::default_impl;                                                      \
        bool ITYPE::setDefaultImpl(::android::sp<ITYPE> impl) {                                        \
            /* Only one user of this interface can use this function     */                            \
            /* at a time. This is a heuristic to detect if two different */                            \
            /* users in the same process use this function.              */                            \
            assert(!ITYPE::default_impl);                                                              \
            if (impl) {                                                                                \
                ITYPE::default_impl = std::move(impl);                                                 \
                return true;                                                                           \
            }                                                                                          \
            return false;                                                                              \
        }                                                                                              \
        const ::android::sp<ITYPE>& ITYPE::getDefaultImpl() { return ITYPE::default_impl; }            \
        ITYPE::INAME() {}                                                                              \
        ITYPE::~INAME() {}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    IMPLEMENT_META_INTERFACE宏最终调用的是DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE0宏的实现,这两个宏分别定义和实现了getInterfaceDescriptor函数以及asInterface函数,后面会使用到。

    queryLocalInterface函数
    以IMediaPlayerService为例子,IMediaPlayerService::asInterface这个函数首先会调用IBinder的queryLocalInterface函数检查IBinder的子类是否是一个本地service接口。在IBinder中提供了默认的实现:

    sp<IInterface>  IBinder::queryLocalInterface(const String16& /*descriptor*/)
    {
        return nullptr;
    }
    
    • 1
    • 2
    • 3
    • 4

    IBinder有两个子类:BpBinder和BBinder,BpBinder并没有对这个函数进行了重写,沿用了基类的默认实现方式。在BBinder的子类BnInterface中对这个函数进行了重写,在函数实现体中,如果检查传递的描述符字符串和自身的描述符相同,就返回this指针

    template<typename INTERFACE>
    inline sp<IInterface> BnInterface<INTERFACE>::queryLocalInterface(
            const String16& _descriptor)
    {
        if (_descriptor == INTERFACE::descriptor) return sp<IInterface>::fromExisting(this);
        return nullptr;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    所以对于IServiceManager::asInterface(const android::sp< android::IBinder >& obj)函数,如果形参IBinder引用obj指向的是一个BpBinder对象,那么obj->queryLocalInterface函数就返回NULL,需要以obj为参数构造一个BpServiceManager对象(继承自IServiceManager);如果形参IBinder引用obj指向的是一个BBinder对象,返回的就是this指针。因为BnInterface< IServiceManager >作为BBinder的子类的同时也是IServiceManager的子类。
    DECLARE_META_INTERFACE费劲心思声明的asInterface函数的作用是非常重要的,它可以直接从IBinder构造一个IServiceManager对象,从而屏蔽了这个对象究竟是本地service对象,还是一个remote代理对象。用户直接使用IServiceManager接口的指针就可以调用具体的函数实现,丝毫不用关心底层的实现细节。

    本章主要学习了一下IBinder类和IInterface这两个类,分别负责Binder通信中的数据传输以及接口封装。下一章我们将结合具体的流程来学习一下IBinder类对象以及IInterface类对象具体是如何发挥作用的。

    5、参考资料

    1、Android - Binder 和 Service(BpInterface和BnInterface研究)
    2、理解Android Binder机制(1/3):驱动篇
    3、Android Binder进程间通信机制

  • 相关阅读:
    传奇外网开服教程-GEE传奇外网全套架设教程
    国产智多晶FPGA基于Verilog的设计开发流程
    给网页添加背景音乐
    第一讲 react的基础---安装 特点 组件 生命周期
    程序媛过中秋的正确打开方式——使用Python绘制月饼消消乐,素描图,词云图,字符画图及提取轮廓
    浅入浅出 1.7和1.8的 HashMap
    知识库建设:从0到1搞定知识库建设的方法论分享
    安全:Linux重要安全配置之关闭常规ssh链接-开启密钥方式链接-防入侵非常重要以及有效的一项操作
    【智能家居入门2】(MQTT协议、微信小程序、STM32、ONENET云平台)
    PDU是什么?
  • 原文地址:https://blog.csdn.net/li_qinging/article/details/125005296