Binder 跨进程传递对象的原理 您所在的位置:网站首页 aidl跨进程通信 Binder 跨进程传递对象的原理

Binder 跨进程传递对象的原理

#Binder 跨进程传递对象的原理| 来源: 网络整理| 查看: 265

文章目录 问题跨进程交互流程Binder 架构图写对象数据读取数据总结

问题 1. binder 传递有哪些方式 2. binder 在传递过程中是怎样存储的 3. binder 对象序列化和反序列化的过程 4. binder 对象在传递过程中驱动做了什么 跨进程交互流程

点击跳转 Binder 跨进程交互流程

Binder 架构图

在这里插入图片描述

写对象数据 先定义一个 aidl 文件 // IMyAidlInterface.aidl package com.example.server; import com.example.server.ICallback; interface IMyAidlInterface { // ICallback 也是一个 aidl 接口 void go(ICallback callback); } // ICallback.aidl package com.example.server; interface ICallback { void callback(int code); } build 后的 IMyAidlInterface 代理对象 go() 方法如下 @Override public void go(com.example.server.ICallback callback) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeStrongBinder((((callback != null)) ? (callback.asBinder()) : (null))); boolean _status = mRemote.transact(Stub.TRANSACTION_go, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { getDefaultImpl().go(callback); return; } _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } }

对象会用 _data.writeStrongBinder() 函数写出去,然后还是通过 mRemote.transact() 出去。 在这里插入图片描述

首先先看 writeStrongBinder() public final void writeStrongBinder(IBinder val) { nativeWriteStrongBinder(mNativePtr, val); }

调用了 nativeWriteStrongBinder() 传入了 mNativePtr 和 callback 的binder 实体对象,mNativePtr 是 Parcel 在 native 层对象的指针。 接下来看 nativeWriteStrongBinder()

