美文网首页
Binder 进程间通信机制详解(Java 和 JNI 篇)

Binder 进程间通信机制详解(Java 和 JNI 篇)

作者: 搬砖写Bug | 来源:发表于2018-07-25 22:35 被阅读97次

    通过上一篇的介绍,大家应该对 Binder 通信流程有了整体的了解,但其中很多知识点并没有讲到,例如:
     1、怎样实现 Binder 双工通信?
     2、进程间 Binder 对象是以什么方式传递?
     3、Binder 通信中 Parcel 的作用?
     4、Java 和 JNI 层在整个 Binder 通信中扮演的角色和作用?
     5、同一个进程会使用到 Binder 通信吗?
    在这一篇中都会给大家一一讲解。

    一、Binder 双工通信

    1.1 什么是 Binder 双工通信

    == 双 ==工通信表示两个进程之间可以互相调用和传递数据,Android 中最典型的场景就是应用进程和 AmS 之间的通信,我们都知道系统应用进程通过如下方法获取 AmS 客户端的代理:

    IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
    IActivityManager am = IActivityManager.Stub.asInterface(b);
    

    或者第三方应用可以通过标准 SDK 接口:

    ActivityManager am = (ActivityManager) mContex.getSystemService(Context.ACTIVITY_SERVICE);
    

    这样,我们就能通过 am 对象跨进程调用 system_server 进程中 AmS 的相关方法或者向它传递数据,但是 AmS 却不能发过来调用应用进程的方法或者向其传递数据,这种情况该怎么处理呢?
    其实方法很简单,Binder 机制已经给我们提供一种便捷的方法,我们只需要在应用进程中创建一个 Binder 服务端对象,再通过刚刚获得 am 对象传递给 AmS ,这样就能实现双工通信了。

    1.2 Binder 双工通信代码实现

    我们知道应用的生命周期方法都是 AmS 来驱动的,其中关键就在 ActivityThread.java 这个类,这个类就是应用的主线程,非常非常重要,我们这里只关注它和 AmS 是如何实现实现双工通信的。

    先来看一个关键的内部类:

    private class ApplicationThread extends ApplicationThreadNative {
        ......
        public final void schedulePauseActivity(IBinder token, boolean finished,
                boolean userLeaving, int configChanges, boolean dontReport) {
            int seq = getLifecycleSeq();
            if (DEBUG_ORDER) Slog.d(TAG, "pauseActivity " + ActivityThread.this
                    + " operation received seq: " + seq);
            sendMessage(
                    finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
                    token,
                    (userLeaving ? USER_LEAVING : 0) | (dontReport ? DONT_REPORT : 0),
                    configChanges,
                    seq);
        }
    
        public final void scheduleStopActivity(IBinder token, boolean showWindow,
                int configChanges) {
            int seq = getLifecycleSeq();
            if (DEBUG_ORDER) Slog.d(TAG, "stopActivity " + ActivityThread.this
                    + " operation received seq: " + seq);
            sendMessage(
                showWindow ? H.STOP_ACTIVITY_SHOW : H.STOP_ACTIVITY_HIDE,
                token, 0, configChanges, seq);
        }
    
        public final void scheduleWindowVisibility(IBinder token, boolean showWindow) {
            sendMessage(
                showWindow ? H.SHOW_WINDOW : H.HIDE_WINDOW,
                token);
        }
    
        public final void scheduleResumeActivity(IBinder token, int processState,
                boolean isForward, Bundle resumeArgs) {
            int seq = getLifecycleSeq();
            if (DEBUG_ORDER) Slog.d(TAG, "resumeActivity " + ActivityThread.this
                    + " operation received seq: " + seq);
            updateProcessState(processState, false);
            sendMessage(H.RESUME_ACTIVITY, token, isForward ? 1 : 0, 0, seq);
        }
    
        // we use token to identify this activity without having to send the
        // activity itself back to the activity manager. (matters more with ipc)
        @Override
        public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
                CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
                int procState, Bundle state, PersistableBundle persistentState,
                List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
                boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
    
            updateProcessState(procState, false);
    
            ActivityClientRecord r = new ActivityClientRecord();
    
            r.token = token;
            r.ident = ident;
            r.intent = intent;
            r.voiceInteractor = voiceInteractor;
            r.activityInfo = info;
            r.compatInfo = compatInfo;
            .....
            updatePendingConfiguration(curConfig);
    
            sendMessage(H.LAUNCH_ACTIVITY, r);
        }
        ......
    }
    

    可以看到 ApplicationThread 继承 ApplicationThreadNative,ApplicationThreadNative 又是什么呢?

    public abstract class ApplicationThreadNative extends Binder
            implements IApplicationThread {
    }
    

    看到它是继承了 Binder 并实现 IApplicationThread 接口的抽象类,这就表示它是 Binder 服务端,我们可以看看 ActivityManagerService.java 的继承关系:

    public class ActivityManagerService extends ActivityManagerNative {
        ...
    }
    

    而 ActivityManagerNative 也是继承 Binder,所以说 ApplicationThreadNative 本质上和 AmS 都是 Binder 服务端,如果发布到 ServiceManager,其他进程是可以访问到的。

    public abstract class ActivityManagerNative extends Binder implements IActivityManager
    {
        ...
    }
    

    知道了 ApplicationThread 是什么,接下来看应用进程是如何把它传递给 AmS 的?

    private void attach(boolean system) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        ......
        //获取AmS的代理对象
        final IActivityManager mgr = ActivityManagerNative.getDefault();
        try {
            //通过这个代理对象把mAppThread传递给AmS
            //mAppThread就是new一个ApplicationThread()对象;
            mgr.attachApplication(mAppThread);
        } catch (RemoteException ex) {
            // Ignore
        }
        .....
        try {
            mInstrumentation = new Instrumentation();
            ContextImpl context = ContextImpl.createAppContext(
                    this, getSystemContext().mPackageInfo);
            mInitialApplication = context.mPackageInfo.makeApplication(true, null);
            mInitialApplication.onCreate();
        } catch (Exception e) {
            throw new RuntimeException(
                    "Unable to instantiate Application():" + e.toString(), e);
        }
    }
    

    获取到 AmS 的代理对象,通过 attachApplication() 方法把 mAppThread 当作参数传过去即可。是不是很简单,仅仅两行代码就搞定了,我们再来看看 attachApplication() 的实现。

    public void attachApplication(IApplicationThread app) throws RemoteException
    {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(app.asBinder());
        mRemote.transact(ATTACH_APPLICATION_TRANSACTION, data, reply, 0);
        reply.readException();
        data.recycle();
        reply.recycle();
    }
    

    经典的 Binder 调用方式,这部分上一篇文章已经介绍过,这样会最终调用到 AmS 那边的 attachApplication() 方法:

    @Override
    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        switch (code) {
            ......
            case ATTACH_APPLICATION_TRANSACTION: {
                data.enforceInterface(IActivityManager.descriptor);
                IApplicationThread app = ApplicationThreadNative.asInterface(
                        data.readStrongBinder());
                if (app != null) {
                    attachApplication(app);
                }
                reply.writeNoException();
                return true;
            }
            ......
        }
    }
    
    @Override
    public void attachApplication(IApplicationThread thread) {
        synchronized (this) {
            int callingPid = Binder.getCallingPid();
            final long origId = Binder.clearCallingIdentity();
            attachApplicationLocked(thread, callingPid);
            Binder.restoreCallingIdentity(origId);
        }
    }
    

    AmS 收到 thread 对象后保存下来,之后就可以直接调用应用进程中的相应方法。讲到这里,引言中第一问题已经有了答案,但真正的原理还是没有说明白,比如,为什么把 Binder 对象传递过去,对端就能使用它调用自己的方法,这和在 ServiceManager 注册的服务有什么区别?下面我重点介绍其中的原理。

    二、Binder 对象在进程中传递过程

    2.1 匿名 Binder 的概念

    Binder 服务分为两种:实名服务匿名服务
    区别:
    实名服务:能够通过 ServiceManager 查询到,比如 Android 中的实名服务都是系统提供的如AmS、WmS、PmS;
    匿名服务:普通应用开发的 Binder 服务,只能是匿名服务,比如我们刚刚介绍的 ApplicationThread。
    这就回答了上一章最后说的那个问题,其实它们没有本质的区别,只不过实名服务在 ServiceManager 中注册过,别的进程可以查询使用,而匿名服务只有创建的人知道,除非你暴露给别的进程,否则它们无法访问。最终对 Binder 驱动而言,它们都是同一种东西。

    2.2 Binder 对象的传递过程

    上一章介绍应用进程和 AmS 之间的双工通信就是通过attachApplication() 方法把 ApplicationThread 传递给 AmS 进程:

    public void attachApplication(IApplicationThread app) throws RemoteException
    {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(app.asBinder());
        mRemote.transact(ATTACH_APPLICATION_TRANSACTION, data, reply, 0);
        reply.readException();
        data.recycle();
        reply.recycle();
    }
    

    而这个IApplicationThread app对象本质是一个 Binder 对象,为什么一个简单的 Binder 对象传递过去,对方就能直接调用自己的方法呢?这其中的原理是什么?
    这一块是本文的重点,我们就从这个 Binder 对象传递过程讲起。
    IApplicationThread app对象是通过 Parcel.java 中的 writeStrongBinder() 方法打包到 Parcel 中的,我们来看这个方法的实现:

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

    Java 层的代码很简单,直接调用了 native 层的方法,继续往下看:

    status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
    {
        return flatten_binder(ProcessState::self(), val, this);
    }
    

    native 层的 writeStrongBinder() 也很简单,调用了 flatten_binder() 方法,继续往下跟:

    status_t flatten_binder(const sp<ProcessState>& /*proc*/,
        const sp<IBinder>& binder, Parcel* out)
    {
        flat_binder_object obj;
        ...
        if (binder != NULL) {
            IBinder *local = binder->localBinder();
            if (!local) {
                BpBinder *proxy = binder->remoteBinder();
                if (proxy == NULL) {
                    ALOGE("null proxy");
                }
                const int32_t handle = proxy ? proxy->handle() : 0;
                obj.type = BINDER_TYPE_HANDLE;
                obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
                obj.handle = handle;
                obj.cookie = 0;
            } else {
                obj.type = BINDER_TYPE_BINDER;
                obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
                obj.cookie = reinterpret_cast<uintptr_t>(local);
            }
        } else {
            obj.type = BINDER_TYPE_BINDER;
            obj.binder = 0;
            obj.cookie = 0;
        }
    
        return finish_flatten_binder(binder, obj, out);
    }
    

    先来看看 local 是什么,其实,它就是用来判断当前 binder 对象是本地BBinder 对象还是代理 BpBinder 对象。
    来看具体定义:

    class IBinder : public virtual RefBase
    {
        ...
        virtual BBinder*        localBinder();
        virtual BpBinder*       remoteBinder();
        ...
    }
    

    localBinder() 和 remoteBinder() 是 IBinder 中的两个虚方法,而BBinder 和 BpBinder 都继承 IBinder:

    • frameworks/native/libs/binder/Binder.cpp
    BBinder* IBinder::localBinder()
    {
        return NULL;
    }
    
    BpBinder* IBinder::remoteBinder()
    {
        return NULL;
    }
    

    默认两个方法都返回 NULL,但 BBinder 重写了其中 localBinder() 方法,返回 BBinder 对象:

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

    BpBinder 重写了其中 remoteBinder() 方法,返回 BpBinder 对象:

    • frameworks/native/libs/binder/BpBinder.cpp
    BpBinder* BpBinder::remoteBinder()
    {
        return this;
    }
    

    所以 flatten_binder() 方法中通过 IBinder *local = binder->localBinder() 获得 local 对象,再根据它是否为空判断当前传递的 binder 对象是本地 BBinder 还是代理 BpBinder,因为只有 BBinder 对象 localBinder() 方法的返回值不为 NULL

    回过头再开看 flatten_binder() 方法:

    status_t flatten_binder(const sp<ProcessState>& /*proc*/,
        const sp<IBinder>& binder, Parcel* out)
    {
        flat_binder_object obj;
        ...
        if (binder != NULL) {
            IBinder *local = binder->localBinder();
            if (!local) {
                BpBinder *proxy = binder->remoteBinder();
                if (proxy == NULL) {
                    ALOGE("null proxy");
                }
                const int32_t handle = proxy ? proxy->handle() : 0;
                obj.type = BINDER_TYPE_HANDLE;
                obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
                obj.handle = handle;
                obj.cookie = 0;
            } else {
                obj.type = BINDER_TYPE_BINDER;
                obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
                obj.cookie = reinterpret_cast<uintptr_t>(local);
            }
        } else {
            ...
        }
        return finish_flatten_binder(binder, obj, out);
    }
    

    根据 local 是否为空分了两种情况:

    • BINDER_TYPE_HANDLE
    • BINDER_TYPE_BINDER

    我们传下来的 ApplicationThread 是 Binder 本地对象(为什么说ApplicationThread 是 Binder 本地对象我们在后面再讲),故 local 不为 NULL, 所以走下面的分支:

    obj.type = BINDER_TYPE_BINDER;
    obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
    obj.cookie = reinterpret_cast<uintptr_t>(local);
    

    只有 type 为BINDER_TYPE_BINDER时才会把 binder 对象打包到 flat_binder_object中,传递给 Binder 驱动,当 type 为 BINDER_TYPE_HANDLE 时,只是传递的一个整型句柄 handle, 真正的 binder 对象并没有传递下去,这从代码中可以看出:obj.binder = 0

    所以,“打扁”的意思就是把 binder 对象整理成 flat_binder_object 变量,如果打扁的是 binder 实体,那么 flat_binder_object 用 cookie 域记录 binder 实体的指针,即 BBinder 指针;而如果打扁的是 binder 代理,那么 flat_binder_object 用 handle 域记录的 binder 代理的句柄值。

    接下来就调用 finish_flatten_binder() 方法把flat_binder_object写入 parcel 后发给 Binder 驱动, 发送的过程在上一篇文章已经介绍,这里再说下 IPCThreadState::writeTransactionData() 方法,它会先把 Parcel 数据整理成一个 binder_transaction_data 数据:

    status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
            int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
    {
        binder_transaction_data tr;
            ......
            // 这部分是待传递数据
            tr.data_size = data.ipcDataSize();
            tr.data.ptr.buffer = data.ipcData();
            // 这部分是扁平化的binder对象在数据中的具体位置
            tr.offsets_size = data.ipcObjectsCount()*sizeof(size_t);
            tr.data.ptr.offsets = data.ipcObjects();
            ......
        mOut.write(&tr, sizeof(tr));
        ......
    }
    

    所以,当binder_transaction_data传递到 Binder 驱动层后,驱动层可以准确地分析出数据中到底有多少binder对象,并分别进行处理产生出合适的红黑树节点。此时,如果产生的红黑树节点是 binder_node 的话, binder_node 的 cookie 域会被赋值成flat_binder_object所携带的 cookie 值,也就是用户态的 BBinder 地址值。
    这个新生成的 binder_node 节点被插入红黑树后,会一直严阵以待,以后当它成为另外某次传输动作的目标节点时,它的 cookie 域就派上用场了(这里的成为另外某次传输动作的目标节点可以理解为:AmS 拿到 ApplicationThread 的代理对象后,想要反过来调用应用进程的方法,此时刚刚传入的 BBinder 对象就成为目标节点),此时 cookie 值会被反映到用户态,于是用户态就拿到了 BBinder 对象。

    总结:

    • 1、应用进程获取 AmS 的代理对象,把 ApplicationThread 传递过去,这个 ApplicationThread 继承 Binder,可以理解为 binder 实体对象;
    • 2、通过 Parcel 的 writeStrongBinder() 方法,把传入的 ApplicationThread 对象,并判断local 是否为空,如果是 binder 代理对象,flat_binder_object用 handle 域记录的 binder 代理的句柄值,并把 type 设为 BINDER_TYPE_HANDLE;如果是 binder 实体对象,flat_binder_object用 cookie 域记录 binder 实体的指针,即BBinder指针;
    • 3、经过 Binder 驱动时,驱动会根据传入的数据生成 binder node,以后当它成为另外某次传输动作的目标节点时,用户态就能根据生成的 binder node 拿到 BBinder 对象,这就解释了开始我们的疑问:为什么把 Binder 对象传递给 AmS,AmS 就能使用它调用自己的方法?是因为传递 BBinder 对象过程中,Binder 驱动会生成一一对应的节点,对端进程根据节点自然可以找到自己。

    三、JNI 层 Binder 内容介绍

    3.1 Java 和 Native 层 Binder 对象转化

    Android 上层都是用 Java 写的,但是 Binder 驱动是 C 实现,它们之间互相传递对象必然要经过 JNI 层,之前说到应用进程传给 AmS 的 ApplicationThread 是 Binder 本地对象,并没有说其中的原因,其实在 JNI 层有一个转化过程。
    先来看Java 层 Binder.java 的构造方法:

    public Binder() {
        init();
        ......
    }
    
    private native final void init();
    

    init() 是 native 方法,我们继续往下看:

    • frameworks/base/core/jni/android_util_Binder.cpp
    static void android_os_Binder_init(JNIEnv* env, jobject obj)
    {
        JavaBBinderHolder* jbh = new JavaBBinderHolder();
        if (jbh == NULL) {
            jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
            return;
        }
        ALOGV("Java Binder %p: acquiring first ref on holder %p", obj, jbh);
        jbh->incStrong((void*)android_os_Binder_init);
        //这里很关键,请注意是 gBinderOffsets
        env->SetLongField(obj, gBinderOffsets.mObject, (jlong)jbh);
    }
    

    这个方法里面创建一个 JavaBBinderHolder 对象,它其实会持有一个 JavaBBinder 对象,而
    JavaBBinder 继承 BBinder :

    class JavaBBinderHolder : public RefBase
    {
    public:
        sp<JavaBBinder> get(JNIEnv* env, jobject obj)
        {
            AutoMutex _l(mLock);
            sp<JavaBBinder> b = mBinder.promote();
            if (b == NULL) {
                b = new JavaBBinder(env, obj);
                mBinder = b;
                ALOGV("Creating JavaBinder %p (refs %p) for Object %p, weakCount=%" PRId32 "\n",
                     b.get(), b->getWeakRefs(), obj, b->getWeakRefs()->getWeakCount());
            }
    
            return b;
        }
    
        sp<JavaBBinder> getExisting()
        {
            AutoMutex _l(mLock);
            return mBinder.promote();
        }
    
    private:
        Mutex           mLock;
        wp<JavaBBinder> mBinder;
    };
    
    class JavaBBinder : public BBinder
    {
    public:
        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);
        }
    ......
    }
    

    我们回过头来看 Java 层向下传输 ApplicationThread 的方法:

    public void attachApplication(IApplicationThread app) throws RemoteException
    {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(app.asBinder());
        mRemote.transact(ATTACH_APPLICATION_TRANSACTION, data, reply, 0);
        reply.readException();
        data.recycle();
        reply.recycle();
    }
    

    ApplicationThread 对象是通过writeStrongBinder() 写入 Parcel 的,再看它是native 方法,直接看它的 JNI 实现:

    • frameworks/base/core/jni/android_os_Parcel.cpp
    static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
    {
        Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
        if (parcel != NULL) {
            const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
            ......
        }
    }
    

    在调用真正的 Parcel.cpp 的 writeStrongBinder() 方法之前,通过 ibinderForJavaObject() 把 Java 层的对象转化为 native 层的 IBinder 对象,

    • ibinderForJavaObject(): 将 Java 层对象转换为Native 层的 JavaBBinder 对象
    • javaObjectForIbinder(): 将 Native 层对象转换为Java 层对象
      来看 ibinderForJavaObject() 的实现:
    sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
    {
        ......
        // 刚刚 init() 方法中,设置的值为 gBinderOffsets,所以走的是这个分支,通过上面介绍,这边会返回一个 JavaBBinder 对象
        if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
            JavaBBinderHolder* jbh = (JavaBBinderHolder*)
                env->GetLongField(obj, gBinderOffsets.mObject);
            return jbh != NULL ? jbh->get(env, obj) : NULL;
        }
    
        if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
            return (IBinder*)
                env->GetLongField(obj, gBinderProxyOffsets.mObject);
        }
        ......
        return NULL;
    }
    

    刚刚 Binder.java 调用的native init() 方法中,设置的值为 gBinderOffsets,所以走的是上面的 if 分支,通过上面介绍,这里会返回一个 JavaBBinder 对象。

    同理,javaObjectForIBinder()方法就是 Java 层从 Parcel 中读取 Binder 对象时调用的,如下:

    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;
    }
    

    到此,引言中提到的第四个问题 “Java 和 JNI 层在整个 Binder 通信中扮演的角色和作用?”已经阐述,其实 JNI 中还有很多内容,我们这里就不一一介绍了。

    四、相同进程中 Binder 通信过程

    4.1 asBinder() 方法的作用

    public abstract class ActivityManagerNative extends Binder implements IActivityManager {
        /**
         * Cast a Binder object into an activity manager interface, generating
         * a proxy if needed.
         */
        static public IActivityManager asInterface(IBinder obj) {
            if (obj == null) {
                return null;
            }
            IActivityManager in =
                (IActivityManager)obj.queryLocalInterface(descriptor);
            if (in != null) {
                Log.v(TAG, " queryLocalInterface return not null in = " + in);
                return in;
            }
            Log.v(TAG, "Activitymanager  new ActivityManagerProxy() ");
            return new ActivityManagerProxy(obj);
        }
    
        public IBinder asBinder() {
            return this;
        }
        ......
    }
    
    class ActivityManagerProxy implements IActivityManager {
        public ActivityManagerProxy(IBinder remote) {
            mRemote = remote;
        }
    
        public IBinder asBinder() {
            return mRemote;
        }
        ......
    }
    

    本地做了一个验证,WindwoManagerService.java 和 Settings 应用分别去通过 Binder 去获得 AmS 对象,代码如下:

    IBinder b = ServiceManager.getService("activity");
    IActivityManager am = ActivityManagerNative.asInterface(b);
    Log.d(TAG, " WindowManagerService binder = " + b + "  service = " + am + " old service = " + mActivityManager);
    

    WmS 中打印的 log 如下:

    01-07 06:59:23.283  1424  1520 V  binder:  queryLocalInterface return not null in = com.android.server.am.ActivityManagerService@e7c84de
    01-07 06:59:23.283  1424  1520 D  binder:  WindowManagerService binder = com.android.server.am.ActivityManagerService@e7c84de  service = com.android.server.am.ActivityManagerService@e7c84de
    

    Settings 打印 log 如下:

    01-08 08:10:31.059  3179  3179 V  binder: Activitymanager  new ActivityManagerProxy() 
    01-08 08:10:31.059  3179  3179 D  binder:  Settings binder = android.os.BinderProxy@ceb71a0  service = android.app.ActivityManagerProxy@e04a9aa
    

    结论:可以看出,因为 WmS 和 AmS 都属于 system_server 进程,所以返回的直接是 ActivityManagerService 本身对象,而 Settings 属于应用进程,返回的是 ActivityManagerProxy 代理对象。

    为什么会有这种现象呢,可以看出 Java 层代码两者并无不同,区别就是 JNI 和 Binder 驱动对两者 type 类型的处理不一样,JNI 刚刚已经介绍过,Binder 驱动会判断传来的 IBinder 类型为BINDER_TYPE_HANDLE时,会判断该 IBinder 的实体被定义的进程(也就是该 IBinder 代表的 server 被定义的进程)与目标进程(也即 IBinder被传递的目标进程)是否相同,如果相同,则将该IBinder type 转化BINDER_TYPE_BINDER,同时使其变为 IBinder 本地对象的引用

    static void binder_transaction(struct binder_proc *proc,
                       struct binder_thread *thread,
                       struct binder_transaction_data *tr, int reply)
    {
        struct binder_transaction *t;
        for (; offp < off_end; offp++) {
            .....
            case BINDER_TYPE_BINDER:
            case BINDER_TYPE_WEAK_BINDER: {
                ........
            if (fp->type == BINDER_TYPE_BINDER)
                fp->type = BINDER_TYPE_HANDLE;
            else
                fp->type = BINDER_TYPE_WEAK_HANDLE;
            fp->binder = 0;
            fp->handle = ref->desc;
            fp->cookie = 0;
            binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,
                       &thread->todo);
        
        } break;
        case BINDER_TYPE_HANDLE:
        case BINDER_TYPE_WEAK_HANDLE: {
            ......
            if (ref->node->proc == target_proc) {
                if (fp->type == BINDER_TYPE_HANDLE)
                    fp->type = BINDER_TYPE_BINDER;
                else
                    fp->type = BINDER_TYPE_WEAK_BINDER;
                fp->binder = ref->node->ptr;
                fp->cookie = ref->node->cookie;
                binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL);
                ......
            } else {
                struct binder_ref *new_ref;
                new_ref = binder_get_ref_for_node(target_proc, ref->node);
                if (new_ref == NULL) {
                    return_error = BR_FAILED_REPLY;
                    goto err_binder_get_ref_for_node_failed;
                }
                fp->binder = 0;
                fp->handle = new_ref->desc;
                fp->cookie = 0;
                binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL);
                         ......
        } break;
    }
    

    参考:
    IBinder对象在进程间传递的形式(一)
    红茶一杯话Binder(ServiceManager篇)
    Android Binder跨进程与非跨进程的传输异同源码分析
    深入分析Android Binder 驱动

    相关文章

      网友评论

          本文标题:Binder 进程间通信机制详解(Java 和 JNI 篇)

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