猪小花1号

个人签名

282篇博客

理解Binder通信原理及常见问题6

猪小花1号2018-08-30 09:58

作者:李尚


首先看一下关键点1 ,这里将内核数据映射到一个用户空间的Parcel对象中去,之后在调用目标Service的transact函数,进而调用他的onTrasanct函数 , 通过前面的分析知道,Java层Binder在注册时候,最终注册的是JavaBBinder对象,看一下它的onTrasanct函数:

virtual status_t onTransact(
        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0)
    {
        JNIEnv* env = javavm_to_jnienv(mVM);
        IPCThreadState* thread_state = IPCThreadState::self();
        const int strict_policy_before = thread_state->getStrictModePolicy();
        thread_state->setLastTransactionBinderFlags(flags);
        ..
        jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
            code, (int32_t)&data, (int32_t)reply, flags);
         ..
        return res != JNI_FALSE ? NO_ERROR : UNKNOWN_TRANSACTION;
    }

关键代码只有一句:env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact, code, (int32_t)&data, (int32_t)reply, flags),其实就是调用Binder.java的execTransact函数,最终调用BBinder实例化类的onTransact

private boolean execTransact(int code, int dataObj, int replyObj,
            int flags) {
        Parcel data = Parcel.obtain(dataObj);
        Parcel reply = Parcel.obtain(replyObj);
        boolean res;
        try {
            res = onTransact(code, data, reply, flags);
        } ...
        reply.recycle();
        data.recycle();
        return res;
    }}

对于AMS而bindService对应的操作如下

public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
    throws RemoteException {
    。。
    case BIND_SERVICE_TRANSACTION: {
    data.enforceInterface(IActivityManager.descriptor);
    IBinder b = data.readStrongBinder();
    IApplicationThread app = ApplicationThreadNative.asInterface(b);
    IBinder token = data.readStrongBinder();
    Intent service = Intent.CREATOR.createFromParcel(data);
    String resolvedType = data.readString();
    b = data.readStrongBinder();
    int fl = data.readInt();
    int userId = data.readInt();
    IServiceConnection conn = IServiceConnection.Stub.asInterface(b);
    int res = bindService(app, token, service, resolvedType, conn, fl, userId);
    reply.writeNoException();
    reply.writeInt(res);
    return true;
}

b = data.readStrongBinder()会先读取Binder对象,这里会调用本地函数nativeReadStrongBinder(mNativePtr),mNativePtr就是Native层Parcel的首地址:

public final IBinder readStrongBinder() {
    return nativeReadStrongBinder(mNativePtr);
}

nativeReadStrongBinder(mNativePtr)会将本地Binder对象转化成Java层对象,其实就是将传输的InnerConnection读取出来,不过由于Binder驱动将BINDER_TYPE_BINDER转换成了BINDER_TYPE_HANDLE,对于AMS其实是实例化BinderProxy

static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jint nativePtr)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {

        // /parcel->readStrongBinder() 其实就会创建BpBInder、
        return javaObjectForIBinder(env, parcel->readStrongBinder());
    }
    return NULL;
}

首先会利用Parcel.cpp的parcel->readStrongBinder(),读取binder对象,这里会根据flat_binder_object的类型,分别进行BBinder与BpBinder映射,如果是Binder实体直接将指针赋值out,如果不是,则根据handle获取或者新建BpBinder返回给out。

status_t unflatten_binder(const sp<ProcessState>& proc,
    const Parcel& in, sp<IBinder>* out)
{
    const flat_binder_object* flat = in.readObject(false);

    if (flat) {
        switch (flat->type) {
            case BINDER_TYPE_BINDER:
                *out = static_cast<IBinder*>(flat->cookie);
                return finish_unflatten_binder(NULL, *flat, in);
            case BINDER_TYPE_HANDLE:
                *out = proc->getStrongProxyForHandle(flat->handle);
                return finish_unflatten_binder(
                    static_cast<BpBinder*>(out->get()), *flat, in);
        }        
    }
    return BAD_TYPE;
}

之后会牵扯一个将native binder转换成java层Binder的操作,javaObjectForIBinder,这个函数很关键,是理解Java层BinderProxy或者BBinder实体的关键:

jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
    if (val == NULL) return NULL;
    <!--关键点1-->
    if (val->checkSubclass(&gBinderOffsets)) {
        jobject object = static_cast<JavaBBinder*>(val.get())->object();
        return object;
    }
    AutoMutex _l(mProxyLock);
    <!--关键点2-->
    jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
    if (object != NULL) {
        android_atomic_dec(&gNumProxyRefs);
        val->detachObject(&gBinderProxyOffsets);
        env->DeleteGlobalRef(object);
    }
    <!--关键点3-->
    object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
    if (object != NULL) {
        env->SetIntField(object, gBinderProxyOffsets.mObject, (int)val.get());
        val->incStrong((void*)javaObjectForIBinder);
        jobject refObject = env->NewGlobalRef(
                env->GetObjectField(object, gBinderProxyOffsets.mSelf));
        val->attachObject(&gBinderProxyOffsets, refObject,
                jnienv_to_javavm(env), proxy_cleanup);
        sp<DeathRecipientList> drl = new DeathRecipientList;
        drl->incStrong((void*)javaObjectForIBinder);
        env->SetIntField(object, gBinderProxyOffsets.mOrgue, reinterpret_cast<jint>(drl.get()));
        android_atomic_inc(&gNumProxyRefs);
        incRefsCreated(env);
    }
    return object;
}

