美文网首页源码解析相关Android日记Android进阶+实战
听说你Binder机制学的不错,来面试下这几个问题(三)

听说你Binder机制学的不错,来面试下这几个问题(三)

作者: 看书的小蜗牛 | 来源:发表于2017-03-15 19:14 被阅读1546次

    很多文章将Binder框架定义了四个角色:Server,Client,ServiceManager、以及Binder驱动,但这容易将人引导到歧途:好像所有的Binder服务都需要去ServiceManager去注册才能使用,其实不是这样。例如,平时APP开发通过bindService启动的服务,以及有些自己定义的AIDL远程调用,都不一定都ServiceManager注册这条路,个人理解:ServiceManager主要功能是:管理系统服务,比如AMS、WMS、PKMS服务等,而APP通过的bindService启动的Binder服务其实是由SystemServer的ActivityManagerService负责管理。这篇主要关注Android APP Java层Binder通信一些奇葩点:

    听说你Binder机制学的不错,来解决下这几个问题(一)
    听说你Binder机制学的不错,来看看这几个问题(二)
    听说你Binder机制学的不错,来看看这几个问题(三)

    • ServiceManager addService的限制(并非服务都能使用ServiceManager的addService)
    • bindService启动Service与Binder服务实体的流程
    • Java层Binder实体与与BinderProxy是如何实例化及使用的,与Native层的关系是怎样的
    • Parcel readStrongBinder与writeStrongBinder的原理(首先两端知晓)

    ServiceManager addService的限制--并非所有服务都能通过addService添加到ServiceManager

    ServiceManager其实主要的面向对象是系统服务,大部分系统服务都是由SystemServer进程总添加到ServiceManager中去的,在通过ServiceManager添加服务的时候,是有些权限校验的,源码如下:

    int svc_can_register(unsigned uid, uint16_t *name)
     {
        unsigned n;
        // 谁有权限add_service 0进程,或者 AID_SYSTEM进程
        if ((uid == 0) || (uid == AID_SYSTEM))
            return 1;
         for (n = 0; n < sizeof(allowed) / sizeof(allowed[0]); n++)
            if ((uid == allowed[n].uid) && str16eq(name, allowed[n].name))
                return 1;
        return 0;
    }
    

    可以看到 (uid == 0) 或者 (uid == AID_SYSTEM)的进程都是可以添加服务的,uid=0,代表root用户,而uid=AID_SYSTEM,代表系统用户 。或者是一些特殊的配置进程。SystemServer进程在被Zygote创建的时候,就被分配了UID 是AID_SYSTEM(1000),

    private static boolean startSystemServer()
            throws MethodAndArgsCaller, RuntimeException {
        /* Hardcoded command line to start the system server */
        String args[] = {
            "--setuid=1000",
            "--setgid=1000",
            "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003,3006,3007",
            "--capabilities=130104352,130104352",
            "--runtime-init",
            "--nice-name=system_server",
            "com.android.server.SystemServer",
        };
    

    Android每个APP的UID,都是不同的,用了Linux的UID那一套,但是没完全沿用,这里不探讨,总之,普通的进程是没有权限注册到ServiceManager中的,那么APP平时通过bindService启动的服务怎么注册于查询的呢?接管这个任务的就是SystemServer的ActivityManagerService

    bindService启动Service与Binder服务实体的流程 (ActivityManagerService)

    • bindService的框架
    • binder服务实例化与转化
    • 业务逻辑的唤醒
    • 请求代理的转化与唤醒

    bindService比startService多了一套Binder通信,其余的流程基本相同,而startService的流程,同startActivity差不多,四大组件的启动流程这里不做分析点,主要看bindService中C/S通信的建立流程,在这个流程里面,APP与服务端互为C/S的特性更明显,在APP开发的时候,binder服务是通过Service来启动的。Service的启动方式有两种startService,与bindService,这里只考虑后者,另外启动的binder服务也分为两种情况:第一种,client同server位于同一进程,可以看做内部服务,第二种,Client与Server跨进程,即使是位于同一个APP,第一桶可以不用AIDL来编写,但是第二种必须通过AIDL实现跨进程通信,看一个最简单的AIDL例子,首先在定义一个aidl接口:

    IMyAidlInterface.aidl

    interface IMyAidlInterface {
    void communicate(int count);
    }

    IMyAidlInterface.aidl定义了通信的借口,通过build之后,构建工具会自动为IMyAidlInterface.aidl生成一些辅助类,这些辅助类主要作用是生成Binder通信协议框架,必须保证两方通信需要指令相同,才能解析通信内容。天王盖地虎,宝塔镇河妖。Java层Binder的对应关系Binder与BinderProxy从这里可以看出,binder采用了代理模式 stub与proxy对应,使用aidl实现的服务时候,Client如果想要获得Binder实体的代理可以通过asInterface来处理,比如如果在同一进程就是实体,不在就新建代理对象

        public interface IMyAidlInterface extends android.os.IInterface {
    
        public static abstract class Stub extends android.os.Binder implements com.snail.labaffinity.IMyAidlInterface {
            private static final java.lang.String DESCRIPTOR = "com.snail.labaffinity.IMyAidlInterface";
    
            public Stub() {
                this.attachInterface(this, DESCRIPTOR);
            }
    
            public static com.snail.labaffinity.IMyAidlInterface asInterface(android.os.IBinder obj) {
                if ((obj == null)) {
                    return null;
                }
                android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
                if (((iin != null) && (iin instanceof com.snail.labaffinity.IMyAidlInterface))) {
                    return ((com.snail.labaffinity.IMyAidlInterface) iin);
                }
                return new com.snail.labaffinity.IMyAidlInterface.Stub.Proxy(obj);
            }
    
            @Override
            public android.os.IBinder asBinder() {
                return this;
            }
    
            @Override
            public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
                switch (code) {
                    case INTERFACE_TRANSACTION: {
                        reply.writeString(DESCRIPTOR);
                        return true;
                    }
                    case TRANSACTION_communicate: {
                        data.enforceInterface(DESCRIPTOR);
                        int _arg0;
                        _arg0 = data.readInt();
                        this.communicate(_arg0);
                        reply.writeNoException();
                        return true;
                    }
                }
                return super.onTransact(code, data, reply, flags);
            }
    
            private static class Proxy implements com.snail.labaffinity.IMyAidlInterface {
                private android.os.IBinder mRemote;
    
                Proxy(android.os.IBinder remote) {
                    mRemote = remote;
                }
    
                @Override
                public android.os.IBinder asBinder() {
                    return mRemote;
                }
    
                public java.lang.String getInterfaceDescriptor() {
                    return DESCRIPTOR;
                }
    
                @Override
                public void communicate(int count) throws android.os.RemoteException {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        _data.writeInt(count);
                        mRemote.transact(Stub.TRANSACTION_communicate, _data, _reply, 0);
                        _reply.readException();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                }
            }
    
            static final int TRANSACTION_communicate = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        }
    
        public void communicate(int count) throws android.os.RemoteException;
    }
    

    启动Binder服务端封装Service,之所以成为封装Service,是因为Service对于Binder实体的最大作用是个作为新建服务的入口:

    public class AidlService extends Service {
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return new BBinderService();
        }
    
        public class BBinderService extends IMyAidlInterface.Stub {
    
            @Override
            public void communicate(int count) throws RemoteException {
            }
        }
    }
    

    而启动的入口:

    public class MainActivity extends AppCompatActivity {
        ...
       void bind(){
        Intent intent = createExplicitFromImplicitIntent(MainActivity.this, new Intent("com.snail.labaffinity.service.AidlService"));
        bindService(intent, new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                IMyAidlInterface  iMyAidlInterface = IMyAidlInterface.Stub.asInterface(iBinder);
            }
    
            @Override
            public void onServiceDisconnected(ComponentName componentName) {
            }
        }, Context.BIND_AUTO_CREATE);
        }
     }
    

    以上四个部分就组成了AIDL跨进程服务的基本组件,现在从ActivitybindService入口开始分析:bindService大部分的流程与startActivity类似,其实都是通过AMS启动组件,这里只将一些不同的地方,Activity启动只需要Intent就可以了,而Service的bind需要一个ServiceConnection对象,这个对象其实是为了AMS端在启动Service后回调用的,ServiceConnection是个接口,其实例在ContextImpl的:

    private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags,
                                      UserHandle user) {
        IServiceConnection sd;
        if (conn == null) {
            throw new IllegalArgumentException("connection is null");
        }
        if (mPackageInfo != null) {
            sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
                    mMainThread.getHandler(), flags);
        } else {
            throw new RuntimeException("Not supported in system context");
        }
        validateServiceIntent(service);
        try {
            IBinder token = getActivityToken();
            if (token == null && (flags & BIND_AUTO_CREATE) == 0 && mPackageInfo != null
                    && mPackageInfo.getApplicationInfo().targetSdkVersion
                    < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                flags |= BIND_WAIVE_PRIORITY;
            }
            service.prepareToLeaveProcess();
            int res = ActivityManagerNative.getDefault().bindService(
                    mMainThread.getApplicationThread(), getActivityToken(), service,
                    service.resolveTypeIfNeeded(getContentResolver()),
                    sd, flags, getOpPackageName(), user.getIdentifier());
            if (res < 0) {
                throw new SecurityException(
                        "Not allowed to bind to service " + service);
            }
            return res != 0;
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
    }
    

    mPackageInfo是一个LoadApk类,通过它的getServiceDispatcher获得一个IServiceConnection对象,这个对象一个Binder实体,看一下具体原理

    public final IServiceConnection getServiceDispatcher(ServiceConnection c,
            Context context, Handler handler, int flags) {
        synchronized (mServices) {
            LoadedApk.ServiceDispatcher sd = null;
            ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
            if (map != null) {
                sd = map.get(c);
            }
            if (sd == null) {
                sd = new ServiceDispatcher(c, context, handler, flags);
                if (map == null) {
                    map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
                    mServices.put(context, map);
                }
                map.put(c, sd);
            } else {
                sd.validate(context, handler);
            }
            return sd.getIServiceConnection();
        }
    }
    

    在LoadApk中IServiceConnection对象是通过context键值来存储ServiceDispatcher对象,而ServiceDispatcher对象内存会有个InnerConnection对象,该对象就是getServiceDispatcher的返回对象。因此bindServiceCommon最终调用
    ActivityManagerNative.getDefault().bindService(x,x,x,x,x sd, x, x, x) 的时候,传递的参数sd其实就是一个InnerConnection对象,这是个Binder实体。但是,Binder.java中的Binder只是对native层BBinder的一个简单封装,真正的实例化还是通过JNI到native层去创建一个JavaBBinderHolder对象,并初始化gBinderOffsets,让其能映射Java层Binder对象,而JavaBBinderHolder中又可以实例化BBinder的实例JavaBBinder,不过BBinder的实例化时机并不在这里,而是在Parcel对象writeStrongBinder的时候,

    static struct bindernative_offsets_t
    {
        // Class state.
        jclass mClass;
        jmethodID mExecTransact;
    
        // Object state.
        jfieldID mObject;
    
    } gBinderOffsets;
    
    static void android_os_Binder_init(JNIEnv* env, jobject obj)
    {
        JavaBBinderHolder* jbh = new JavaBBinderHolder();
        jbh->incStrong((void*)android_os_Binder_init);
        env->SetIntField(obj, gBinderOffsets.mObject, (int)jbh);
    }
    

    继续往下看bindService,会调用到ActivityManagerProxy的bindService

    public int bindService(IApplicationThread caller, IBinder token,
            Intent service, String resolvedType, IServiceConnection connection,
            int flags, int userId) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        data.writeStrongBinder(token);
        service.writeToParcel(data, 0);
        data.writeString(resolvedType);
        data.writeStrongBinder(connection.asBinder());
        data.writeInt(flags);
        data.writeInt(userId);
        mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0);
        reply.readException();
        int res = reply.readInt();
        data.recycle();
        reply.recycle();
        return res;
    }
    

    利用Parcel的writeStrongBinder会将Binder实体写入到Parcel中去,这里首先看一下 Parcel data = Parcel.obtain();在java层Parcel只是一个容器,具体Parcel相关的操作都在Native层

    static jint android_os_Parcel_create(JNIEnv* env, jclass clazz)
    {
        Parcel* parcel = new Parcel();
        return reinterpret_cast<jint>(parcel);
    }
    

    这里的返回值,其实就是Parcel对象的地址,被赋值给了Parcel.java的mNativePtr成员变量,方便Native调用,接着看writeStrongBinder的实现,其实就是调用Parcel.cpp中的对应方法,通过flatten_binder将Binder实体对象打扁,创建flat_binder_object写入Parcel中,

    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主要为Java层Binder实例化native binder对象:

    sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
    {
        if (obj == NULL) return NULL;
    
        if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
            JavaBBinderHolder* jbh = (JavaBBinderHolder*)
                env->GetIntField(obj, gBinderOffsets.mObject);
            return jbh != NULL ? jbh->get(env, obj) : NULL;
        }
    
        if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
            return (IBinder*)
                env->GetIntField(obj, gBinderProxyOffsets.mObject);
        }
        return NULL;
    }
    

    如果BBinder还没实例化,要通过JavaBBinderHolder的get函数实例化一个BBinder对象,这里就是JavaBBinder对象,综上分析Java层与Native的Binder其对应关系如下:

    Java层Binder与native 层BBiner.png

    BBinder对象被Parcel转换成flat_binder_object,经过一次拷贝写入目标进程,并执行BINDER_TYPE_BINDER与BINDER_TYPE_HANDLE的转换,如下:

    static void
    binder_transaction(struct binder_proc *proc, struct binder_thread *thread,
        struct binder_transaction_data *tr, int reply)
        ...
     fp = (struct flat_binder_object *)(t->buffer->data + *offp);
    
        switch (fp->type) {
            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->handle = ref->desc;
            } break;
            case BINDER_TYPE_HANDLE:
            case BINDER_TYPE_WEAK_HANDLE: {..
                struct binder_ref *ref = binder_get_ref(proc, fp->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;
                } else {
                    struct binder_ref *new_ref;
                    new_ref = binder_get_ref_for_node(target_proc, ref->node);
                    fp->handle = new_ref->desc;
                }
            } break;
    }
    

    在内核中,bindService中的InnerConnection会由BINDER_TYPE_BINDER转换成BINDER_TYPE_HANDLE,之后,AMS线程被唤醒后,执行后面的流程,在前文分析Parcel数据转换的时候,在Binder线程被唤醒继续执行的时候,会将数据映射到一个natvie Parcel对象中

    status_t IPCThreadState::executeCommand(int32_t cmd)
     {
        BBinder* obj;
        switch (cmd) {
         ..
        // read到了数据请求,这里是需要处理的逻辑 ,处理完毕,
        case BR_TRANSACTION:
            {
                binder_transaction_data tr;
                result = mIn.read(&tr, sizeof(tr));
                Parcel buffer;
                <!--关键点1 -->
                buffer.ipcSetDataReference(
                    reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                    tr.data_size,
                    reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
                    tr.offsets_size/sizeof(size_t), freeBuffer, this);
                ...
              <!--关键点2 -->
            if (tr.target.ptr) {
                sp<BBinder> b((BBinder*)tr.cookie);
                const status_t error = b->transact(tr.code, buffer, &reply, tr.flags);
                if (error < NO_ERROR) reply.setError(error);
            }
            ..
          }
       }        
    

    首先看一下关键点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函数,该函数首先将Native的Parcel映射成Jave层Parcel,之后调用BBinder子类的onTransact函数执行对应的业务逻辑,最后会通过data.recycle通知释放内存:

    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自身,这样就能为上层区分出是生成代理还是存根自身,整体对象转换流程如下:

    ServiceConnection的回调作用

    到这里分析了一半,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未启动,但是进程已经启动的情况”,关键代码如下

     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实体与引用的整体流程图如下:

    bindSerivce整体流程图

    如果要深究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进行通信了。
    bindService流程

    听说你Binder机制学的不错,来解决下这几个问题(一)
    听说你Binder机制学的不错,来看看这几个问题(二)
    听说你Binder机制学的不错,来看看这几个问题(三)

    作者:看书的小蜗牛
    原文链接: 听说你Binder机制学的不错,来面试下这几个问题(三)

    仅供参考,欢迎指正

    相关文章

      网友评论

      • 布吉刀:Client如果想要获得Binder实体的代理可以通过asInterface来处理,比如如果在同一进程就是实体,不在就新建代理对象
      • 布吉刀:而APP通过的bindService启动的Binder服务其实是由SystemServer的ActivityManagerService负责管理。

      本文标题:听说你Binder机制学的不错,来面试下这几个问题(三)

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