Native层
android_os_BinderProxy_transact
//frameworks/base/core/jni/android_util_Binder.cpp
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj, jobject replyObj, jint flags)
{
…
//java Parcel转为native Parcel
Parcel* data = parcelForJavaObject(env, dataObj);
Parcel* reply = parcelForJavaObject(env, replyObj);
…
//gBinderProxyOffsets.mObject中保存的是new BpBinder(0)对象
IBinder* target = (IBinder*)
env->GetLongField(obj, gBinderProxyOffsets.mObject);
…
//此处便是BpBinder::transact(), 经过native层
status_t err = target->transact(code, *data, reply, flags);
…
return JNI_FALSE;
}
最终调用BpBinder.transact
的方法来进行
BpBinder.transact
//frameworks/native/libs/binder/BpBinder.cpp
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。在上一篇文章中,也出现了这个IPCThreadState。这也是个单例模式,每个线程只有一个哦。
到这里接下来的事情基本上和上一篇中的如出一辙,我这里大概过一下把~
IPC.transact
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
status_t err = data.errorCheck(); //数据错误检查
flags |= TF_ACCEPT_FDS;
…
if (err == NO_ERROR) {
// 传输数据
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
}
if (err != NO_ERROR) {
if (reply) reply->setError(err);
return (mLastError = err);
}
// 默认情况下,都是采用非oneway的方式, 也就是需要等待服务端的返回结果
if ((flags & TF_ONE_WAY) == 0) {
if (reply) {
//reply对象不为空
err = waitForResponse(reply);
}else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
} else {
err = waitForResponse(NULL, NULL);
}
return err;
}
transact主要过程:
- 先执行
writeTransactionData()
向Parcel
数据类型的mOut
写入数据,此时mIn
还没有数据; - 然后执行
waitForResponse()
方法,循环执行,直到收到应答消息. 在waitForResponse
()方法中会调用talkWithDriver()
跟驱动交互,收到应答消息,便会写入mIn
, 则根据收到的不同响应吗,执行相应的操作。
上一篇文章中也将到过,这里再说一次~
mIn
用来接收来自Binder设备的数据,默认大小为256字节;mOut
用来存储发往Binder设备的数据,默认大小为256字节。
IPC.talkWithDriver
//frameworks/native/libs/binder/IPCThreadState.cpp
status_t IPCThreadState::waitForResponse(Parcel reply, status_t acquireResult)
{
int32_t cmd;
int32_t err;
while (1) {
//此处是真正的与内核交互的方法
if ((err=talkWithDriver()) < NO_ERROR) break;
…
cmd = mIn.readInt32();
switch (cmd) {
case BR_REPLY:
{
binder_transaction_data tr;
err = mIn.read(&tr, sizeof(tr));
if (reply) {
if ((tr.flags & TF_STATUS_CODE) == 0) {
//当reply对象回收时,则会调用freeBuffer来回收内存
reply->ipcSetDataReference(
reinterpret_cast<const uint8_t>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t),
freeBuffer, this);
} else {
…
}
}
}
case :…
}
}
…
return err;
}
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
…
//和Binder驱动通信的结构体
binder_write_read bwr;
//mIn是否有可读的数据,接收的数据存储在mIn
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;
//将要发送给Binder设备的消息填充到与Binder通信的结构体中
bwr.write_buffer = (uintptr_t)mOut.data();
if (doReceive && needRead) {
//接收数据缓冲区信息的填充。如果以后收到数据,就直接填在mIn中了。
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;
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
//通过ioctl不停的读写操作,跟Binder Driver进行通信
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
…
} while (err == -EINTR); //当被中断,则继续执行
…
return err;
}
接下来会通过ioctl方法于Binder驱动进行交互,这个交互的调用链是如下
进入驱动。binder_ioctl -> binder_ioctl_write_read -> binder_thread_write,最终会将命令和数据插入到ServiceManager
的todo队列中。 这个的叙述可以参考上一篇的内容。
那么接下来ServiceManager
在不断地从队列中取事务并处理,当service manager
进程收到该命令后,会执行do_find_service() 查询服务所对应的handle,然后再binder_send_reply()
应答 发起者,发送BC_REPLY协议,然后调用binder_transaction()
,再向服务请求者的Todo队列 插入事务。接下来,请求服务的进程在执行talkWithDriver
的过程执行到binder_thread_read()
,处理Todo队列的事务.(这部分不明白的小伙伴一定要看我上一篇文章)。
在waitForResponse
方法中,收到消息以后这个reply
就不为空,此时会进入reply的ipcSetDataReference
方法中,由于这个reply是Parcel对象,其实就是调用了Parcel的ipcSetDataReference
方法将ServiceManager
返回过来的数据设置到parcel对象中。waitForResponse()
执行完BR_REPLY之后,便返回到IPCThreadState::transact()
中;然后层层返回,直到退回到Java层的ServiceManagerProxy.getService
方法,然后调用reply的readStrongBinder
方法,最终调用的Native的方法nativeReadStrongBinder
()方法。
nativeReadStrongBinder
static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr) {
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
return javaObjectForIBinder(env, parcel->readStrongBinder());
}
return NULL;
}
Parcel::readStrongBinder
sp Parcel::readStrongBinder() const
{
sp val;
unflatten_binder(ProcessState::self(), *this, &val);
return val;
}
readStrongBinder()
会调用unflatten_binder()
来解析Parcel中的数据。
Parcel.unflatten_binder
status_t unflatten_binder(const sp& proc,
const Parcel& in, sp* out)
{
const flat_binder_object* flat = in.readObject(false);
if (flat) {
switch (flat->type) {
case BINDER_TYPE_BINDER:
out = reinterpret_cast<IBinder>(flat->cookie);
return finish_unflatten_binder(NULL, *flat, in);
case BINDER_TYPE_HANDLE:
//进入该分支
out = proc->getStrongProxyForHandle(flat->handle);
//创建BpBinder对象
return finish_unflatten_binder(
static_cast<BpBinder>(out->get()), *flat, in);
}
}
return BAD_TYPE;
}
ProcessState.getStrongProxyForHandle
sp ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp result;
AutoMutex _l(mLock);
//查找handle对应的资源项
handle_entry* e = lookupHandleLocked(handle);
if (e != NULL) {
IBinder* b = e->binder;
if (b == NULL || !e->refs->attemptIncWeak(this)) {
…
//当handle值所对应的IBinder不存在或弱引用无效时,则创建BpBinder对象
b = new BpBinder(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
result.force_set(b);
e->refs->decWeak(this);
}
}
return result;
}
经过该方法,最终创建了指向Binder服务端的BpBinder
代理对象。经过javaObjectForIBinder
方法将native层BpBinder对象转换为Java层BinderProxy
对象。 也就是说通过getService()最终获取了指向目标Binder服务端的代理对象BinderProxy。
小结
getService的核心过程:
public static IBinder getService(String name) {
…
Parcel reply = Parcel.obtain(); //此处还需要将java层的Parcel转为Native层的Parcel
BpBinder::transact(GET_SERVICE_TRANSACTION, *data, reply, 0); //与Binder驱动交互
IBinder binder = javaObjectForIBinder(env, new BpBinder(handle));
…
}
javaObjectForIBinder
作用是创建BinderProxy
对象,并将BpBinder
对象的地址保存到BinderProxy
对象的mObjects
中。 获取服务过程就是通过BpBinder来发送GET_SERVICE_TRANSACTION
命令,与实现与binder驱动进行数据交互。
请求服务getService()
过程,就是向servicemanager
进程查询指定服务,当执行binder_transaction
()时,会区分请求服务所属进程情况。
- 当请求服务的进程与服务属于不同进程,则为请求服务所在进程创建
binder_ref
对象,指向服务进程中的binder_node
;即创建了一个针对于请求服务进程的一个手机号,然后请求进程就可以通过得到一个小弟(BpBinder),让小弟记住这个手机号,就可以找到对应的服务人员(BBinder),然后就可以让服务人员办事了。
- 最终
readStrongBinder
(),返回的是BpBinder对象;
- 当请求服务的进程与服务属于同一进程,则不再创建新对象,只是引用计数加1,并且修改type为BINDER_TYPE_BINDER或BINDER_TYPE_WEAK_BINDER。
- 最终
readStrongBinder
(),返回的是BBinder对象的真实子类;
一张图来总结一下:
喜欢的话留个赞再走呗,有任何技术问题都可以评论区留言,我会为你解答
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
最后
**要想成为高级安卓工程师,必须掌握许多基础的知识。**在工作中,这些原理可以极大的帮助我们理解技术,在面试中,更是可以帮助我们应对大厂面试官的刁难。
,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**
如果你觉得这些内容对你有帮助,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-YFjEkCpn-1711915648449)]
最后
**要想成为高级安卓工程师,必须掌握许多基础的知识。**在工作中,这些原理可以极大的帮助我们理解技术,在面试中,更是可以帮助我们应对大厂面试官的刁难。
[外链图片转存中…(img-8QnJBkvK-1711915648449)]
[外链图片转存中…(img-rYJLKuXU-1711915648450)]