先看关键点1, checkSubclass默认返回false,但是JavaBBinder,该类对此函数进行了覆盖,如果是JavaBBinder,就会返回true,但入股是BpBinder,则会返回false,

bool    checkSubclass(const void* subclassID) const
{
    return subclassID == &gBinderOffsets;
}

再看关键点2,如果是BpBinder,则需要首先在gBinderProxyOffsets中查找,是不是已经新建了Java层代理BinderProxy对象,如果没有,则新建即可,如果新建就看是否还存在缓存有效的BinderProxy。最后看关键点3 :

env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor)

其实就是新建BinderProxy对象,Java层的BinderProxy都是Native新建的,Java层并没有BinderProxy的新建入口,之后,再通过IServiceConnection.Stub.asInterface(b)进行转换,实例化一个IServiceConnection.Proxy代理对,该对象在Binder通信的基础上封装了业务逻辑,其实就是一些具体的操作。

 public static XXXAidlInterface asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof XXXAidlInterface))) {
                return ((XXXAidlInterface) iin);
            }
            return new XXXAidlInterface.Stub.Proxy(obj);
        }

这里注意一点杜宇BinderProxy,obj.queryLocalInterface(DESCRIPTOR)返回为null,对于Binder实体,返回的是Binder自身,这样就能为上层区分出是生成代理还是存根自身,整体对象转换流程如下:

到这里分析了一半,Java层命令及回调Binder入口已经被传递给AMS,AMS之后需要负责启动Service,并通过回调入口为Client绑定服务,跟踪到AMS源码


public int bindService(IApplicationThread caller, IBinder token,
        Intent service, String resolvedType,
        IServiceConnection connection, int flags, int userId) {
    ...
    synchronized(this) {
        return mServices.bindServiceLocked(caller, token, service, resolvedType,
                connection, flags, userId);
    }
}

最后调用ActiveService的bindServiceLocked,这里会分三中情况,


  • Service已经经启动
  • Service未启动,但是进程已经启动
  • Service与进程君未启动


不过这里只讨论比较经典的Service未启动, Service未启动,但是进程已经启动的情况,关键代码如下


 int bindServiceLocked(IApplicationThread caller, IBinder token,
            Intent service, String resolvedType,
            IServiceConnection connection, int flags, int userId) {

        try {
            .。。

            if ((flags&Context.BIND_AUTO_CREATE) != 0) {
                s.lastActivity = SystemClock.uptimeMillis();
          <!--关键点1-->
                if (bringUpServiceLocked(s, service.getFlags(), false) != null) {
                    return 0;
                }
            }
          <!--关键点2-->
           ..
           requestServiceBindingLocked(s, b.intent, false);
           ..
        }
}

关键点1其实就是启动Service,主要是通过ApplicationThread的binder通信通知App端启动Service,这个流程同Activity启动一样。关键点2是Service特有的:requestServiceBindingLocked,这个命令是告诉APP端:“在Service启动后需要向AMS发消息,之后AMS才能向其他需要绑定该Service的Client发送反馈”。


AMS端
private final boolean requestServiceBindingLocked(ServiceRecord r,
        IntentBindRecord i, boolean rebind) {
    if ((!i.requested || rebind) && i.apps.size() > 0) {
       ..
          r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
       ..
      }        }
    return true;
}

 APP端
 private void handleBindService(BindServiceData data) {
    Service s = mServices.get(data.token);
    ...
    if (!data.rebind) {
        IBinder binder = s.onBind(data.intent);
        ActivityManagerNative.getDefault().publishService(
                data.token, data.intent, binder);
    }
}

ActivityManagerNative.getDefault().publishService会将启动的Binder服务实体传递给AMS,上面分析过Binder实体传输,这里的原理是一样的,AMS端在传输结束后,会获得Service端服务实体的引用,这个时候,就能通过最初的InnerConnection的回调将这个服务传递给Client端。Binder实体与引用的整体流程图如下:

如果要深究Activity的bindService流程,可以按以下几步来分析


  • 1、Activity调用bindService:通过Binder通知ActivityManagerService,要启动哪个Service
  • 2、ActivityManagerService创建ServiceRecord,并利用ApplicationThreadProxy回调,通知APP新建并启动Service启动起来
  • 3、ActivityManagerService把Service启动起来后,继续通过ApplicationThreadProxy,通知APP,bindService,其实就是让Service返回一个Binder对象给ActivityManagerService,以便AMS传递给Client
  • 4、ActivityManagerService把从Service处得到这个Binder对象传给Activity,这里是通过IServiceConnection binder实现。
  • 5、Activity被唤醒后通过Binder Stub的asInterface函数将Binder转换为代理Proxy,完成业务代理的转换,之后就能利用Proxy进行通信了。



相关阅读:

理解Binder通信原理及常见问题1

理解Binder通信原理及常见问题2

理解Binder通信原理及常见问题3

理解Binder通信原理及常见问题4

理解Binder通信原理及常见问题5

理解Binder通信原理及常见问题6

https://www.163yun.com/gift

本文来自网易实践者社区,经作者李尚授权发布。