掌握 binder 机制?先搞懂这几个关键类!

if (b) e->refs = b->getWeakRefs();

} else {

result = b;

e->refs->decWeak(this);

}

}

return result;

}

lookupHandleLocked() 方法用于查找本进程中是否已经创建过要获取的 IBinder,如果没有获取到,就创建一个,lookupHandleLocked() 内部通过一个 Vector 来存放创建过的 IBinder:

Vector<handle_entry> mHandleToObject;

struct handle_entry{

IBinder* binder;

RefBase::weakref_type* refs;

}

如上代码所示,每个 IBinder 对象通过一个 handle_entry 结构体存放,也就是说,ProcessState 中有一个全局列表来记录所有的 IBinder 对象。

IPCThreadState


ProcessState 对应于一个进程,是进程内单例,而 IPCThreadState 对应于一个线程,是线程单例(Thread Local)。

ProcessState 中打开了 binder 驱动、进行 mmap 映射,虽然调用了 ioctl() 函数,但主要是一些初始化配置。而具体的 BR_TRANSACTION 等命令都是由 IPCThreadState 负责执行的,当上层传来一个命令,会调用它的 transact 函数,该函数精简后如下:

status_t IPCThreadState::transact(int32_t handle,

uint32_t code, const Parcel& data,

Parcel* reply, uint32_t flags){

//检查数据是否有效

status_t err = data.errorCheck();

if (err == NO_ERROR) {

//将数据打包塞到 mOut 里

err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);

}

if ((flags & TF_ONE_WAY) == 0) { //不是 one way 调用,需要等待回复

if (reply) {

err = waitForResponse(reply);

} else {

Parcel fakeReply;

err = waitForResponse(&fakeReply);

}

} else { //one way 调用,不用等待回复

err = waitForResponse(NULL, NULL);

}

return err;

}

IPCThreadState 中有 mIn、mOut 两个 Parcel 数据,mIn 用来存放从别处读取而来的数据,mOut 存放要写入到别处的数据,在 writeTransactionData() 方法中将数据存放到 mOut,准备写入到 binder 驱动。

waitForResponse() 方法去实际执行写入到 binder 驱动,简化后的 waitForResponse() 方法如下:

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult){

uint32_t cmd;

int32_t err;

while (1) {

//进一步调用 talkWithDriver 去执行写入数据到 binder 驱动

if ((err=talkWithDriver()) < NO_ERROR) break;

err = mIn.errorCheck(); //检查数据有效性

if (err < NO_ERROR) break;

if (mIn.dataAvail() == 0) continue; //检查数据有效性

cmd = (uint32_t)mIn.readInt32(); //拿到 binder 驱动发过来的命令

switch (cmd) {

//处理命令

case BR_TRANSACTION_COMPLETE:{…}

case BR_DEAD_REPLY:{…}

case BR_FAILED_REPLY:{…}

case BR_ACQUIRE_RESULT:{…}

case BR_REPLY:{…}

default:

//其他命令在 executeCommand 方法中处理

err = executeCommand(cmd);

if (err != NO_ERROR) goto finish;

break;

}

}

return err;

}

可以看到 waitForResponse() 中并没有直接执行写入数据到 binder,而是进一步调用 talkWithDriver 去处理,随后 waitForResponse() 方法处理了由 binder 驱动发送过来的命令,比如 BR_TRANSACTION_COMPLETE :

case BR_TRANSACTION_COMPLETE:

if (!reply && !acquireResult) goto finish;

break;

在 transact() 方法中判断如果是 one way 调用,reply 及 acquireResult 都传入 NULL,所以上面条件成立,直接退出循环,不用再等待 binder 驱动的回复。

到目前为止,由 transact() 到 waitForResponse(),已经将要发送的数据准备好,并对后续 binder 驱动的回复也做了处理,但还没看到真正写入数据给 binder 驱动的代码,但已经知道就在 talkWithDriver() 方法中,此方法中主要做了三个工作:

  1. 准备 binder_write_read 数据

  2. 写入 binder 驱动

  3. 处理驱动回复

以此将 talkWithDriver() 代码简化分为对应的三部分来看,首先是准备 binder_write_read 数据:

