美文网首页Android技术知识
Android Framework:Binder全解析(二)这篇

Android Framework:Binder全解析(二)这篇

作者: 唐唐_1388 | 来源:发表于2020-12-17 17:12 被阅读0次

    作者

    Mlx

    前言

    在上一篇中我们分别从Native层到内核层讲解了系统服务是如何注册,那这篇从Java层开始讲,系统服务是如何获取的。

    Java层

    小伙伴想想我们平常接触系统服务最多的时候是什么时候?

    是不是就是获取系统服务呢?没错,那我们就从获取系统服务开始。

    首先以我们最基础的使用方式getSystemService()这个方法开始

    getSystemService()

    var manager=getSystemService(Service.AUDIO_SERVICE) as AudioManager
    

    一般情况下我们是这样使用的。但是这个AudioManager到底是如何实现的呢?

    其实它也是通过获取Service来实现的。我们来看看它的方法

    AudioManager.getService

    //android.media.AudioManager.java
    private static IAudioService getService()
        {
            if (sService != null) {
                return sService;
            }
            IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
            sService = IAudioService.Stub.asInterface(b);
            return sService;
    }
    

    AudioManager是通过AIDL的方式获取的真正的系统服务。

    大家要注意这里的ServiceManager和上一篇中native层的ServiceManager是不一样的,这个是Java层的。我们来看一下这个Java层ServiceManager是如何做的。

    ServiceManager.getService

    //frameworks/base/core/java/android/os/ServiceManager.java
    public static IBinder getService(String name) {
            try {
                //先从缓存中查看
                IBinder service = sCache.get(name);
                if (service != null) {
                    return service;
                } else {
                    return Binder.allowBlocking(rawGetService(name));
                }
            } catch (RemoteException e) {
                Log.e(TAG, "error in getService", e);
            }
            return null;
    }
    

    可以看到首先从缓存中去取,如果没有的话就去创建一个,请求获取服务过程中,如果缓存中不存在的话,再通过binder交互来查询相应的服务。创建的方法是rawGetService方法。

    rawGetService

    //frameworks/base/core/java/android/os/ServiceManager.java
    //省略部分代码
    private static IBinder rawGetService(String name) throws RemoteException {
    
           final IBinder binder = getIServiceManager().getService(name);
           /*
           *
           */
            return binder;
    }
    

    getIServiceManager()

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

    是通过ServiceManagerNative.asInterface()方法来获取ServiceManager对象,asInterface方法的参数中是调用了BinderInternal.getContextObject()方法。这是一个native方法。

    getContextObject()

    static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
    {
        sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
        return javaObjectForIBinder(env, b); 
    }
    

    由于本小节是讲解Java的,这里就不做过多的讲解了。对于ProcessState::self()->getContextObject()这个方法,等价于new BpBinder(0)。即BinderInternal.getContextObject()方法最后是获取BpBinder对象。

    那么回过头来看asInterface方法的具体实现:

    ServiceManagerNative.asInterface

    //frameworks/base/core/java/android/os/ServiceManagerNative.java
    static public IServiceManager asInterface(IBinder obj)
        {
            if (obj == null) {
                return null;
            }
            IServiceManager in =
                (IServiceManager)obj.queryLocalInterface(descriptor);
            if (in != null) {
                return in;
            }
    
            return new ServiceManagerProxy(obj);
    }
    

    采用了单例模式获取ServiceManagerasInterface()返回的是ServiceManagerProxy(简称SMP)对象。所以最后getIServiceManager() 方法等价于new ServiceManagerProxy(new BinderProxy())

    既然getIServiceManager()获取到的是ServiceManagerProxyServiceManager.getService(name)方法就是调用的ServiceManagerProxy.getService(name)的方法。我们先看一下ServiceManagerProxy是怎么被初始化的:

    ServiceManagerProxy初始化

    //frameworks/base/core/java/android/os/ServiceManagerNative.java
    class ServiceManagerProxy implements IServiceManager {
        public ServiceManagerProxy(IBinder remote) {
            mRemote = remote;
        }
    }
    

    mRemoteBinderProxy对象,该BinderProxy对象对应于BpBinder(0),其作为binder代理端,指向native层大管家service Manager。还记得BpBinder对象吗?在上一节,我们讲到了这个BpBinder对象于BBinder对象是一对一的,客户端拿着BpBinder去找BBinder,然后服务端的BBinder去做真正的事情。

    emmm

    好像有点懵逼了

    没关系,我们捋一捋

    在Java层,我们首先通过Native方法获得BpBinder对象。BpBinder对象中的handler为0的的时候,就指向的是ServiceManager了。

    接下来构造一个ServiceManagerProxy,ServiceManagerProxy持有BpBinder。内部的工作也全部都是BpBinder去做的。

    简单说就是获取ServiceManager,相当于你找人办事,但是人家架子很大不会自己来,先派给你一个小弟(ServiceManagerProxy),你想做什么就吩咐小弟,小弟手里拿着手机(BpBinder),你吩咐小弟任务以后,小弟通过手机拨打对应号码(BBinder)告诉办事的人。

    ServiceManagerProxy.getService(name)

    //frameworks/base/core/java/android/os/ServiceManagerNative.java
    class ServiceManagerProxy implements IServiceManager {
        public IBinder getService(String name) throws RemoteException {
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
            data.writeInterfaceToken(IServiceManager.descriptor);
            data.writeString(name);
            //mRemote为BinderProxy
            mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
            //从reply里面解析出获取的IBinder对象
            IBinder binder = reply.readStrongBinder();
            reply.recycle();
            data.recycle();
            return binder;
        }
    }
    

    由上可知,framework层的ServiceManager的调用实际的工作确实交给SMP的成员变量BinderProxy;而BinderProxy通过jni方式,最终会调用BpBinder对象;可见上层binder架构的核心功能依赖native架构的服务来完成的。mRemote.transact这行代码将调用BinderProxy.transact方法,最终获得到的数据将会被赋值到reply对象中。

    BinderProxy.transact

    //frameworks/base/core/java/android/os/Binder.java
    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");
            return transactNative(code, data, reply, flags);
        }
    }
    

    最终BinderProxy.transact方法调用了Native方法,从这里开始进入了Native层。Java层的工作到这里就结束了。

    Native层

    android_os_BinderProxy_transact

    //frameworks/base/core/jni/android_util_Binder.cpp
    static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
        jint code, jobject dataObj, jobject replyObj, jint flags)
    {
        ...
        //java Parcel转为native Parcel
        Parcel* data = parcelForJavaObject(env, dataObj);
        Parcel* reply = parcelForJavaObject(env, replyObj);
        ...
    
        //gBinderProxyOffsets.mObject中保存的是new BpBinder(0)对象
        IBinder* target = (IBinder*)
            env->GetLongField(obj, gBinderProxyOffsets.mObject);
        ...
    
        //此处便是BpBinder::transact(), 经过native层
        status_t err = target->transact(code, *data, reply, flags);
        ...
        return JNI_FALSE;
    }
    

    最终调用BpBinder.transact的方法来进行

    BpBinder.transact

    //frameworks/native/libs/binder/BpBinder.cpp
    status_t BpBinder::transact(
        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
    {
        if (mAlive) {
            // 
            status_t status = IPCThreadState::self()->transact(
                mHandle, code, data, reply, flags);
            if (status == DEAD_OBJECT) mAlive = 0;
            return status;
        }
        return DEAD_OBJECT;
    }
    

    如果看过我上一篇文章的话,看到这里已经会发现一个很熟悉的身影。没错就是IPCThreadState。在上一篇文章中,也出现了这个IPCThreadState。这也是个单例模式,每个线程只有一个哦。

    到这里接下来的事情基本上和上一篇中的如出一辙,我这里大概过一下把~

    IPC.transact

    status_t IPCThreadState::transact(int32_t handle,
                                      uint32_t code, const Parcel& data,
                                      Parcel* reply, uint32_t flags)
    {
        status_t err = data.errorCheck(); //数据错误检查
        flags |= TF_ACCEPT_FDS;
        ....
        if (err == NO_ERROR) {
             // 传输数据 
            err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
        }
    
        if (err != NO_ERROR) {
            if (reply) reply->setError(err);
            return (mLastError = err);
        }
    
        // 默认情况下,都是采用非oneway的方式, 也就是需要等待服务端的返回结果
        if ((flags & TF_ONE_WAY) == 0) {
            if (reply) {
                //reply对象不为空 
                err = waitForResponse(reply);
            }else {
                Parcel fakeReply;
                err = waitForResponse(&fakeReply);
            }
        } else {
            err = waitForResponse(NULL, NULL);
        }
        return err;
    }
    

    transact主要过程:

    • 先执行writeTransactionData()Parcel数据类型的mOut写入数据,此时mIn还没有数据;
    • 然后执行waitForResponse()方法,循环执行,直到收到应答消息. 在waitForResponse()方法中会调用talkWithDriver()跟驱动交互,收到应答消息,便会写入mIn, 则根据收到的不同响应吗,执行相应的操作。

    上一篇文章中也将到过,这里再说一次~

    • mIn 用来接收来自Binder设备的数据,默认大小为256字节;
    • mOut用来存储发往Binder设备的数据,默认大小为256字节。

    IPC.talkWithDriver

    //frameworks/native/libs/binder/IPCThreadState.cpp
    status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
    {
        int32_t cmd;
        int32_t err;
        while (1) {
            //此处是真正的与内核交互的方法
            if ((err=talkWithDriver()) < NO_ERROR) break;
            ...
            cmd = mIn.readInt32();
            switch (cmd) {
              case BR_REPLY:
              {
                binder_transaction_data tr;
                err = mIn.read(&tr, sizeof(tr));
                if (reply) {
                    if ((tr.flags & TF_STATUS_CODE) == 0) {
                        //当reply对象回收时,则会调用freeBuffer来回收内存
                        reply->ipcSetDataReference(
                            reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                            tr.data_size,
                            reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
                            tr.offsets_size/sizeof(binder_size_t),
                            freeBuffer, this);
                    } else {
                        ...
                    }
                }
              }
              case :...
            }
        }
        ...
        return err;
    }
    
    status_t IPCThreadState::talkWithDriver(bool doReceive)
    {
        ...
        //和Binder驱动通信的结构体    
        binder_write_read bwr;
        //mIn是否有可读的数据,接收的数据存储在mIn
        const bool needRead = mIn.dataPosition() >= mIn.dataSize();
        const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
    
        bwr.write_size = outAvail;
        //将要发送给Binder设备的消息填充到与Binder通信的结构体中
        bwr.write_buffer = (uintptr_t)mOut.data();
    
        if (doReceive && needRead) {
            //接收数据缓冲区信息的填充。如果以后收到数据,就直接填在mIn中了。
            bwr.read_size = mIn.dataCapacity();
            bwr.read_buffer = (uintptr_t)mIn.data();
        } else {
            bwr.read_size = 0;
            bwr.read_buffer = 0;
        }
        //当读缓冲和写缓冲都为空,则直接返回
        if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
    
        bwr.write_consumed = 0;
        bwr.read_consumed = 0;
        status_t err;
        do {
            //通过ioctl不停的读写操作,跟Binder Driver进行通信
            if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
                err = NO_ERROR;
            ...
        } while (err == -EINTR); //当被中断,则继续执行
        ...
        return err;
    }
    

    接下来会通过ioctl方法于Binder驱动进行交互,这个交互的调用链是如下

    进入驱动。binder_ioctl -> binder_ioctl_write_read -> binder_thread_write,最终会将命令和数据插入到ServiceManagertodo队列中。 这个的叙述可以参考上一篇的内容。

    那么接下来ServiceManager在不断地从队列中取事务并处理,当service manager进程收到该命令后,会执行do_find_service() 查询服务所对应的handle,然后再binder_send_reply()应答 发起者,发送BC_REPLY协议,然后调用binder_transaction(),再向服务请求者的Todo队列 插入事务。接下来,请求服务的进程在执行talkWithDriver的过程执行到binder_thread_read(),处理Todo队列的事务.(这部分不明白的小伙伴一定要看我上一篇文章)。

    waitForResponse方法中,收到消息以后这个reply就不为空,此时会进入reply的ipcSetDataReference方法中,由于这个reply是Parcel对象,其实就是调用了Parcel的ipcSetDataReference方法将ServiceManager返回过来的数据设置到parcel对象中。waitForResponse()执行完BR_REPLY之后,便返回到IPCThreadState::transact()中;然后层层返回,直到退回到Java层的ServiceManagerProxy.getService方法,然后调用reply的readStrongBinder方法,最终调用的Native的方法nativeReadStrongBinder()方法。

    nativeReadStrongBinder

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

    Parcel::readStrongBinder

    sp<IBinder> Parcel::readStrongBinder() const
    {
        sp<IBinder> val; 
        unflatten_binder(ProcessState::self(), *this, &val);
        return val; 
    }
    

    readStrongBinder()会调用unflatten_binder()来解析Parcel中的数据。

    Parcel.unflatten_binder

    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 = reinterpret_cast<IBinder*>(flat->cookie);
                    return finish_unflatten_binder(NULL, *flat, in);
                case BINDER_TYPE_HANDLE:
                    //进入该分支
                    *out = proc->getStrongProxyForHandle(flat->handle);
                    //创建BpBinder对象
                    return finish_unflatten_binder(
                        static_cast<BpBinder*>(out->get()), *flat, in);
            }
        }
        return BAD_TYPE;
    }
    

    ProcessState.getStrongProxyForHandle

    sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
    {
        sp<IBinder> result;
    
        AutoMutex _l(mLock);
        //查找handle对应的资源项
        handle_entry* e = lookupHandleLocked(handle);
    
        if (e != NULL) {
            IBinder* b = e->binder;
            if (b == NULL || !e->refs->attemptIncWeak(this)) {
                ...
                //当handle值所对应的IBinder不存在或弱引用无效时,则创建BpBinder对象
                b = new BpBinder(handle);
                e->binder = b;
                if (b) e->refs = b->getWeakRefs();
                result = b;
            } else {
                result.force_set(b);
                e->refs->decWeak(this);
            }
        }
        return result;
    }
    

    经过该方法,最终创建了指向Binder服务端的BpBinder代理对象。经过javaObjectForIBinder方法将native层BpBinder对象转换为Java层BinderProxy对象。 也就是说通过getService()最终获取了指向目标Binder服务端的代理对象BinderProxy。

    小结

    getService的核心过程:

    public static IBinder getService(String name) {
        ...
        Parcel reply = Parcel.obtain(); //此处还需要将java层的Parcel转为Native层的Parcel
        BpBinder::transact(GET_SERVICE_TRANSACTION, *data, reply, 0);  //与Binder驱动交互
        IBinder binder = javaObjectForIBinder(env, new BpBinder(handle));
        ...
    }
    

    javaObjectForIBinder作用是创建BinderProxy对象,并将BpBinder对象的地址保存到BinderProxy对象的mObjects中。 获取服务过程就是通过BpBinder来发送GET_SERVICE_TRANSACTION命令,与实现与binder驱动进行数据交互。

    请求服务getService()过程,就是向servicemanager进程查询指定服务,当执行binder_transaction()时,会区分请求服务所属进程情况。

    1. 当请求服务的进程与服务属于不同进程,则为请求服务所在进程创建binder_ref对象,指向服务进程中的binder_node;即创建了一个针对于请求服务进程的一个手机号,然后请求进程就可以通过得到一个小弟(BpBinder),让小弟记住这个手机号,就可以找到对应的服务人员(BBinder),然后就可以让服务人员办事了。
      • 最终readStrongBinder(),返回的是BpBinder对象;
    2. 当请求服务的进程与服务属于同一进程,则不再创建新对象,只是引用计数加1,并且修改type为BINDER_TYPE_BINDERBINDER_TYPE_WEAK_BINDER
      • 最终readStrongBinder(),返回的是BBinder对象的真实子类;

    一张图来总结一下:

    喜欢的话留个赞再走呗,有任何技术问题都可以评论区留言,都会回复的哦~

    Android 开发相关源码精编解析

    随着Android开发行业逐渐饱和,对Android开发者的面试要求也越来越高,是否掌握底层源码,便是考验一名Android开发者的重要一环。面试被问到源码问题答不出来,会掉身价、砍薪资尚且不谈,甚至连面试都过不了!

    网上各类源码解析的文章博客五花八门、良莠不齐。杂乱、要么内容质量太浅,零散、碎片化,总看着看着就衔接不上了。

    所以特意将我在疫情期间花了4个月整理出来的《Android 开发相关源码精编解析》分享出来大家

    由于内容较多,避免影响到大家的阅读体验,在此只截图展示目录部分,487详细完整版的《Android 开发相关源码精编解析》电子书文档可以在我的GitHub获取百度网盘下载地址。。也欢迎大家找我探讨Android技术问题~

    目录:一共18节,487页PDF,包括MMKV 源码,ARouter 源码,AsyncTask 源码,Volley 源码,Retrofit 源码,OkHttp 源码,ButterKnife 源码,Okio 源码,SharedPreferences 源码,EventBus 源码,Android 自定义注解初探,View 的工作机制源码分析,Android 触摸事件分发机制源码分析,Android 按键事件分发机制源码分析,深入解析 Handler 源码,深入解析 Binder 源码,深入解析 JNI 源码,深入解析 Glide 源码。

    《Android 开发相关源码精编解析》电子书文档可以在我的GitHub获取百度网盘免费下载地址。

    相关文章

      网友评论

        本文标题:Android Framework:Binder全解析(二)这篇

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