//检查数据是否有效
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() 方法中,此方法中主要做了三个工作:
-
准备 binder_write_read 数据
-
写入 binder 驱动
-
处理驱动回复
以此将 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 中取数据的逻辑。
上文介绍 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 就是 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) {
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
最后笔者收集整理了一份Flutter高级入门进阶资料PDF
以下是资料目录和内容部分截图
里面包括详细的知识点讲解分析,带你一个星期入门Flutter。还有130个进阶学习项目实战视频教程,让你秒变大前端。学不会来打我!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
[外链图片转存中…(img-gqksbs57-1710704200777)]
最后笔者收集整理了一份Flutter高级入门进阶资料PDF
以下是资料目录和内容部分截图
[外链图片转存中…(img-sGKl30Fa-1710704200778)]
[外链图片转存中…(img-5OHhcmP8-1710704200778)]
里面包括详细的知识点讲解分析,带你一个星期入门Flutter。还有130个进阶学习项目实战视频教程,让你秒变大前端。学不会来打我!
[外链图片转存中…(img-TRb3hkBQ-1710704200779)]
以上资料皆无偿分享,领取方式:点击我的GitHub即可免费获取