zoukankan      html  css  js  c++  java
  • Parcel在binder通信readStrongBinder和writeStrongBinder

    Binder IPC通信中,Binder是通信的媒介,Parcel是通信的內容。远程调用过程中,其参数都被打包成Parcel的形式来传递。

    在IPC通信的Proxy端,我们经常可以看到下面类似的代码,一些参数都会打包到Parcel中。看下面的data和reply。

    public void publishService(IBinder token,
                Intent intent, IBinder service) throws RemoteException {
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
            data.writeInterfaceToken(IActivityManager.descriptor);
            data.writeStrongBinder(token);
            intent.writeToParcel(data, 0);
            data.writeStrongBinder(service);
            mRemote.transact(PUBLISH_SERVICE_TRANSACTION, data, reply, 0);
            reply.readException();
            data.recycle();
            reply.recycle();
        }

    在IPC通信里,android是通过Parcel类的成员函数writeStrongBinder()向Parcel写入IBinder,再通过mRemote发送出去。

    2.writeStrongBinder()

    接下來就看一下writeStrongBinder()这个函数里做了什么。
    /frameworks/base/core/java/android/os/Parcel.java

    public final class Parcel {
        …
        /**
         * Write an object into the parcel at the current dataPosition(),
         * growing dataCapacity() if needed.
         */
        public final void writeStrongBinder(IBinder val) {
            nativeWriteStrongBinder(mNativePtr, val);
        }
        private static native void nativeWriteStrongBinder(int nativePtr, IBinder val);
        …
    }

    看,这里又调用了native方法,我们会发现Java 层的一些Parcel其实只是对C/C++层的一个封裝,大部分操作还是依靠JNI去调用Native的操作。
    那看一下C++里对应的方法:

    /frameworks/base/core/jni/android_os_Parcel.cpp

    static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jint nativePtr, jobject object)
    {
        Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
        if (parcel != NULL) {
            const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
            if (err != NO_ERROR) {
                signalExceptionForError(env, clazz, err);
            }
        }
    }

    最主要的就是ibinderForJavaObject 这个函数,继续跟踪代码:

    /frameworks/base/core/jni/android_util_Binder.cpp

    sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
    {
        if (obj == NULL) return NULL;
    
        if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) { //mClass指向Java层中的Binder class
            JavaBBinderHolder* jbh = (JavaBBinderHolder*)
                env->GetIntField(obj, gBinderOffsets.mObject);
            return jbh != NULL ? jbh->get(env, obj) : NULL; //get() 返回一個JavaBBinder,继承自BBinder
        }
    
        if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) { //mClass 指向Java层的BinderProxy class
            return (IBinder*)
                env->GetIntField(obj, gBinderProxyOffsets.mObject); //返回一个BpBinder,mObject是它的地址值
        }
        ALOGW("ibinderForJavaObject: %p is not a Binder object", obj);
        return NULL;
    }

    这个函数呢,就是根据传进来的Java对象找到对应的C++对象,这里的参数obj,可能会指向两种对象:Binder对象或者BinderProxy对象。这两个对象我们在RemoteService那一篇里其实就遇到过了,Binder对象呢就是Service里实现的那个mRemoteBinder,BinderProxy对象呢就是Activity里回调传进来的那个service。

    接着说,如果传进來的是Binder对象,那么就会把gBinderOffsets.mObject转化成JavaBBinderHolder, 并从中获得一个JavaBBinder对象。JavaBBinder继承自BBinder。(在RemoteService那一篇,Service会在onBind回调里把mRemoteBinder传给AMS,这里传递的就是Binder对象)

    如果传进來的是BinderProxy对象。就会返回一个BpBinder,这个BpBinder的地址值就保存在gBinderProxyOffsets.mObject中。(在RemoteService那一篇,AMS要传递给Acticity的就是BinderProxy对象)。

    到这里,你可能会奇怪,为什么Service把Binder对象传递给AMS,后面AMS却是把BinderProxy对象传递给Activity呢?这个我们后面再说,(可以先说一下,其实是因为这些Binder对象都会经过底层传输,那在传输的过程中,Binder模块就会根据不同的情况对这些对象进行转化)

    3.readStrongBinder()

    同样也是JNI调用:

    /frameworks/base/core/jni/android_os_Parcel.cpp

    static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jint nativePtr)
    {
          ...
          return javaObjectForIBinder(env, parcel->readStrongBinder());
    }
    /frameworks/base/core/jni/android_util_Binder.cpp
    jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val) (1)
    {
        if (val == NULL) return NULL;
        if (val->checkSubclass(&gBinderOffsets)) { (2)12         // One of our own!
            jobject object = static_cast<JavaBBinder*>(val.get())->object();
            LOGDEATH("objectForBinder %p: it's our own %p!
    ", val.get(), object);
            return object;
        }
       ...
        jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
        if (object != NULL) {
            jobject res = env->CallObjectMethod(object, gWeakReferenceOffsets.mGet); (3if (res != NULL) {
                ALOGV("objectForBinder %p: found existing %p!
    ", val.get(), res);
                return res;
            }
           ...
        }
        object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor); (4if (object != NULL) {
           ….
        }
        return object;
    }

    (1):这里的val和writeStrongBinder类似,不过是反过来,指向的可能是JavaBBinder或者BpBinder。

    (2):如果是JavaBBinder,就会通过成员函数object(),返回一个Java对象,这个对象就是Java层的Binder对象。

    (3):如果是BpBinder,那就先查找是否已经存在需要使用的BinderProxy对象,如果找到就返回引用

    (4):如果沒找到可用的引用,就new 一个BinderProxy对象。

  • 相关阅读:
    Redis常用数据类型介绍、使用场景及其操作命令
    spring的官方文档地址
    ps基础学习笔记一
    类的加载时机与步骤(转)
    jvm的基本结构以及各部分详解(转)
    jdk1.8使用的url和driverName的改变
    测试框架简单了解
    shiro简单学习的简单总结
    easyui弹框后销毁当前tab弹框不显示的解决方式
    springboot学习章节代码-Spring MVC基础
  • 原文地址:https://www.cnblogs.com/mingfeng002/p/10993599.html
Copyright © 2011-2022 走看看