Android Binder通信机制学习(二)

4 篇文章 1 订阅
4 篇文章 0 订阅

新人阿彡的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;

这是个纯虚函数,它肩负着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();

默认的实现都是返回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;

这个函数是用来为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;
};

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());
}
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();
}

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;                                              \
                                                                                                  \
// 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() {}

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;
}

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;
}

所以对于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进程间通信机制

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值