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

通过上一篇的介绍,大家应该对 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 驱动
魅族内核团队 Android Binder

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容