新人阿彡的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机制从架构上大致可以分为三层:
- 驱动层,我们知道Android系统是基于Linux内核的,Binder驱动层则位于Linux内核中。Binder 驱动会将自己注册为一个misc device,并向上层提供一个dev/binder节点(此Binder节点并不会对应真实的硬件设备)。Binder驱动运行在内核态,提供了最底层的数据传递,对象标识,线程管理,调用过程控制等功能,是Binder实现跨进程通信的核心。
- Framework C++层,以驱动层为基础,Binder机制C++的封装实现。
- 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>

最低0.47元/天 解锁文章
436

被折叠的 条评论
为什么被折叠?



