Binder解析

Binder解析

一. 概述

Binder作为Android中最主要的进程间通讯方式,它涉及到的主要有以下这几个方面

  • Client端
  • Service端
  • ServiceManager
  • Binder驱动

Binder通信采用了C/S架构,它和TCP/IP网络通讯有很多相似的地方。

TCP/IP网络通讯最典型的一个过程(例如访问百度首页:)如下;

  1. Client端要访问一个域名,需要先访问DNS服务器查询域名对应的ip地址。

    当然,如果Client端已经知道http地址对应的ip地址,可以跳过这一步。比如Windows系统中就内置了一个hosts文件,可以直接查询到常用网址对应的ip地址。

  2. DNS服务端返回域名对应的ip地址。

  3. Client连接这个ip地址,与Service端进行通讯。

其中,在这中间充当桥梁的硬件是路由器,它负责将根据ip地址选择合适的路径,将数据投递到正确的目标位置。

Binder通讯中,Binder驱动就相当于是这个路由器,ServiceManger就是DNS服务商。

二. 智能指针

智能指针在Binder中比比皆是,所以我们先来回顾下智能指针的知识。

  1. 指针

    Android应用开发使用的语言主要是Java,Java和C/C++有一个很大的不同,就是Java没有指针的概念,它被Java隐藏在了底层。 C/C++中指针是非常重要的一个概念。是一把非常锋利的武器,然而这把武器用不好,就会伤到我们自己。 C/C++中指针常见的问题有这些

    1. 指针没有初始化

    2. new对象,但用完了没有delete对象,造成内存泄漏。

    3. 野指针:我们new了一个对象A,用完也delete了这个对象A。然而,我们没有把指向A对象的指针ptr置为null,导致B对象使用这个指针时发现指针还有指向,会认为A对象依然存活着,这就会出现严重的后果。

      或者ptr1和ptr2都指向对象A,我们用完对象,调用了delete删除A,也将ptr1置为null了,然而ptr2并不知道它指向的对象已经死亡了。这也会造成野指针。

    从而 就出现了只能指针的需求,来解决上面的三个缺陷。

  2. 智能指针

    • 第一个缺陷很好解决,智能指针只需要在创建时自动置为null即可。

    • 第二点。需要在对象不被需要的时候自动的delete。

      智能指针作为一个类,内部有个属性用来指向Object。

      Object有一个父类RefBase,所有Object都要继承它。

      RefBase包含有一个引用计数器,记录指向它的智能指针个数。并提供两个方法incCount,decCount。

      每调用一次incCount,计数器+1.

      每调用一次decCount,计数器-1,并且判断,当计数器为0时,delete掉Object。

      每次需要智能指针指向一个Object时,内部属性指向Object的引用地址,并且调用Object的incCount。

      每当智能智能不再指向一个Object时,调用Object的decCount,并且内部属性置为null。

    然而这又会出现一个问题,加入当一个父对象parent指向一个子对象child,子对象又指向父对象时,这就会出现循环引用,出现问题。从而出现类强弱指针的设计思路:

    • 智能指针分为强指针sp和弱指针wp。
    • Object继承自RefBase,它提供了一个weakref_iml类型的引用计数器,可以同时进行强弱引用的控制,内部分别用mStrong与mWeak来计数。
    • 当incStrong增加强引用计数时,也会同时增加弱引用。
    • 当incWeak增加弱引用计数时,只会增加弱引用计数。
    • 使用者通过设置不同的引用计数器规则来设置不同的删除对象时机。
  3. Binder驱动

    Binder驱动是一个标准的Linux驱动,它将自己注册成一个misc device,并向上层提供一个/dev/binder节点。 Binder节点并不对应真实的硬件设备。Binder驱动运行于内核态,可提供open(), ioctl(),mmap() 等常用的文件操作。

    1. Linux中字符设备的注册需要alloc_chrdev_region(), cedv-init()等许多操作才能在内核中注册自己。而misc类型驱动注册相对简单,调用misc_register()即可。

      binder为上层应用提供了6个接口: binder_poll binder_ioctl,binder_mmap,binder_open,binder_flush,binder_release

    2. 上层进程需要使用Binder驱动时,首先需要打开/dev/binder节点, 这个操作最终会调用到

      binder_open(),最终会创建binder_proc这个对象,他是一个管理数据的记录体(每个进程都有独立的记录体)。然后对proc对象进行各种初始化操作,最后将它加入到Binder的全局管理中。

      目前,Binder驱动已经为用户创建了一个他自己的binder_proc实体,之后用户对Binder设备的操作将以这个对象为基础。

    3. binder_mmap

      上层用户调用mmap()函数之后,最终会调用到binder驱动的binder_mmap。mmap()可以将设备的指定内存块映射到应用程序的内存空间中。

      那么它有什么用呢?假设有两个进程A和B

      • 对于A进程,当他调用binder_open,mmap()得到一个虚拟内binder_open存的地址,这个地址经过内存转换(分段,分页转换)之后会指向一个确定的物理内存地址。
      • 对于binder驱动而言,它的内部有一个指针binder_proc->buffer指向一个虚拟内存地址。而这个虚拟内存地址经过转换之后会和进程A指向同一个物理内存地址。
      • 这样binder驱动就和进程A拥有了共享的内存地址块。
      • binder驱动可以通过copy_from_user()将进程B中的部分数据复制到binder_proc->buffer指向的内存空间。这样,只通过一次复制,我们就实现了A进程和B进程之间数据的共享。
    4. binder_ioctl

      binder_ioctl提供了许多命令,它承载了Binder驱动的大部分业务。

    说明 命令
    可以通过此命令向binder读取或写入数据 BINDER_WRITE_READ
    设置支持的最大线程数 BINDER_SET_MAX_THREADS
    ServiceManager专用,将自己设置为Binder的总管。 BINDER_SET_CONTEXT_MGR
    通知Binder线程退出,每一个线程退出时都应该通知Binder驱动 BINDER_THREAD_EXIT
    获取Binder版本号 BINDER_VERSION
  4. ServiceManager

    SM有点类似于网络中的DNS服务器。SM的句柄(handle)是固定的为0;

    SM必须保证它在binder驱动被使用之前就要启动。所以,它的启动是在init.rc被解析时启动的。SM本身也是一个BinderServer。

    int main(int argc, char **argv)
    {
       struct binder_state *bs;
       void *svcmgr = BINDER_SERVICE_MANAGER;
    
       bs = binder_open(128*1024);
    
       if (binder_become_context_manager(bs)) {
           LOGE("cannot become context manager (%s)\n", strerror(errno));
           return -1;
       }
    
       svcmgr_handle = svcmgr;
       binder_loop(bs, svcmgr_handler);
       return 0;
    }

    SM流程:

    • 给变量svcmgr赋初值,宏定义

      #define BINDER_SERVICE_MANAGER ((void*) 0)

    • 调用binder_open打开Binder设备。进行初始化。

      bs = binder_open(128*1024);

      struct binder_state *binder_open(unsigned mapsize)
      {
       struct binder_state *bs;
      
       bs = malloc(sizeof(*bs));
      ...
       bs->fd = open("/dev/binder", O_RDWR);//打开binder驱动节点
      ...
       bs->mapsize = mapsize;
      //将binder驱动指定内存地址的部分空间映射到SM进程所在内存空间
       bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
      ...
       return bs;
      
      fail_map:
       close(bs->fd);
      fail_open:
       free(bs);
       return 0;
      }

    • 将自己设置为Binder大管家。

      int binder_become_context_manager(struct binder_state *bs)
      {
       return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
      }

      可以看到,像binder驱动发送了BINDER_SET_CONTEXT_MGR

      SM启动很早,可以保证自己是第一个向binder驱动发送命令注册为binder管家的。

    • 进入主循环。

      binder_loop(bs, svcmgr_handler);

      for (;;) {
           bwr.read_size = sizeof(readbuf);
           bwr.read_consumed = 0;
           bwr.read_buffer = (unsigned) readbuf;
      
           res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);//从binder驱动中获取消息
      
           if (res < 0) {
               fprintf(stderr,"binder: ioctl failed (%s)\n", strerror(errno));
               goto fail;
           }
      
           res = binder_parse(bs, reply, readbuf, bwr.read_consumed, 0);//处理读到的消息
           if (res == 0) return 0;
           if (res < 0) goto fail;
       }

      循环就是典型的消息轮询机制了

      • 从消息队列中不断读取消息
      • 如果是退出命令,则退出循环;如果消息为空,就继续读取或者进入阻塞;如果读到了消息,就处理消息。

      SM的主要功能就是

      • 注册:当一个Binder Server被创建之后,需要将自身的名称、句柄告知SM进行注册
      • 查询:其它应用程序可以向SM发起查询请求,查询某个Binder Server对应的句柄。

      SM中维持着一个全局的list数据结构,保存所有Binder Server的注册信息。查询是直接从这个list中进行查询即可。

      注册的话,需要先在SM中查询是否已有对应节点。如果有就不需要再注册,否则需要创建一个新的节点来记录这个Binder Server的对应信息,并保存在list中。

  5. Binder 上层的设计思路

    现在,我们如何从Binder Client中获取SM这个Binder Server呢?

    整体流程也就这几步:

    • 打开binder驱动
    • 调用mmap映射内存空间
    • 通过binder驱动向SM发送请求(SM的句柄为0)
    • 获得结果

    考虑:如果每次应用程序每次使用binder都要打开binder驱动,映射空间,那么他消耗的资源会越来越多,根本吃不消。所以我们要求每个进程只能打开一次binder,映射一次空间,其中进程中的所有线程要共享这一资源。那么就需要一个对象来管理。所以出现了一个对象ProcessState。

    并且所有线程都要自由访问binder驱动(Binder通讯进行时是阻塞式的), 它们之间就需要进行同步处理,所以实际上与Binder驱动进行交互的是IPCThreadState

    现在我们可以获取SM了,我们可以通过发送BINDER_WRITE_READ等Binder支持的命令来与binder驱动交互,从而一步一步获得SM提供的服务。然而这样做实在太过繁琐了,那怎么办?当然是封装,这些与binder驱动的交互封装起来 对上层透明。

    我们知道SM主要功能有两个getService addService那么我们就设计这样一个接口,将SM提供的功能定义出来。

    public interface IServiceManager {
       public IBinder getService(String name) throws RemoteException;
    
       public void addService(String name, IBinder service, boolean allowIsolated)
                   throws RemoteException;
    
       public String[] listServices() throws RemoteException;
    
       static final String descriptor = "android.os.IServiceManager";
        ...
    }

    我们再创建一个代理类ServiceManagerProxy来远程代理ServiceManager(注意这里的代理是指代理SM这个概念的功能)的功能。就像买火车票一样,你去火车站售票窗口可以买,但是太远了。 你家附近就有一个售票代理点。 那么这个售票代理点就要和火车站的服务内容保持一致,可以查票,买票,退票。

    所以ServiceManagerProxy需要继承自IServiceManager

    class ServiceManagerProxy implements IServiceManager {
       private IBinder mRemote;
       public ServiceManagerProxy(IBinder remote) {
           mRemote = remote;
       }
    
       public IBinder asBinder() {
           return mRemote;
       }
    
       public IBinder getService(String name) throws RemoteException {
           Parcel data = Parcel.obtain();
           Parcel reply = Parcel.obtain();
           data.writeInterfaceToken(IServiceManager.descriptor);
           data.writeString(name);
           mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
           IBinder binder = reply.readStrongBinder();
           reply.recycle();
           data.recycle();
           return binder;
       }
    
       public void addService(String name, IBinder service)
               throws RemoteException {
           Parcel data = Parcel.obtain();
           Parcel reply = Parcel.obtain();
           data.writeInterfaceToken(IServiceManager.descriptor);
           data.writeString(name);
           data.writeStrongBinder(service);
           mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
           reply.recycle();
           data.recycle();
       }
       ...
    }

    使用ServiceManagerProxy来代理ServiceManager的功能可能会让某些人迷茫,native层是ServiceManager,怎么到了Java层变成了ServiceManagerProxy? 所以我们可以在ServiceManagerProxy外面再包上一层,就取名为ServiceManager

    public final class ServiceManager {
       private static final String TAG = "ServiceManager";
    
       private static IServiceManager sServiceManager;
       private static HashMap sCache = new HashMap();
    
       public static void initServiceCache(Map cache) {
           if (sCache.size() != 0) {
               throw new IllegalStateException("setServiceCache may only be called once");
           }
           sCache.putAll(cache);
       }
       private static IServiceManager getIServiceManager() {
           if (sServiceManager != null) {
               return sServiceManager;
           }
           // Find the service manager
           sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
           return sServiceManager;
       }
    
       public static IBinder getService(String name) {
           try {
               IBinder service = sCache.get(name);//首先从缓存中查找
               if (service != null) {
                   return service;
               } else {
                   return getIServiceManager().getService(name);
               }
           } catch (RemoteException e) {
               Log.e(TAG, "error in getService", e);
           }
           return null;
       }

    public static void addService(String name, IBinder service) {
    try {
    getIServiceManager().addService(name, service);
    } catch (RemoteException e) {
    Log.e(TAG, “error in addService”, e);
    }
    }

    这时,我们就可以直接使用ServiceManager.getService(name);来获取Binder Server。

  6. 我们来看看获得SM的调用过程
    ServiceManager中全都是静态方法,所以可以直接调用getService方法。

    public static IBinder getService(String name) {
           try {
               IBinder service = sCache.get(name);
               if (service != null) {
                   return service;
               } else {
                   return getIServiceManager().getService(name);
               }
           } catch (RemoteException e) {
               Log.e(TAG, "error in getService", e);
           }
           return null;
       }
    private static IServiceManager getIServiceManager() {
        if (sServiceManager != null) {
            return sServiceManager;
        }
        sServiceManager =ServiceManagerNative.asInterface(BinderInternal.getContextObject());
        return sServiceManager;
    }

    getService会先充cache中查找本地有没有这个IBinder对象。没有的话就会调用ServiceManagerNative.asInterface(BinderInternal.getContextObject());来获取。

    public abstract class ServiceManagerNative extends Binder implements IServiceManager{
       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);
       }
    
       public ServiceManagerNative(){
           attachInterface(this, descriptor);
       }
    
       ...
    
       public IBinder asBinder(){
           return this;
       }
    }

    可以看到 asInterface这个方法先调用了queryLocalInterface查询本地是否有这个对象,有的话将这个对象转为IServiceManager类型的对象返回,没有的话 new 了一个ServiceManagerProxy对象,并且使用ServiceManagerProxy中的成员变量mRemote来记录这个IBinder对象。其中ServiceManagerProxy是继承自IServiceManager接口的,所以可以直接返回。

    那么这里的关键就是这个IBinder obj了,它是从哪来的呢? 查看调用流程会发现调用

    BinderInternal.getContextObject()获得了IBinder对象,更进去会发现这是一个native的方法。说明它是和底层Binder驱动交互的,我们先不管他。

    获得了IServiceManager的实现对象ServiceManagerProxy,调用了它的getService方法。

       public IBinder getService(String name) throws RemoteException {
           Parcel data = Parcel.obtain();
           Parcel reply = Parcel.obtain();
           data.writeInterfaceToken(IServiceManager.descriptor);
           data.writeString(name);
           mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);//最关键的一句
           IBinder binder = reply.readStrongBinder();
           reply.recycle();
           data.recycle();
           return binder;
       }

    data,reply都是Parcel对象用来装载数据。 整体流程就是,将IServiceManager的描述符以及需要获得的Binder Server的名称放入data,接着调用mRote的transact方法,线程挂起,调用native层代码。等待数据返回之后,调用reply接受数据,从reply中读取到IBinder对象。 所以整个流程最关键的一句就是mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);

    GET_SERVICE_TRANSATION是一个常量

    int GET_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION;
    int FIRST_CALL_TRANSACTION  = 0x00000001;

    而在Service_manager.c中的业务代码定义(实际定义在binder.h文件中)

    enum {
       SVC_MGR_GET_SERVICE = 1,
       SVC_MGR_CHECK_SERVICE,
       SVC_MGR_ADD_SERVICE,
       SVC_MGR_LIST_SERVICES,
    };

    这样,客户端功能就和服务端统一了。

  7. 再探native

    上一小节,我们有两个地方调用到了native层去,分别是

    BinderInternal.getContextObject()mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);

    BinderInternal是获取到IBinder对象的。而mRemote实际就是一个IBinder对象。

    所以IBinder接口至少有如下方法

    public interface IBinder {
    public IInterface queryLocalInterface(String descriptor);
    public boolean transact(int code, Parcel data, Parcel reply, int flags)throws RemoteException;
     ...
    }

    而BinderInternal至少有如下方法

    public class BinderInternal {
    public static final native IBinder getContextObject();
    ...
    }

    其中BinderInternal的getContextObject方法native实现代码如下

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

    可以看到,它调用了ProcessState的getContextObject方法,然后将ProcessState创建的对象转换为IBinder对象返给Java层。

    IBinder是一个接口,那么在Java层肯定有有类实现了它,这个类就是IBinderProxy,而在natice层继承了IBinder接口的就是BpBinder。 实际上ProcessState::self()->getContextObject(NULL);调用返回的就是一个BpBinder对象

    final class BinderProxy implements IBinder {
    
    
       public native String getInterfaceDescriptor() throws RemoteException;
       public native boolean transact(int code, Parcel data, Parcel reply,
               int flags) throws RemoteException;
        ...
    }

    transact方法是一个native方法,native层对应的实现在android_util_binder中

    static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
           jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
    {
        ...
       Parcel* data = parcelForJavaObject(env, dataObj);
    ...
       Parcel* reply = parcelForJavaObject(env, replyObj);
    ...
    
       IBinder* target = (IBinder*)
           env->GetIntField(obj, gBinderProxyOffsets.mObject);
    ...
         //调用了native层IBinder的transact方法
       status_t err = target->transact(code, *data, reply, flags);
        ...
       if (err == NO_ERROR) {
           return JNI_TRUE;
       } else if (err == UNKNOWN_TRANSACTION) {
           return JNI_FALSE;
       }
       signalExceptionForError(env, obj, err, true /*canThrowRemoteException*/);
       return JNI_FALSE;
    }

    其中data以及reply是将Java层的Parcel转化为native层的Parcel容器对象。 然后调用了native层IBinder的transact方法。而native层的IBinder接口实现为BpBinder,BpBinder中的transact方法是

    status_t BpBinder::transact(
       uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
    {
       // Once a binder has died, it will never come back to life.
       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的transact方法

    所以饶了一大圈,最后实现的还是IPCThreadState和ProcessState。

  8. ProcessState和IPCThreadState

    ProcessState的主要职责在于:

    • 保证一个进程只有一个ProcessState对象存在,并且在创建对象时做打开binder驱动以及mmap内存映射。

    • 向上层提供服务

    • 与IPCThreadState各司其职

      第一个很好解决,采用类似Java中的单例即可。

      sp ProcessState::self()
      {
       if (gProcess != NULL) return gProcess;
      
       AutoMutex _l(gProcessMutex);
       if (gProcess == NULL) gProcess = new ProcessState;
       return gProcess;
      }

      如果当前进程有ProcessState实例,则直接返回实例。否则创建这个实例。

      ProcessState的构造函数

      ProcessState::ProcessState()
       : mDriverFD(open_driver()), mVMStart(MAP_FAILED)
       , mManagesContexts(false), mBinderContextCheckFunc(NULL)
       , mBinderContextUserData(NULL), mThreadPoolStarted(false)
       , mThreadPoolSeq(1)
      {
       if (mDriverFD >= 0) {
      
      #if !defined(HAVE_WIN32_IPC)
      
           mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
      ...
       }
      }

      其中 ,调用open_driver()打开binder驱动。调用mmap来将binder驱动部分空间映射到当前进程的内存空间。

      前面我们看到Java层调用了BinderInternal.getContextObject()来获取IBinder对象,而这个方法又调用了native方法ProcessState::self()->getContextObject(NULL);

      sp ProcessState::getContextObject(const sp& caller) {
       return getStrongProxyForHandle(0);
      }
      sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
      {
       sp<IBinder> result;//需要返回的IBinder
       AutoMutex _l(mLock);
      //查找一个vector表。这个表保存了这个进程中已经建立的Binder相关信息
       handle_entry* e = lookupHandleLocked(handle);//如果是SM,Handle为0
      //如果verctor中没有找到节点,会自动创建一个。所以e一般不会为null
       if (e != NULL) {
           IBinder* b = e->binder;
           if (b == NULL || !e->refs->attemptIncWeak(this)) {
               b = new BpBinder(handle); //BpBinder创建
               e->binder = b;
               if (b) e->refs = b->getWeakRefs();
               result = b;
           } else {
               result.force_set(b);
               e->refs->decWeak(this);
           }
       }
      
       return result;
      }

      IPCThreadState需要保证线程单实例,所以他采取了TLS (Thread Loacl Storage) 机制来保证线程单实例。

      IPCThreadState* IPCThreadState::self()
      {
       if (gHaveTLS) {
      restart:
           const pthread_key_t k = gTLS;
           IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
           if (st) return st;
           return new IPCThreadState;
       }
      
       if (gShutdown) return NULL;
      
       pthread_mutex_lock(&gTLSMutex);
       if (!gHaveTLS) {
           if (pthread_key_create(&gTLS, threadDestructor) != 0) {
               pthread_mutex_unlock(&gTLSMutex);
               return NULL;
           }
           gHaveTLS = true;
       }
       pthread_mutex_unlock(&gTLSMutex);
       goto restart;
      }

      IPCThreadState的构造函数

      IPCThreadState::IPCThreadState()
       : mProcess(ProcessState::self()),
         mMyThreadId(androidGetTid()),
         mStrictModePolicy(0),
         mLastTransactionBinderFlags(0)
      {
       pthread_setspecific(gTLS, this);
       clearCaller();
       mIn.setDataCapacity(256);
       mOut.setDataCapacity(256);
      }

      IPCThreadState主要负责与binder驱动交互,所以他的transact方法非常重要

      status_t IPCThreadState::transact(int32_t handle,
                                     uint32_t code, const Parcel& data,
                                     Parcel* reply, uint32_t flags){
                                      ...
                                     }

      各个参数:

      handle:目前调用的是SM,所以为0; 即在ProcessState中构建BpBinder时的mHandle

      code:从Java层传递过来的,为GET_SERVICE_TRANSACTION

      data:从Java层传递过来的,Java层对data的操作为:

          data.writeInterfaceToken(IServiceManager.descriptor);
            data.writeString(name);

      reply:Parcel类型的变量。

      flags: Java层传递过来的,目前为0;

      • 先检查数据是否异常,然后将flags置为TF_ACCEPT_FDS
         status_t err = data.errorCheck();
         flags |= TF_ACCEPT_FDS;

      各个flag的意义

    flags 意义
    TF_ONE_WAY 表示当前业务是异步的。不需要返回
    TF_ROOT_OBJECT 所包含的内容是根对象
    TF_STATUS_CODE 所包含的内容是32位状态值
    TF_ACCEPT_FDS 允许回复中包含文件描述符
    • 接下来,trasact将数据按照binder协议约定的格式进行打包.

      if (err == NO_ERROR) {
             LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
                 (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
             err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
         }

      进行打包的函数是writeTransactionData。这个方法只是将数据整理打包,数据被存储在mOut中。

    • 调用了waitForResponse

      if ((flags & TF_ONE_WAY) == 0) {//判断上面的flag克制,代码会走到调用waitForResponse
            ...
             if (reply) {
                 err = waitForResponse(reply);
             } else {
                 Parcel fakeReply;//做一个假的reply,调用waitForResponse
                 err = waitForResponse(&fakeReply);
             }
            ...
         }
    • 调用了talkWithDriver

      status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
      {
         int32_t cmd;
         int32_t err;
      
         while (1) {//循环等待响应数据
             if ((err=talkWithDriver()) < NO_ERROR) break;//处理与binder驱动的交互
             err = mIn.errorCheck();
             if (err < NO_ERROR) break;//出现异常就退出循环
             if (mIn.dataAvail() == 0) continue; //mIn中没有数据的话,继续循环
             cmd = mIn.readInt32();//从mIn中读取响应
          //接下来是一个switch,根据返回的响应来决定如何处理,暂时先不看
          ...
          }
      }
    • 看看talkWithDriver的具体实现

      status_t IPCThreadState::talkWithDriver(bool doReceive)
      {
         LOG_ASSERT(mProcess->mDriverFD >= 0, "Binder driver is not opened");
         binder_write_read bwr;
      
         const bool needRead = mIn.dataPosition() >= mIn.dataSize();
         const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
      
         bwr.write_size = outAvail;
         bwr.write_buffer = (long unsigned int)mOut.data();
         if (doReceive && needRead) {
             bwr.read_size = mIn.dataCapacity();
             bwr.read_buffer = (long unsigned int)mIn.data();
         } else {
             bwr.read_size = 0;
             bwr.read_buffer = 0;
         }
      ...
      
      #if defined(HAVE_ANDROID_OS)
      
           //调用ioctl函数与binder驱动交互
             if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
                 err = NO_ERROR;
             else
                 err = -errno;
      
      #else
      
             err = INVALID_OPERATION;
      
      #endif
      
             IF_LOG_COMMANDS() {
                 alog << "Finished read/write, write size = " << mOut.dataSize() << endl;
             }
         } while (err == -EINTR);
      
         IF_LOG_COMMANDS() {
             alog << "Our err: " << (void*)err << ", write consumed: "
                 << bwr.write_consumed << " (of " << mOut.dataSize()
              << "), read consumed: " << bwr.read_consumed << endl;
         }
      
         if (err >= NO_ERROR) {
             if (bwr.write_consumed > 0) {
                 if (bwr.write_consumed < (ssize_t)mOut.dataSize())
                     mOut.remove(0, bwr.write_consumed);
                 else
                     mOut.setDataSize(0);
             }
             if (bwr.read_consumed > 0) {
                 mIn.setDataSize(bwr.read_consumed);
                 mIn.setDataPosition(0);
             }
             IF_LOG_COMMANDS() {
                 TextOutput::Bundle _b(alog);
                 alog << "Remaining data size: " << mOut.dataSize() << endl;
                 alog << "Received commands from driver: " << indent;
                 const void* cmds = mIn.data();
                 const void* end = mIn.data() + mIn.dataSize();
                 alog << HexDump(cmds, mIn.dataSize()) << endl;
                 while (cmds < end) cmds = printReturnCommand(alog, cmds);
                 alog << dedent;
             }
             return NO_ERROR;
         }
      
         return err;
      }

      在于Binder驱动进行交互中,Binder Client端会进入睡眠等待。

      Binder驱动根据命令从用户空间复制数据,并且将睡眠的ServiceManger唤醒。 ServiceManager会从Binder驱动中通过消息模型读取命令,与Binder驱动交互。

      ServiceManager根据读取到的数据进行处理,并将处理结果写到binder_write_read数据结构中(其中包含了查询的BinderServer的handle),然后调用ioctl与binder驱动交互,Binder驱动把数据写到mIn中,将数据从Binder Server端复制到Binder Client端。

      将mIn中的数据封装到reply中,经过一系列返回, 回到Java端的ServiceManagerProxy中得getService()方法中

          mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
              IBinder binder = reply.readStrongBinder();

      这个方法native实现是在Parcel的native实现中中

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

      unflatten_binder的实现

      status_t unflatten_binder(const sp& proc,
         const Parcel& in, sp* out)
      {
         const flat_binder_object* flat = in.readObject(false);
      
         if (flat) {
           //type这个属性在Service Server封装时会判断,在同一个进程时type属性为BINDER_TYPE_BINDER,不同进程时为BINDER_TYPE_HANDLE。即同一个进程直接给了要查询的binder的引用,不同进程时给的binder的句柄
             switch (flat->type) {
                 case BINDER_TYPE_BINDER://同一个进程type类型
                     *out = static_cast(flat->cookie);
                     return finish_unflatten_binder(NULL, *flat, in);
                 case BINDER_TYPE_HANDLE://不同的进程type类型
                     *out = proc->getStrongProxyForHandle(flat->handle);
                     return finish_unflatten_binder(
                         static_cast(out->get()), *flat, in);
             }        
         }
         return BAD_TYPE;
      }

      调用了getStrongProxyForHandle

      sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
      {
         sp<IBinder> result;
      //先从本地记录查找有没有。
         handle_entry* e = lookupHandleLocked(handle);
      
         if (e != NULL) {
             IBinder* b = e->binder;
           //当本地没有这个IBinder或者给它增加引用失败,就根据handle创建一个BpBinder
             if (b == NULL || !e->refs->attemptIncWeak(this)) {
                 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;
      }

      至此,通过getservice方法成功获得了ServiceManager的本地代理对象。

      总结:

    • ServiceManagerProxy

      ServiceManagerProxy是SM在本地的代理端。

      当一个BinderServer在启动的时候,会在SM端注册自己,SM会记录它的name和handle。当调用者需要使用一个BinderServer时,通常只知道它的name。所以SM提供了查询服务来获得某个Server的handle。而SM本身也是一个Server,它的handle是固定的为0。

      获得SM的本地代理对象需要调用BinderInternal.getObjectContext()来获取SM的BpBinder。在Java层就是ServiceManagerProxy

    • ProcessState和IPCThreadState

      ProcessState负责处理与进程有关的业务,IPCThreadState负责线程有关的业务。他们是Android系统为了方便上层使用binder所封装的两个实现类.

      ProcessState主要负责打开binder驱动,mmap映射binder驱动内存空间。而具体的与binder驱动的交互就交给了IPCThreadState来处理。

      上面的例子中,从Java层的IBinder.transact调用到native层的IPCThreadState的transact(),然后到waitForResponse进入循环——直到收到SM端的回复之后跳出循环,然后再一层一层返回Java端。

    • ServiceManager

      SM在系统启动时就启动了,然后将自己注册为BinderServer的管家。并在最后一次ioctl操作中进入睡眠状态,直到有Client端发起请求,然后被binder驱动唤醒。唤醒之后SM分为两条线进行

      • SM执行read操作,把具体的请求读取出来,然后掉binder_parse进行解析。将处理的结果通过ioctl操作返回给binder驱动。
      • Client端在执行玩write请求,执行read请求时进入了睡眠状态,直到binder驱动收到了SM的回复后将Client端唤醒。Client端将回复的结果封装到Parcel类型的reply中,然后层层返回到Java端。

      最后将返回的IBInder通过asInterface进行包装。例如返回的SM的IBInder会通过调用ServiceManagerNative的asInterface方法包装成ServiceManagerProxy对象。

你可能感兴趣的:(android源码,android)