美文网首页
Android跨进程通信IPC之17——Binder之Frame

Android跨进程通信IPC之17——Binder之Frame

作者: 凯玲之恋 | 来源:发表于2018-08-21 11:47 被阅读32次

    移步系列Android跨进程通信IPC系列

    1 注册服务

    注册服务在ServiceManager里面

    //frameworks/base/core/java/android/os/ServiceManager.java     70行
    public static void addService(String name, IBinder service, boolean allowIsolated) {
        try {
            //getIServiceManager()是获取ServiceManagerProxy对象
            // addService() 是执行注册服务操作
            getIServiceManager().addService(name, service, allowIsolated); 
        } catch (RemoteException e) {
            Log.e(TAG, "error in addService", e);
        }
    }
    

    2 getIServiceManager()方法

    //frameworks/base/core/java/android/os/ServiceManager.java     70行
        private static IServiceManager getIServiceManager() {
            if (sServiceManager != null) {
                return sServiceManager;
            }
            // Find the service manager
            sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
            return sServiceManager;
        }
    

    2.1 BinderInternal.getContextObject()方法

    //frameworks/base/core/java/com/android/internal/os/BinderInternal.java  88行
        /**
         * Return the global "context object" of the system.  This is usually
         * an implementation of IServiceManager, which you can use to find
         * other services.
         */
        public static final native IBinder getContextObject();
    

    可见BinderInternal.getContextObject()最终会调用JNI通过C层来实现,那我们就继续跟踪

    2.1.1 android_os_BinderInternal_getContextObject)函数

    // frameworks/base/core/jni/android_util_Binder.cpp     899行
    static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
    {
        sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
        return javaObjectForIBinder(env, b);  
    }
    
    • 看到上面的代码 大家有没有熟悉的感觉,前面讲过了:对于ProcessState::self() -> getContextObject()
    • 对于ProcessState::self()->getContextObject()可以理解为new BpBinder(0)

    2.1.2 javaObjectForIBinder()函数

    // frameworks/base/core/jni/android_util_Binder.cpp         547行
    jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
    {
        if (val == NULL) return NULL;
        //返回false
        if (val->checkSubclass(&gBinderOffsets)) { 
            jobject object = static_cast<JavaBBinder*>(val.get())->object();
            return object;
        }
    
        AutoMutex _l(mProxyLock);
    
        jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
        //第一次 object为null
        if (object != NULL) { 
            //查找是否已经存在需要使用的BinderProxy对应,如果有,则返回引用。
            jobject res = jniGetReferent(env, object);
            if (res != NULL) {
                return res;
            }
            android_atomic_dec(&gNumProxyRefs);
            val->detachObject(&gBinderProxyOffsets);
            env->DeleteGlobalRef(object);
        }
    
        //创建BinderProxy对象
        object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
        if (object != NULL) {
            // BinderProxy.mObject成员变量记录BpBinder对象
            env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get());
            val->incStrong((void*)javaObjectForIBinder);
    
            jobject refObject = env->NewGlobalRef(
                    env->GetObjectField(object, gBinderProxyOffsets.mSelf));
             //将BinderProxy对象信息附加到BpBinder的成员变量mObjects中
            val->attachObject(&gBinderProxyOffsets, refObject,
                    jnienv_to_javavm(env), proxy_cleanup);
    
            sp<DeathRecipientList> drl = new DeathRecipientList;
            drl->incStrong((void*)javaObjectForIBinder);
             // BinderProxy.mOrgue成员变量记录死亡通知对象
            env->SetLongField(object, gBinderProxyOffsets.mOrgue, reinterpret_cast<jlong>(drl.get()));
    
            android_atomic_inc(&gNumProxyRefs);
            incRefsCreated(env);
        }
        return object;
    }
    

    上面的大致流程如下:

    • 1、第二个入参val在有些时候指向BpBinder,有些时候指向JavaBBinder
    • 2、至于是BpBinder还是JavaBBinder是通过if (val->checkSubclass(&gBinderOffsets)) 这个函数来区分的,如果是JavaBBinder,则为true,则就会通过成员函数object(),返回一个Java对象,这个对象就是Java层的Binder对象。由于我们这里是BpBinder,所以是 返回false
    • 3、如果是BpBinder,会先判断是不是第一次
      • 如果是第一次,下面的object为null。jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
      • 如果不是第一次,就会先查找是否已经存在需要使用的BinderProxy对象,如果找到就会返回引用
    • 4、如果没有找到可用的引用,就new一个BinderProxy对象
    • 所以主要是根据BpBinder(C++) 生成BinderProxy(Java对象),主要工作是创建BinderProxy对象,并把BpBinder对象地址保存到BinderProxy.mObject成员变量。
    • 到此,可知ServiceManagerNative.asInterface(BinderInternal.getContextObject()) 等价于
      ServiceManagerNative.asInterface(new BinderProxy())

    2.2 ServiceManagerNative.asInterface()方法

    //frameworks/base/core/java/android/os/ServiceManagerNative.java      33行
        /**
         * Cast a Binder object into a service manager interface, generating
         * a proxy if needed.
         * 将Binder对象转换service manager interface,如果需要,生成一个代理。
         */
        static public IServiceManager asInterface(IBinder obj)
        {
            //obj为 BpBinder
            // 如果 obj为null 则直接返回
            if (obj == null) {
                return null;
            }
            // 由于是BpBinder,所以BpBinder的queryLocalInterface(descriptor) 默认返回null
            IServiceManager in =
                (IServiceManager)obj.queryLocalInterface(descriptor);
            if (in != null) {
                return in;
            }
            return new ServiceManagerProxy(obj);
        }
    

    我们看下这个obj.queryLocalInterface(descriptor)方法,其实他是调用的IBinder的native方法如下

    public interface IBinder {
        .....
        /**
         * Attempt to retrieve a local implementation of an interface
         * for this Binder object.  If null is returned, you will need
         * to instantiate a proxy class to marshall calls through
         * the transact() method.
         */
        public IInterface queryLocalInterface(String descriptor);
        .....
    }
    
    • 通过注释我们知道,queryLocalInterface是查询本地的对象
    • 本地对象,这里的本地对象是指,如果进行IPC调用,如果是两个进程是同一个进程,即对象是本地对象;如果两个进程是两个不同的进程,则返回的远端的代理类。
    • 所以在BBinder的子类BnInterface中,重载了这个方法,返回this,而在BpInterface并没有重载这个方法。又因为queryLocalInterface 默认返回的是null,所以obj.queryLocalInterface=null。
    • 所以最后结论是 return new ServiceManagerProxy(obj);

    2.2.1 ServiceManagerProxy

    PS:ServiceManagerProxy是ServiceManagerNative类的内部类

    //frameworks/base/core/java/android/os/ServiceManagerNative.java    109行
    class ServiceManagerProxy implements IServiceManager {
        public ServiceManagerProxy(IBinder remote) {
            mRemote = remote;
        }
    }
    
    • mRemote为BinderProxy对象,该BinderProxy对象对应于BpBinder(0),其作为binder代理端,指向native的层的Service Manager。

    所以说:

    • ServiceManager.getIServiceManager最终等价于new ServiceManagerProxy(new BinderProxy())。所以
     getIServiceManager().addService()
    

    等价于

    ServiceManagerNative.addService();
    
    • framework层的ServiceManager的调用实际的工作确实交给了ServiceManagerProxy的成员变量BinderProxy;
    • 而BinderProxy通过JNI的方式,最终会调用BpBinder对象;可见上层binder结构的核心功能依赖native架构的服务来完成的。

    3 addService()方法详解

    上面已经知道了

    getIServiceManager().addService(name, service, allowIsolated); 
    

    等价于

    ServiceManagerProxy..addService(name, service, allowIsolated);
    

    所以让我们来看下ServiceManagerProxy的addService()方法

    3.1 ServiceManagerProxy的addService()

    //frameworks/base/core/java/android/os/ServiceManagerNative.java     142行
        public void addService(String name, IBinder service, boolean allowIsolated)
                throws RemoteException {
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
            //是个常量是 “android.os.IServiceManager"
            data.writeInterfaceToken(IServiceManager.descriptor);
            data.writeString(name);
            data.writeStrongBinder(service);
            data.writeInt(allowIsolated ? 1 : 0);
            mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
            reply.recycle();
            data.recycle();
        }
    

    里面代码都比较容易理解,这里重点说下data.writeStrongBinder(service); 和 mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);

    3.2 Parcel.writeStrongBinder()

    //frameworks/base/core/java/android/os/Parcel.java     583行
        /**
         * Write an object into the parcel at the current dataPosition(),
         * growing dataCapacity() if needed.
         */
        public final void writeStrongBinder(IBinder val) {
            nativeWriteStrongBinder(mNativePtr, val);
        }
    

    注释:在当前的dataPosition()的位置上写入一个对象,如果空间不足,则增加空间

    3.2.1 nativeWriteStrongBinder()方法

    /frameworks/base/core/java/android/os/Parcel.java      265行
        private static native void nativeWriteStrongBinder(long nativePtr, IBinder val);
    

    3.2.2 android_os_Parcel_writeStrongBinder()函数

    //frameworks/base/core/jni/android_os_Parcel.cpp    298行
    static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
    {
        //将java层Parcel转换为native层Parcel
        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);
            }
        }
    }
    

    这里主要涉及的两个重要的函数

    • writeStrongBinder()函数
    • ibinderForJavaObject()函数

    3.2.3 ibinderForJavaObject()函数

    // frameworks/base/core/jni/android_util_Binder.cpp   603行
    sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
    {
        if (obj == NULL) return NULL;
    
        //Java层的Binder对象
        //mClass指向Java层中的Binder class
        if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
            JavaBBinderHolder* jbh = (JavaBBinderHolder*)
                env->GetLongField(obj, gBinderOffsets.mObject);
            //get()返回一个JavaBBinder,继承自BBinder
            return jbh != NULL ? jbh->get(env, obj) : NULL;
        }
        //Java层的BinderProxy对象
        // mClass 指向Java层的BinderProxy class
        if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
            //返回一个 BpBinder,mObject 是它的地址值
            return (IBinder*)env->GetLongField(obj, gBinderProxyOffsets.mObject);
        }
        return NULL;
    }
    

    根据Binder(Java)生成JavaBBinderHolder(C++)对象,主要工作是创建JavaBBinderHolder对象,并把JavaBBinder对象保存在到Binder.mObject成员变量。

    • 这个函数,本质就是根据传进来的Java对象找到对应的C++对象,这里的obj可能会指向两种对象:Binder对象和BinderProxy对象。
    • 如果传进来的是Binder对象,则会把gBinderOffsets.mObject转化为JavaBBinderHolder,并从中获得一个JavaBBinder对象(JavaBBinder继承自BBinder)。
    • 如果是BinderProxy对象,会返回一个BpBinder,这个BpBinder的地址值保存在gBinderProxyOffsets.mObject中

    在上面的代码里面调用了get()函数,如下图

    JavaBBinderHolder* jbh = (JavaBBinderHolder*)
    env->GetLongField(obj, gBinderOffsets.mObject);
    //get()返回一个JavaBBinder,继承自BBinder
    return jbh != NULL ? jbh->get(env, obj) : NULL;
    

    那我们就来研究下JavaBBinderHolder.get()函数

    3.2.4 JavaBBinderHolder.get()函数

    // frameworks/base/core/jni/android_util_Binder.cpp      316行
    sp<JavaBBinder> get(JNIEnv* env, jobject obj)
    {
        AutoMutex _l(mLock);
        sp<JavaBBinder> b = mBinder.promote();
        if (b == NULL) {
            //首次进来,创建JavaBBinder对象
            b = new JavaBBinder(env, obj);
            mBinder = b;
        }
        return b;
    }
    

    JavaBBinderHolder有一个成员变量mBinder,保存当前创建的JavaBBinder对象,这是一个wp类型的,可能会被垃圾回收器给回收的,所以每次使用前都需要先判断是否存在。

    那我们再来看看下JavaBBinder的初始化

    3.2.5 JavaBBinder的初始化

    JavaBBinder(JNIEnv* env, jobject object)
        : mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object))
    {
        ALOGV("Creating JavaBBinder %p\n", this);
        android_atomic_inc(&gNumLocalRefs);
        incRefsCreated(env);
    }
    

    创建JavaBBinder,该对象继承于BBinder对象。

    3.2.6 总结

    所以说 data.writeStrongBinder(Service)最终等价于parcel->writeStringBinder(new JavaBBinder(env, obj));

    3.2.7 writeStrongBinder() 函数

    // frameworks/native/libs/binder/Parcel.cpp     872行
    status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
    {
        return flatten_binder(ProcessState::self(), val, this);
    }
    

    我们看到writeStrongBinder()函数 实际上是调用的flatten_binder()函数

    3.2.8 writeStrongBinder() 函数

    //frameworks/native/libs/binder/Parcel.cpp    205行
    status_t flatten_binder(const sp<ProcessState>& /*proc*/,
        const sp<IBinder>& binder, Parcel* out)
    {
        flat_binder_object obj;
        obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
        if (binder != NULL) {
            IBinder *local = binder->localBinder();
            if (!local) {
                //如果不是本地Binder
                BpBinder *proxy = binder->remoteBinder();
                const int32_t handle = proxy ? proxy->handle() : 0;
                //远程Binder
                obj.type = BINDER_TYPE_HANDLE; 
                obj.binder = 0; 
                obj.handle = handle;
                obj.cookie = 0;
            } else {
                //如果是本地Binder
                obj.type = BINDER_TYPE_BINDER; 
                obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
                obj.cookie = reinterpret_cast<uintptr_t>(local);
            }
        } else {
            //本地Binder
            obj.type = BINDER_TYPE_BINDER;  
            obj.binder = 0;
            obj.cookie = 0;
        }
        return finish_flatten_binder(binder, obj, out);
    }
    

    将Binder对象扁平化,转换成flat_binder_object对象

    • 对于Binder实体,则cookie记录Binder实体指针
    • 对于Binder代理,则用handle记录Binder代理的句柄

    关于localBinder,在Binder.cpp里面

    BBinder* BBinder::localBinder()
    {
        return this;
    }
    
    BBinder* IBinder::localBinder()
    {
        return NULL;
    
    

    在最后面调用了finish_flatten_binder()函数,那我们再研究下finish_flatten_binder()函数

    3.2.9 finish_flatten_binder() 函数

    //frameworks/native/libs/binder/Parcel.cpp    199行
    inline static status_t finish_flatten_binder(
        const sp<IBinder>& , const flat_binder_object& flat, Parcel* out)
    {
        return out->writeObject(flat, false);
    }
    

    这个大家看明白了吧,就是写入一个object。

    3.3 IBinder.transact()

    ServiceManagerProxy的addService()中的mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);里面的mRemote的类型是BinderProxy的,所以调用是BinderProxy的transact()方法,那我们就进去看看

    3.2.3.1 BinderProxy.transact()

    温馨提示:BinderProxy类是Binder类的内部类
    他其实是重写的IBinder的里面的transact()方法,那让我们看下IBinder里面

    // frameworks/base/core/java/android/os/IBinder.java  223行
        /**
         * Perform a generic operation with the object.
         * 
         * @param code The action to perform.  This should
         * be a number between {@link #FIRST_CALL_TRANSACTION} and
         * {@link #LAST_CALL_TRANSACTION}.
         * @param data Marshalled data to send to the target.  Must not be null.
         * If you are not sending any data, you must create an empty Parcel
         * that is given here.
         * @param reply Marshalled data to be received from the target.  May be
         * null if you are not interested in the return value.
         * @param flags Additional operation flags.  Either 0 for a normal
         * RPC, or {@link #FLAG_ONEWAY} for a one-way RPC.
         */
        public boolean transact(int code, Parcel data, Parcel reply, int flags)
            throws RemoteException;
    

    主要是这个注释

    • 用对象执行一个操作
    • 参数code 为操作码,是介于FIRST_CALL_TRANSACTION和LAST_CALL_TRANSACTION之间
    • 参数data 是要发往目标的数据,一定不能null,如果你没有数据要发送,你也要创建一个Parcel,哪怕是空的。
    • 参数reply 是从目标发过来的数据,如果你对这个数据没兴趣,这个数据是可以为null的。
    • 参数flags 一个操作标志位,要么是0代表普通的RPC,要么是FLAG_ONEWAY代表单一方向的RPC即不管返回值

    这时候我们再回来看

    /frameworks/base/core/java/android/os/Binder.java   501行
    final class BinderProxy implements IBinder {
        public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
            if (Binder.isTracingEnabled()) { Binder.getTransactionTracker().addTrace(); }
            return transactNative(code, data, reply, flags);
        }
    }
    

    3.3.2 Binder.checkParcel()

    /frameworks/base/core/java/android/os/Binder.java   415行
        static void checkParcel(IBinder obj, int code, Parcel parcel, String msg) {
            if (CHECK_PARCEL_SIZE && parcel.dataSize() >= 800*1024) {
                // Trying to send > 800k, this is way too much
                StringBuilder sb = new StringBuilder();
                sb.append(msg);
                sb.append(": on ");
                sb.append(obj);
                sb.append(" calling ");
                sb.append(code);
                sb.append(" size ");
                sb.append(parcel.dataSize());
                sb.append(" (data: ");
                parcel.setDataPosition(0);
                sb.append(parcel.readInt());
                sb.append(", ");
                sb.append(parcel.readInt());
                sb.append(", ");
                sb.append(parcel.readInt());
                sb.append(")");
                Slog.wtfStack(TAG, sb.toString());
            }
        }
    
    • 这段代码很简单,主要是检查Parcel大小是否大于800K
    • 执行完Binder.checkParcel后,直接调用了transactNative()方法,那我们就来看看transactNative()方法

    3.3.3 transactNative()方法

    // frameworks/base/core/java/android/os/Binder.java   507行
        public native boolean transactNative(int code, Parcel data, Parcel reply,
                int flags) throws RemoteException;
    

    我们看到他是一个native函数,后面肯定经过JNI调用到了native层,根据包名,它对应的方法应该是"android_os_BinderProxy_transact"函数,那我们继续跟踪

    3.3.4 android_os_BinderProxy_transact()函数

    // frameworks/base/core/jni/android_util_Binder.cpp     1083行
       static jboolean android_os_BinderProxy_transact(JNIEnv*env, jobject obj,
                                                        jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
        {
            if (dataObj == NULL) {
                jniThrowNullPointerException(env, NULL);
                return JNI_FALSE;
            }
            // 将 java Parcel转化为native Parcel
            Parcel * data = parcelForJavaObject(env, dataObj);
            if (data == NULL) {
                return JNI_FALSE;
            }
            Parcel * reply = parcelForJavaObject(env, replyObj);
            if (reply == NULL && replyObj != NULL) {
                return JNI_FALSE;
            }
            // gBinderProxyOffsets.mObject中保存的是new BpBinder(0)对象
            IBinder * target = (IBinder *)
            env -> GetLongField(obj, gBinderProxyOffsets.mObject);
            if (target == NULL) {
                jniThrowException(env, "java/lang/IllegalStateException", "Binder has been finalized!");
                return JNI_FALSE;
            }
    
            ALOGV("Java code calling transact on %p in Java object %p with code %"PRId32"\n",
                    target, obj, code);
    
    
            bool time_binder_calls;
            int64_t start_millis;
            if (kEnableBinderSample) {
                // Only log the binder call duration for things on the Java-level main thread.
                // But if we don't
                time_binder_calls = should_time_binder_calls();
    
                if (time_binder_calls) {
                    start_millis = uptimeMillis();
                }
            }
    
            //printf("Transact from Java code to %p sending: ", target); data->print();
             // 此处便是BpBinder:: transact(),经过native层,进入Binder驱动。
            status_t err = target -> transact(code, * data, reply, flags);
            //if (reply) printf("Transact from Java code to %p received: ", target); reply->print();
    
            if (kEnableBinderSample) {
                if (time_binder_calls) {
                    conditionally_log_binder_call(start_millis, target, code);
                }
            }
    
            if (err == NO_ERROR) {
                return JNI_TRUE;
            } else if (err == UNKNOWN_TRANSACTION) {
                return JNI_FALSE;
            }
            signalExceptionForError(env, obj, err, true /*canThrowRemoteException*/, data -> dataSize());
            return JNI_FALSE;
        }
    

    通过上面的代码我们知道,Java层BinderProxy.transact()最终交由Native层的BpBinder::transact()完成。这部分之前代码讲解过了,我这里就不详细说明了。不过注意,该方法可能会抛出RemoteException。

    参考

    Android跨进程通信IPC之10——Binder之Framework层Java篇

    相关文章

      网友评论

          本文标题:Android跨进程通信IPC之17——Binder之Frame

          本文链接:https://www.haomeiwen.com/subject/bknliftx.html