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<Parcel*>(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<IBinder> 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<IBinder>& val)
{
    
    
    return flattenBinder(val);
}
status_t Parcel::flattenBinder(const sp<IBinder>& 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<uintptr_t>(local->getWeakRefs());
            // local 就是当前binder对象自己
            obj.cookie = reinterpret_cast<uintptr_t>(local);
 return finishFlattenBinder(binder);
}
  • finishFlattenBinder()
status_t Parcel::finishFlattenBinder(const sp<IBinder>& 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<T>);
	// 先判断是否需要扩容 
    if ((mDataPos+sizeof(val)) <= mDataCapacity) {
    
    
restart_write:
        memcpy(mData + mDataPos, &val, sizeof(val));
        return finishWrite(sizeof(val));
    }

    status_t err = growData(sizeof(val));
    if (err == NO_ERROR) goto restart_write;
    return err;
}

上面方法先判断缓冲区是否需要扩容,如果需要扩容则先通过 growData() 扩容,如果不需要扩容则通过 memcpy() 来进行内存拷贝工作(memcpy指的是C和C++使用的内存拷贝函数,函数原型为void *memcpy(void *destin, void *source, unsigned n);函数的功能是从源内存地址的起始位置开始拷贝若干个字节到目标内存地址中)。

  • finishWrite(sizeof(val));
status_t Parcel::finishWrite(size_t len)
{
    
    	
// 判断是否超过了最大长度
    if (len > INT32_MAX) {
    
    
        return BAD_VALUE;
    }
    // 更新一下 mDataPos 长度,如果下次再写,mDataPos就是下一个开始的偏移点
    mDataPos += len;
    if (mDataPos > mDataSize) {
    
    
        mDataSize = mDataPos; 
    }
    return NO_ERROR;
}

在这里插入图片描述

扫描二维码关注公众号,回复: 17092955 查看本文章
  • 接下来 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<Parcel*>(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<IBinder> Parcel::readStrongBinder() const
{
    
    
    sp<IBinder> 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<IBinder>* val) const
{
    
    
    return unflattenBinder(val);
}
  • unflattenBinder(val);
status_t Parcel::unflattenBinder(sp<IBinder>* 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<IBinder> binder =
                        sp<IBinder>::fromExisting(reinterpret_cast<IBinder*>(flat->cookie));
                return finishUnflattenBinder(binder, out);
            }
            case BINDER_TYPE_HANDLE: {
    
    
            //根据 handle  值 生成 BPBinder 返回
                sp<IBinder> binder =
                    ProcessState::self()->getStrongProxyForHandle(flat->handle);
                return finishUnflattenBinder(binder, out);
            }
        }
}
  • getStrongProxyForHandle() 根据 binder代理对象的 handle 值返回binder在native层的对象。
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    
    
    sp<IBinder> result;
	// 根据 handle 生成一个 handle_entry 值
    handle_entry* e = lookupHandleLocked(handle);

    if (e != nullptr) {
    
    
        IBinder* b = e->binder;
        // 	...
        // 封装成 BpBinder 
            sp<BpBinder> 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<IBinder>& val)
{
    
    
	// 先判断是不是binder实体
    if (val->checkSubclass(&gBinderOffsets)) {
    
    
        // It's a JavaBBinder created by ibinderForJavaObject. Already has Java object.
       // 如果是 binder 实体 返回 java 层的 JavaBBinder
        jobject object = static_cast<JavaBBinder*>(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;
}

在这里插入图片描述

总结

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

猜你喜欢

转载自blog.csdn.net/ldxlz224/article/details/128927456