status_t IPCThreadState::talkWithDriver(bool doReceive){

binder_write_read bwr; //binder 驱动接受的数据格式

const bool needRead = mIn.dataPosition() >= mIn.dataSize();

const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;

bwr.write_size = outAvail; //要写入的数据量

bwr.write_buffer = (uintptr_t)mOut.data(); //要写入的数据

// This is what we’ll read.

if (doReceive && needRead) {

bwr.read_size = mIn.dataCapacity(); //要读取的数据量

bwr.read_buffer = (uintptr_t)mIn.data(); //存放读取数据的内存空间

} else {

bwr.read_size = 0;

bwr.read_buffer = 0;

}

// 如果不需要读也不需要写,那就直接返回

if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;

在 IPCThreadState.h 中声明了 talkWithDriver() 方法的参数 doReceive 默认为 true,waitForResponse() 中没有传入参数,所以这里的 doReceive 为 true。

binder_write_read 是 binder 驱动与用户态共用的、存储读写操作的数据,在 binder 驱动内部依赖 binder_write_read 决定是要读取还是写入数据:其内部变量 read_size>0 则代表要读取数据,write_size>0 代表要写入数据,若都大于 0 则先写入,后读取。

准备好 binder_write_read 后,再来看是怎么写入 binder 驱动的,其实很简单,真正执行写入的操作就一行代码:

ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)

对应的会调用到 binder 驱动的 binder_ioctl() 函数,这里不延伸此函数,接着看 talkWithDriver() 方法的第三个工作,处理驱动的回复:

if (bwr.write_consumed > 0) { //成功写入了数据

if (bwr.write_consumed < mOut.dataSize())

mOut.remove(0, bwr.write_consumed);

else

mOut.setDataSize(0);

}

if (bwr.read_consumed > 0) { //成功读取到了数据

mIn.setDataSize(bwr.read_consumed);

mIn.setDataPosition(0);

}

return NO_ERROR;

}

bwr.write_consumed > 0 代表 binder 驱动消耗了 mOut 中的数据,所以要把这部分已经处理过的数据移除调;bwr.read_consumed > 0 代表 binder 驱动成功的返回了数据给我们,并写入了上面通过 bwr.read_buffer 指定的内存地址,即 mIn 中,所以要对 mIn 对相关的修正。

到这里 talkWithDriver 执行完毕,读取到的数据放到了 mIn 中,也正好对应于上面 waitForResponse() 方法中从 mIn 中取数据的逻辑。

BpBinder


上文介绍 ProcessState 中的 getWeakProxyForHandle() 方法时,构造了一个 BpBinder 对象返回:

new BpBinder(handle)

IPCThreadState 作为主要与 binder 驱动交互的对象,它的 transact 方法第一个参数就是 handle 值:

status_t IPCThreadState::transact(int32_t handle,

uint32_t code, const Parcel& data,

Parcel* reply, uint32_t flags)

注意这两个线索:一是将 handle 交给 BpBinder 持有,二是在调用 IPCThreadState transact 方法时需要传入 handle,这意味着什么呢?一个 BpBinder 对象就是关联了一个远程 handle 的操作封装,其内部是通过 IPCThreadState 来实现的 。但这个仅是猜想,下面通过 BpBinder 源码来验证是否属实,首先是构造函数:

BpBinder::BpBinder(int32_t handle)
mHandle(handle)

, mAlive(1)

, mObitsSent(0)

, mObituaries(NULL)

ALOGV(“Creating BpBinder %p handle %d\n”, this, mHandle);

extendObjectLifetime(OBJECT_LIFETIME_WEAK);

IPCThreadState::self()->incWeakHandle(handle);

}

智能指针的 OBJECT_LIFETIME_WEAK 配置,代表 BpBinder 对象的强计数器和弱计数器的值都为 0 时才会被销毁。另外可以看到通过内部变量 mHandle 持有 handle 值,在 BpBinder 的 transact 方法中使用了 mHandle:

status_t BpBinder::transact(

uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){

if (mAlive) {

status_t status = IPCThreadState::self()->transact(

mHandle, code, data, reply, flags);

if (status == DEAD_OBJECT) mAlive = 0;

return status;

}

return DEAD_OBJECT;

}

其内部确实是调用了 IPCThreadState 的 transact 方法,这便验证了 一个 BpBinder 对象就是关联了一个远程 handle 的操作封装,其内部是通过 IPCThreadState 来实现的 的描述是正确的。

BinderProxy