frameworks/base/core/jni/android_os_Parcel.cpp 下的 android_os_Parcel_writeStrongBinder() 函数 static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object) { // 通过Parcel 指针 nativePtr 获取到 native 层的Parcel对象 Parcel* parcel = reinterpret_cast(nativePtr); if (parcel != NULL) { // 然后通过 java层的 binder 对象 获取到 native 层的 binder 对象,写到 native 层的parcel 对象中。 const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object)); if (err != NO_ERROR) { signalExceptionForError(env, clazz, err); } } }

在这里插入图片描述

ibinderForJavaObject(env, object) 是如何将 java层的binder 对象 转换为 native 层的 binder 对象的? // obj 传入的是 java 层的 bidner 对象 sp ibinderForJavaObject(JNIEnv* env, jobject obj) { if (obj == NULL) return NULL; // 后面根据 obj 的类型来处理 对应的逻辑 // Instance of Binder? // 如果传入的 java层 binder 对象是一个实体对象 if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) { // 获取的是 JavaBBinderHolder ,java 层对象中存储了 native JavaBBinderHolder 的指针 JavaBBinderHolder* jbh = (JavaBBinderHolder*) env->GetLongField(obj, gBinderOffsets.mObject); if (jbh == nullptr) { ALOGE("JavaBBinderHolder null on binder"); return nullptr; } //通过get() 从 JavaBBinderHolder 中获取到native层的 binder对象:JavaBBinder // JavaBBinder 继承了 BBinder return jbh->get(env, obj); } // Instance of BinderProxy? // 如果是 BinderProxy 对象,则获取到 native 层保存的 Proxy 对象 if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) { return getBPNativeData(env, obj)->mObject; } return NULL; }

通过 java 层对象转换为 native 层的 binder 对象之后,就通过 writeStrongBinder() 把 native 层的 binder 对象写到 Parcel 里面。

status_t Parcel::writeStrongBinder(const sp& val) { return flattenBinder(val); } status_t Parcel::flattenBinder(const sp& binder) { BBinder* local = nullptr; if (binder) local = binder->localBinder(); flat_binder_object obj; // 标记成 BINDER_TYPE_BINDER 代表是 binder 实体对象 obj.hdr.type = BINDER_TYPE_BINDER; obj.binder = reinterpret_cast(local->getWeakRefs()); // local 就是当前binder对象自己 obj.cookie = reinterpret_cast(local); return finishFlattenBinder(binder); } finishFlattenBinder() status_t Parcel::finishFlattenBinder(const sp& binder) { internal::Stability::tryMarkCompilationUnit(binder.get()); int16_t rep = internal::Stability::getRepr(binder.get()); return writeInt32(rep); }

finishFlattenBinder() 的作用是将 binder 对象写到 Parcel 中writeInt32(rep); 调用了 writeAligned(T val)

status_t Parcel::writeAligned(T val) { static_assert(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T)); static_assert(std::is_trivially_copyable_v); // 先判断是否需要扩容 if ((mDataPos+sizeof(val)) // 判断是否超过了最大长度 if (len > INT32_MAX) { return BAD_VALUE; } // 更新一下 mDataPos 长度,如果下次再写,mDataPos就是下一个开始的偏移点 mDataPos += len; if (mDataPos > mDataSize) { mDataSize = mDataPos; } return NO_ERROR; }

在这里插入图片描述

接下来 binder 对象写到驱动层以后是怎么处理的

Binder 实体对象传入到 binder 驱动以后,如果是实体对象,先看驱动中有没有实体对象(binder_node 数据结果),如果没有则 new 一个,然后再检查在目标进程有没有对应的引用对象,如果没有则创建一个, 如果是实体对象则转换成代理对象,标记由 BINDER_TYPE_BINDER 转换成 BINDER_BINDER_TYPE_HANDLE。 在这里插入图片描述

读取数据 data.readStrongBinder() 读取数据是从 onTransact 中 data.readStrongBinder() 开始的 // mNativePtr 是java层 Parcel 对象对应的 native 层 Parcel 对象的指针 public final IBinder readStrongBinder() { return nativeReadStrongBinder(mNativePtr); } frameworks/base/core/jni/android_os_Parcel.cpp 的 nativeReadStrongBinder() 函数 static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr) { // 通过 nativePtr Parcel 指针获取 native 层 Parcel 对象 Parcel* parcel = reinterpret_cast(nativePtr); if (parcel != NULL) { // 从 Parcel 中 先通过 readStrongBinder() 读出来 native 层的 binder 对象 // 再通过 javaObjectForIBinder 将 native 层的 binder 对象转换为 java 层的 binder 对象返回 return javaObjectForIBinder(env, parcel->readStrongBinder()); } return NULL; } readStrongBinder():从 Parcel 中 先通过 readStrongBinder() 读出来 native 层的 binder 对象。调用了 readNullableStrongBinder() 后又调用了 unflattenBinder(val); sp Parcel::readStrongBinder() const { sp val; // Note that a lot of code in Android reads binders by hand with this // method, and that code has historically been ok with getting nullptr // back (while ignoring error codes). readNullableStrongBinder(&val); return val; } status_t Parcel::readNullableStrongBinder(sp* val) const { return unflattenBinder(val); } unflattenBinder(val); status_t Parcel::unflattenBinder(sp* out) const{ // 首先先从 Parcel 将 flat_binder_object 读取出来 const flat_binder_object* flat = readObject(false); // 根据 type 区分,上面说了驱动将写到缓冲区的实体对象的 type 从 BINDER_TYPE_BINDER 改为了 BINDER_TYPE_HANDLE(如果是同一个进程的话则还是BINDER_TYPE_BINDER 因为转换之前判断了进程是否含有) switch (flat->hdr.type) { case BINDER_TYPE_BINDER: { // 同一个进程返回的是 cookie 赋值的是 binder 实体对象 sp binder = sp::fromExisting(reinterpret_cast(flat->cookie)); return finishUnflattenBinder(binder, out); } case BINDER_TYPE_HANDLE: { //根据 handle 值 生成 BPBinder 返回 sp binder = ProcessState::self()->getStrongProxyForHandle(flat->handle); return finishUnflattenBinder(binder, out); } } } getStrongProxyForHandle() 根据 binder代理对象的 handle 值返回binder在native层的对象。 sp ProcessState::getStrongProxyForHandle(int32_t handle) { sp result; // 根据 handle 生成一个 handle_entry 值 handle_entry* e = lookupHandleLocked(handle); if (e != nullptr) { IBinder* b = e->binder; // ... // 封装成 BpBinder sp b = BpBinder::PrivateAccessor::create(handle); e->binder = b.get(); if (b) e->refs = b->getWeakRefs(); result = b; } } return result; }

getStrongProxyForHandle() 是 handler值来创建一个 BPBinder;接下来继续 javaObjectForIBinder() 函数

javaObjectForIBinder() 根据 native 层的 binder 对象返回 java 层的 binder 对象 // If the argument is a JavaBBinder, return the Java object that was used to create it. // Otherwise return a BinderProxy for the IBinder. If a previous call was passed the // same IBinder, and the original BinderProxy is still alive, return the same BinderProxy. jobject javaObjectForIBinder(JNIEnv* env, const sp& val) { // 先判断是不是binder实体 if (val->checkSubclass(&gBinderOffsets)) { // It's a JavaBBinder created by ibinderForJavaObject. Already has Java object. // 如果是 binder 实体 返回 java 层的 JavaBBinder jobject object = static_cast(val.get())->object(); return object; } // 如果是代理对象 则需要创建 BinderProxy 对象 内部存储了 native 层 binder 对象的指针 BinderProxyNativeData* nativeData = new BinderProxyNativeData(); nativeData->mOrgue = new DeathRecipientList; nativeData->mObject = val; jobject object = env->CallStaticObjectMethod(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mGetInstance, (jlong) nativeData, (jlong) val.get()); BinderProxyNativeData* actualNativeData = getBPNativeData(env, object); return object; }

在这里插入图片描述

总结 Binder 跨进程传输是通过 Parcel 传输的,先通过 WriteStrongBinder 写到 Parcel 再通过 ReadStrongBinder 读取Parcel。在 Parcel 中存储的结构是 flat_binder_object 根据偏移量来确定保存的位置。然后 Binder 驱动通过读取 Parcel 中的 binder 实体对象 创建了 binder_node 结构,和 binder_ref 引用给到目标进程;目标进程通过 binder_ref 的 handle 创建了 BpBinder 再往上调用到 BinderProxy 再调用到业务层 Proxy


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有