先给出结论:BinderProxy 就是 BpBinder,“BpBinder” 中的 “p” 即 Proxy,只不过 BpBinder 是 Native 层的,BinderProxy 是 Java 层的。BinderProxy 和 BpBinder 分别继承自 Java 和 Native 层的 IBinder 接口,即 IBinder.h 和 IBinder.java,它们可以看作同一个接口,都定义了 transact 等方法。

下面根据源码来验证这个结论,ServiceManager.java 中获取 Service Manager 的代码如下:

private static IServiceManager getIServiceManager() {

if (sServiceManager != null) {

return sServiceManager;

}

// Find the service manager

sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());

return sServiceManager;

}

其中 asInterface 方法接收的参数就是一个 IBinder 类型对象,可想而知,BinderInternal 的 getContextObject() 方法返回的是一个 BinderProxy 对象:

/**

  • Return the global “context object” of the system. This is usually

  • an implementation of IServiceManager, which you can use to find

  • other services.

*/

public static final native IBinder getContextObject();

这里保留了注释,为什么将 Service Manager 命名为 Context Object 呢?因为每个进程都需要 IPC 操作,IPC 是作为进程的基础配置存在的。上面代码的注释更直接的描述了此方法,有助于我们理解。

接着看这个方法,对应的 native 实现在 android_util_Binder.cpp 中:

static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz){

sp b = ProcessState::self()->getContextObject(NULL);

return javaObjectForIBinder(env, b);

}

ProcessState 的 getContextObject() 方法如下:

《设计思想解读开源框架》

第一章、 热修复设计

  • 第一节、 AOT/JIT & dexopt 与 dex2oat

  • 第二节、 热修复设计之 CLASS_ISPREVERIFIED 问题

  • 第三节、热修复设计之热修复原理

  • 第四节、Tinker 的集成与使用(自动补丁包生成)

    第二章、 插件化框架设计

  • 第一节、 Class 文件与 Dex 文件的结构解读

  • 第二节、 Android 资源加载机制详解

  • 第三节、 四大组件调用原理

  • 第四节、 so 文件加载机制

  • 第五节、 Android 系统服务实现原理

    第三章、 组件化框架设计

  • 第一节、阿里巴巴开源路由框——ARouter 原理分析

  • 第二节、APT 编译时期自动生成代码&动态类加载

  • 第三节、 Java SPI 机制

  • 第四节、 AOP&IOC

  • 第五节、 手写组件化架构

    第四章、图片加载框架

  • 第一节、图片加载框架选型

  • 第二节、Glide 原理分析

  • 第三节、手写图片加载框架实战

    第五章、网络访问框架设计

  • 第一节、网络通信必备基础

  • 第二节、OkHttp 源码解读

  • 第三节、Retrofit 源码解析

    第六章、 RXJava 响应式编程框架设计

  • 第一节、链式调用

  • 第二节、 扩展的观察者模式

  • 第三节、事件变换设计

  • 第四节、Scheduler 线程控制

    第七章、 IOC 架构设计

  • 第一节、 依赖注入与控制反转

  • 第二节、ButterKnife 原理上篇、中篇、下篇

  • 第三节、Dagger 架构设计核心解密

    第八章、 Android 架构组件 Jetpack

  • 第一节、 LiveData 原理

  • 第二节、 Navigation 如何解决 tabLayout 问题

  • 第三节、 ViewModel 如何感知 View 生命周期及内核原理

  • 第四节、 Room 架构方式方法

  • 第五节、 dataBinding 为什么能够支持 MVVM

  • 第六节、 WorkManager 内核揭秘

  • 第七节、 Lifecycles 生命周期


    本文包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…

    《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!
    与控制反转**

  • 第二节、ButterKnife 原理上篇、中篇、下篇

  • 第三节、Dagger 架构设计核心解密

    [外链图片转存中…(img-M9ZCHj1x-1715315577283)]

    第八章、 Android 架构组件 Jetpack

  • 第一节、 LiveData 原理

  • 第二节、 Navigation 如何解决 tabLayout 问题

  • 第三节、 ViewModel 如何感知 View 生命周期及内核原理

  • 第四节、 Room 架构方式方法

  • 第五节、 dataBinding 为什么能够支持 MVVM

  • 第六节、 WorkManager 内核揭秘

  • 第七节、 Lifecycles 生命周期

    [外链图片转存中…(img-UfdyXYAc-1715315577284)]
    本文包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…
    [外链图片转存中…(img-7f69sU9i-1715315577284)]
    《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

  • 10
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值