Android底层:通熟易懂的分析binder--3. 探究binder全流程通信之请求篇

前言

本系列文章我们来探究下binder全流程通信,这里的全流程既指请求binder服务和binder服务返回结果的过程;又指整个通信过程贯穿app,framework,jni,native,driver这五层。在讲解之前大家可以看下 Android底层:通熟易懂的分析binder--2. binder进程通信协议及“记录链路”结构体 这篇文章,它是本系列文章的基础。

我会把binder通信流程划分为请求回复两个阶段,每个阶段都会贯穿从app到driver这五层。下面是这个系列的所有文章:

  1. 探究binder全流程通信之请求篇
  2. 探究binder全流程通信之回复篇

binder进程通信其实就是一个c/s架构,因此用client代替请求binder服务的一端,server代替提供binder服务的一端。

本系列文章的分析都是基于client进程已经获取到了binder服务引用(BinderProxy对象)来分析的(关于如何获取binder服务引用后面的文章会提到)

本篇内容

  1. 请求从app层到framework层
  2. 请求从jni层到native层
  3. 小结
  4. 请求到达driver层
  5. 查找“目标”,拷贝数据给“目标”
  6. 发送“complete”给client
  7. “目标”处理收到的数据
  8. 请求到达server进程native层
  9. “真正”方法收到请求
  10. 请求流程总结

1.请求从app层到framework层

发生于client进程

我会从请求是如何在每层中传递的以及传递过程中请求的数据都发生了哪些变化来分析请求流程。

binder进程通信的其中一个妙处就在于调用远程(其他进程)方法就如调用本地(本进程)的方法一样,并且是面向接口调用。那我就从调用远程方法开始来作为起始点,来分析下client调用server的方法都经过了哪些坎坷的流程,最终才把参数等传递到server的方法。

先看段aidl生成的代码

public interface IXXX extends android.os.IInterface {
/**
    * Local-side IPC implementation stub class.
    */
    public static abstract class Stub extends android.os.Binder implements IXXX {
        private static final java.lang.String DESCRIPTOR
                        = "...IXXX";
/**
          * Construct the stub at attach it to the interface.
          */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }
​
        @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply,
                int flags) throws android.os.RemoteException {
            switch (code) {
              case TRANSACTION_methodXX: {
                    data.enforceInterface(descriptor);
                    // xxx 代表某一类型, data.readXXX代表读取参数
                    xxx _result = this.methodXX(data.readXXX());
                    reply.writeNoException();
                    reply.writeInt(_result);
                    return true;
                }
            }
        }        
​
        省略代码...
​
        // 对方进程使用代理类
        private static class Proxy implements IXXX {
​
            private android.os.IBinder mRemote;
            Proxy(android.os.IBinder remote) {
                mRemote = remote;
            }
            省略代码...
            @Override
            public xxx methodXX(param)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.writeStrongBinder((((cb != null)) ? (cb.asBinder()) : (null)));
                    // writeXXX代表与param对应的类型
                    _data.writeXXX(param);
                    mRemote.transact(Stub.TRANSACTION_methodXX, _data, _reply, 0);
                    _reply.readException();
                    // 读取返回结果
                    return _reply.readXXX();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
              }
          }
            static final int TRANSACTION_methodXX = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    }
    public void methodXX(param) throws android.os.RemoteException;
}

这段代码大家肯定很熟悉,其中的Stub类是server进程中的binder服务的父类,Proxy就是client进程中binder服务的引用。那我们在client进程调用server进程的methodXX方法的代码如下

serverProxy.methodXX(param),

这段代码就犹如在调用本地的一个方法,serverProxy是Proxy的一个实例(关于它是怎么生成的,后面章节会讲解到)。那我们进入methodXX中看下它的具体实现

public void methodXX(param) 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.writeStrongBinder((((cb != null)) ? (cb.asBinder()) : (null)));
        //进入阻塞状态
        mRemote.transact(Stub.TRANSACTION_methodXX, _data, _reply, 0);
        _reply.readException();
        // 读取返回结果,这段代码先不考虑
        return _reply.readXXX();
    } finally {
        _reply.recycle();
        _data.recycle();
    }
}

先初始化两个Parcel的实例 _data , _reply(存放返回的结果),把param参数写入 _data中,最终调用mRemote.transact方法,mRemote其实是BinderProxy的实例(同样关于它的生成时机也会在后续文章中讲解到)

transact方法的第一个参数是要调用方法对应的int值,这是通过接口的方式与server进行约定的,后面的参数就是 _data, _reply, flag。调用该方法会进入阻塞状态等待返回结果。

那我们在进入BinderProxy中看下transact的实现

public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
    // 检查传输的数据是否超了 800 * 1024
    Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
​
    省略代码...
​
    try {
        return transactNative(code, data, reply, flags);
    } finally {
        省略代码...
    }
}

该方法中检查了传递的数据是否超了800*1024,没超则调用transactNative方法,从名字就能看出这是一个native方法。

小结

上面的请求过程是发生在app到framework层的。传递的数据由 param(各种参数,参数可以是基本类型,也可以是Binder) ----> code(方法),data(参数放入Parcel),reply(存储返回结果)

2.请求从jni层到native层

发生于cleint进程

2.1 transactNative的对应方法

进入jni层的android_util_Binder.cpp文件,transactNative方法最终对应的是(void*)android_os_BinderProxy_transact方法,那我们来看下它

​static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
        jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{
    // 把java层的Parcel对象转换为c++对象
    Parcel* data = parcelForJavaObject(env, dataObj);
    if (data == NULL) {
        return JNI_FALSE;
    }
    Parcel* reply = parcelForJavaObject(env, replyObj);
    if (reply == NULL && replyObj != NULL) {
        return JNI_FALSE;
    }
​
    // 获取java层Binderproxy对象对应native层的IBinder实例
    IBinder* target = getBPNativeData(env, obj)->mObject.get();
    if (target == NULL) {
        jniThrowException(env, "java/lang/IllegalStateException", "Binder has been finalized!");
        return JNI_FALSE;
    }
    省略代码...
    // 最终调用点
    status_t err = target->transact(code, *data, reply, flags);
​
    省略代码...
    return JNI_FALSE;
}

该方法中主要做了几件事情:

把java层的Parcel对象转为native层的对象

根据BindeProxy中的mObject属性找到BpBinder对象,mObject能找到BpBinder是因为BinderProxy在被jni层代码初始化时,会传递一个long值给mObject,这个long值可以理解为是BpBinder的一个指针

最终调用BpBinder的transact(code, *data, reply, flags)方法

2.2 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) {
​
        省略代码...
        // 进入IPCThreadState的transact方法
        status_t status = IPCThreadState::self()->transact(
            mHandle, code, data, reply, flags);
        if (status == DEAD_OBJECT) mAlive = 0;
​
        return status;
    }
​
    return DEAD_OBJECT;
}

上面方法最终调用了IPCThreadState的transact方法,注意这时候的transact方法多了一个参数 mHandle ,它的作用用来查找binder服务。

2.3 IPCThreadState

2.3.1 transact

进入transact方法,看下它的代码

status_t IPCThreadState::transact(int32_t handle,
                                  uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags)
{
    省略代码...
    // 把数据写入binder_transaction_data中,
    err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
​
    if (err != NO_ERROR) {
        if (reply) reply->setError(err);
        return (mLastError = err);
    }
​
    // 同步调用,等待返回结果
    if ((flags & TF_ONE_WAY) == 0) {
        省略代码...
​
        if (reply) {
            err = waitForResponse(reply);
        } else {
            Parcel fakeReply;
            err = waitForResponse(&fakeReply);
        }
​
        省略代码...
    } else {
        // 异步调用,不需要返回结果,
        err = waitForResponse(NULL, NULL);
    }
​
    return err;
}

该方法中,先把数据(BC_TRANSACTION,参数,code值,handle等)写入binder_transaction_data中,很重要一点这时候的数据多了一个BC_TRANSACTION****(Android底层:通熟易懂的分析binder--2. binder进程通信协议及“记录链路”结构体 里面介绍过)它是传递给driver层的cmd。

TF_ONE_WAY代表异步调用,否则同步,不管是异步还是同步调用,最后都调用waitForResponse方法,只不过传递的参数不一样,异步调用所有参数都是null,null

2.3.2 waitForResponse
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    uint32_t cmd;
    int32_t err;
​
    while (1) {
        if ((err=talkWithDriver()) < NO_ERROR) break;
        err = mIn.errorCheck();
        if (err < NO_ERROR) break;
        if (mIn.dataAvail() == 0) continue;
​
        cmd = (uint32_t)mIn.readInt32();
​
        switch (cmd) {
        // driver层处理完毕 BC_TRANSACTION后返回BR_TRANSACTION_COMPLETE命令
        case BR_TRANSACTION_COMPLETE:
            // !reply && !acquireResult 异步处理不需要结果,直接结束
            if (!reply && !acquireResult) goto finish;
            break;
​
        省略代码...
​
        // 接收返回结果的命令
        case BR_REPLY:
            {
                binder_transaction_data tr;
                err = mIn.read(&tr, sizeof(tr));
                ALOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");
                if (err != NO_ERROR) goto finish;
​
                if (reply) {
                    if ((tr.flags & TF_STATUS_CODE) == 0) {
                        reply->ipcSetDataReference(
                            reinterpret_cast(tr.data.ptr.buffer),
                            tr.data_size,
                            reinterpret_cast(tr.data.ptr.offsets),
                            tr.offsets_size/sizeof(binder_size_t),
                            freeBuffer, this);
                    } else {
                        err = *reinterpret_cast(tr.data.ptr.buffer);
                        freeBuffer(NULL,
                            reinterpret_cast(tr.data.ptr.buffer),
                            tr.data_size,
                            reinterpret_cast(tr.data.ptr.offsets),
                            tr.offsets_size/sizeof(binder_size_t), this);
                    }
                } else {
                    freeBuffer(NULL,
                        reinterpret_cast(tr.data.ptr.buffer),
                        tr.data_size,
                        reinterpret_cast(tr.data.ptr.offsets),
                        tr.offsets_size/sizeof(binder_size_t), this);
                    continue;
                }
            }
            goto finish;
​
        default:
            err = executeCommand(cmd);
            if (err != NO_ERROR) goto finish;
            break;
        }
    }
​
finish:
    if (err != NO_ERROR) {
        if (acquireResult) *acquireResult = err;
        if (reply) reply->setError(err);
        mLastError = err;
    }
​
    return err;
}

该方法中有一个循环,在这个循环内会调用talkWithDriver方法(该方法已在 Android底层:通熟易懂分析binder:1.binder准备工作 的进程与driver层通信中介绍过),talkWithDriver方法中最终会通过

 ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0

把数据发送给driver层,其中的cmd是BINDER_WRITE_READ,数据被放入binder_write_read中,mProcess->mDriverFD是打开binder驱动时返回的一个值。

小结

请求从jni层到native层,经历了jni层根据BinderProxy查找BpBinder---> BpBinder的transact方法 ---> IPCThreadState的transact方法 ---> IPCThreadState的waitForResponse方法, 当前线程进入中断状态。

数据由 code, data(参数), reply ---> handle, code, data, reply --->BC_TRANSACTION,handle, code, data ---> cmd: BINDER_WRITE_READ , BC_TRANSACTION,handle, code, data。在每层都会增加本层的协议和字段。

3.小结

到这需要总结下以上的流程,请求是如何一步一步从app到达native层的,传递的数据(主要是参数)都发生了哪些变化。

请求从app到native层的过程:
1.从 serverProxy.methodXX(param) 开始 。(app层)

2.进入mRemote.transact(code, data, reply, flag)方法 (mRemote是BinderProxy对象) 。(进入framework层)

3.BinderProxy实例的transact方法最终调用transactNative方法。

4.transactNative方法最终调用android_os_BinderProxy_transact方法,该方法中通过binderProxy的mObject找到BpBinder实例。(进入jni层)

5.进入BpBinder实例的transact方法,该方法中调用IPCThreadState的transact方法。(进入native层)

6.IPCThreadState的transact方法调用它的waitForResponse,该方法中先调用talkWithDriver方法把数据(参数,code等)传递给driver层,进而等待driver层返回数据。(native层)

请求数据从app到native层的变化:
1.param(调用方法的参数有基本类型,String,IBinder等)(app层)

2.code(调用方法的int值),data(Parcel类型,方法参数),reply(Parcel类型,存储返回值),flag。(framework层)

3.handle(用来查找binder服务),code,data,reply,flag。(native层)

4.BC_TRANSACTION,handle, code, data放入binder_transaction_data结构体中,最终把它写入binder_write_read结构体的write中 (native传数据到driver层)

这时候当前的线程进入中断状态,进而导致serverProxy.methodXX(param)调用处也进入中断状态(因为ioctl是进行系统调用,系统调用陷入内核态),切换到内核线程执行。稍后我们还会回到talkWithDriver方法。

记住waitForResponse, talkWithDriver方法,因为它们等待着返回数据。

请求数据经过ioctl方法后最终进入driver层,那我们进入driver层来分析。

4.请求到达driver层

我使用“driver层xx代理”来代表在driver层中记录的上层进程的信息(binder_proc,binder_thread等)的总称,xx是上层进程的名字(实在没想出一个好名字)。“driver层client代理”与client进程是对应关系,同理“driver层server代理”与server进程是对应关系。

driver层是binder进程通信是最复杂最关键的一层。比如会出现“driver层client代理”与“driver层server代理”并行执行的情况;也会出现一个处于等待,一个处于执行的情况,因此我会在相应标题后面标明当前是在哪个“driver层xx代理”执行,来标明当前是在哪执行。

我用clientInvokeStack来存放“driver层client代理”方法的调用,同理用serverInvokeStack存放“driver层server代理”方法的调用,这样有利于我们分析问题。

4.1 binder_ioctl(driver层client代理)

native层通过调用ioctl方法后,driver层的binder_ioctl(该方法入clientInvokeStack)开始执行,简单来看下它的相关代码:

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
  int ret;
  struct binder_proc *proc = filp->private_data;
  struct binder_thread *thread;
  unsigned int size = _IOC_SIZE(cmd);
  void __user *ubuf = (void __user *)arg;
​
  省略代码...
​
  // 查找上层binder线程对应的binder_thread,若不存在则创建
  thread = binder_get_thread(proc);
  if (thread == NULL) {
    ret = -ENOMEM;
    goto err;
  }
​
  switch (cmd) {
  // BINDER_WRITE_READ类型cmd
  case BINDER_WRITE_READ:
    ret = binder_ioctl_write_read(filp, cmd, arg, thread);
    if (ret)
      goto err;
    break;
​
  省略代码...
​
  }
  省略代码...
​
}

上面代码主要做了以下几件事:
1.查找到binder_proc(有了它才能继续执行) ,arg可以理解为上层数据空间的索引

2.查找并创建binder_thread(记录上层binder线程状态)

3.当前的cmd是BINDER_WRITE_READ,因此进入binder_ioctl_write_read方法(该方法入栈)

clientInvokeStac中的方法有:binder_ioctl_write_read,binder_ioctl。(排在最前的是栈顶)

4.2 binder_ioctl_write_read(driver层client代理)

来看下这个方法代码,同理只把相关代码展示出来

static int binder_ioctl_write_read(struct file *filp,
        unsigned int cmd, unsigned long arg,
        struct binder_thread *thread)
{
  int ret = 0;
  struct binder_proc *proc = filp->private_data;
  unsigned int size = _IOC_SIZE(cmd);
  void __user *ubuf = (void __user *)arg;
  struct binder_write_read bwr;
​
  if (size != sizeof(struct binder_write_read)) {
    ret = -EINVAL;
    goto out;
  }
​
  // 把上层的数据拷贝到内核空间(数据类型binder_write_read)
  if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
    ret = -EFAULT;
    goto out;
  }
​
  // 若上层传递了数据,则进入读取上层数据流程
  if (bwr.write_size > 0) {
    ret = binder_thread_write(proc, thread,
            bwr.write_buffer,
            bwr.write_size,
            &bwr.write_consumed);
    trace_binder_write_done(ret);
    if (ret < 0) {
      bwr.read_consumed = 0;
      if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
        ret = -EFAULT;
      goto out;
    }
  }
​
  省略代码...
}

上面代码主要做了以下几件事:

1.拷贝上层的数据到binder_write_read结构体中。

2.若上层传递了数据则进入binder_thread_write方法,请求肯定是有数据的,因此该方法入栈。

clientInvokeStac中的方法有:binder_thread_write,binder_ioctl_write_read,binder_ioctl。

4.3 binder_ioctl_write(driver层client代理)

binder_ioctl_write才是真正的核心方法,这个方法里面读取上层的命令,数据。进而根据命令执行不同的操作,那我们来看下请求部分的操作代码

static int binder_thread_write(struct binder_proc *proc,
      struct binder_thread *thread,
      binder_uintptr_t binder_buffer, size_t size,
      binder_size_t *consumed)
{
  //上层传递的命令以 BC_ 开头
  uint32_t cmd;
  void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
  // 类似于上层数据指针
  void __user *ptr = buffer + *consumed;
  // 上层数据的结束位置
  void __user *end = buffer + size;
​
  // ptr < end 代表上层数据还没拷贝完毕继续拷贝, BR_OK代表还没把信息返回给上层
  while (ptr < end && thread->return_error == BR_OK) {
    // 拷贝上层命令
    if (get_user(cmd, (uint32_t __user *)ptr))
      return -EFAULT;
    // 数据指针移动 uint32_t 
    ptr += sizeof(uint32_t);
    if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {
      binder_stats.bc[_IOC_NR(cmd)]++;
      proc->stats.bc[_IOC_NR(cmd)]++;
      thread->stats.bc[_IOC_NR(cmd)]++;
    }
    switch (cmd) {
​
    省略代码...
​
    // 请求的cmd是BC_TRANSACTION
    case BC_TRANSACTION:
    // 返回数据的cmd是BC_REPLY
    case BC_REPLY: {
      struct binder_transaction_data tr;
​
      // 拷贝 binder_transaction_data,这个数据结构是不是很眼熟,上层就是把数据赋值给了它
      if (copy_from_user(&tr, ptr, sizeof(tr)))
        return -EFAULT;
      // 指针位置移动
      ptr += sizeof(tr);
      // 进入 binder_transaction 方法
      binder_transaction(proc, thread, &tr, cmd == BC_REPLY);
      break;
    }
​
    省略代码...
​
    default:
      pr_err("%d:%d unknown command %d\n",
             proc->pid, thread->pid, cmd);
      return -EINVAL;
    }
    *consumed = ptr - buffer;
  }
  return 0;
}

上面代码做了以下几件事:

1.若上层数据没有拷贝完,继续拷贝

2.get_user(cmd, (uint32_t __user *)ptr) 拷贝cmd,cmd是上层传递给driver层的命令以BC开头

3.根据cmd进入不同的case,请求的cmd是BC_TRANSACTION,进入这个case

4.copy_from_user(&tr, ptr, sizeof(tr)),拷贝数据到binder_transaction_data中,这个结构体是不是很眼熟,在native层会把传递给driver层的数据放入这个结构体中,最终进入binder_transaction方法中(该方法入栈)。

clientInvokeStac中的方法有:binder_transaction, binder_thread_write,binder_ioctl_write_read,binder_ioctl。

5.查找“目标”,拷贝数据给“目标”

发生于“driver层client代理”

binder_transaction方法主要是处理binder进程通信请求和回复的关键核心方法。这个方法主要做了三件事情:查找“目标”;拷贝数据,构造binder_transaction;把binder_transactin交给“目标”。

这里的“目标”在请求流程中指“driver层server代理”及它包含的binder_proc,binder_thread,binder_node等。

5.1 查找“目标”

开始查找“目标”,把“目标”查找到后才能进入下个环节,否则停止交互流程,我们一段一段的分析,

​static void binder_transaction(struct binder_proc *proc,
             struct binder_thread *thread,
             struct binder_transaction_data *tr, int reply)
{
   // t里面的数据会存放到目标binder_proc或binder_thread的队列中
  struct binder_transaction *t;
    // tcomplete用来告诉client数据已经成功的交给了目标
  struct binder_work *tcomplete;
    // 用来对binder服务,binder服务引用做转换
  binder_size_t *offp, *off_end;
  binder_size_t off_min;
​
  // 目标
  struct binder_proc *target_proc;
  struct binder_thread *target_thread = NULL;
  struct binder_node *target_node = NULL;
  struct list_head *target_list;
  wait_queue_head_t *target_wait;
​
  // 代表回复的数据
  struct binder_transaction *in_reply_to = NULL;
​
  省略代码...
​
  // 回复时执行这
  if (reply) {
    省略代码...
  } else {
        // 请求时执行这
    if (tr->target.handle) {
      struct binder_ref *ref;
      // 找到binder_ref
      ref = binder_get_ref(proc, tr->target.handle);
      if (ref == NULL) {
        binder_user_error("%d:%d got transaction to invalid handle\n",
          proc->pid, thread->pid);
        return_error = BR_FAILED_REPLY;
        goto err_invalid_target_handle;
      }
      target_node = ref->node;
    } else {
            // 没handle时代表请求的是serviceManager
      target_node = binder_context_mgr_node;
      if (target_node == NULL) {
        return_error = BR_DEAD_REPLY;
        goto err_no_context_mgr_node;
      }
    }
    // 根据target_node找到target_proc
    target_proc = target_node->proc;
    if (target_proc == NULL) {
      return_error = BR_DEAD_REPLY;
      goto err_dead_binder;
    }
    if (security_binder_transaction(proc->tsk,
            target_proc->tsk) < 0) {
      return_error = BR_FAILED_REPLY;
      goto err_invalid_target_handle;
    }
​
    // 同步请求
    if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {
      struct binder_transaction *tmp;
​
      // 事务栈
      tmp = thread->transaction_stack;
      if (tmp->to_thread != thread) {
        binder_user_error("%d:%d got new transaction with bad transaction stack, transaction %d has target %d:%d\n",
          proc->pid, thread->pid, tmp->debug_id,
          tmp->to_proc ? tmp->to_proc->pid : 0,
          tmp->to_thread ?
          tmp->to_thread->pid : 0);
        return_error = BR_FAILED_REPLY;
        goto err_bad_call_stack;
      }
​
      // 找target_thread
      while (tmp) {
        if (tmp->from && tmp->from->proc == target_proc)
          target_thread = tmp->from;
        tmp = tmp->from_parent;
      }
    }
  }
​
  // 找到target_thread
  if (target_thread) {
    e->to_thread = target_thread->pid;
    target_list = &target_thread->todo;
    target_wait = &target_thread->wait;
  } else {
    // 否则使用 进程的队列
    target_list = &target_proc->todo;
    target_wait = &target_proc->wait;
  }
​
  省略代码...
}

先介绍下定义的几个变量:

binder_transaction *t:“driver层XX代理”之间交互的结构体,会存储上层的data,code,target_node等,最终会放入目标binder_proc或binder_thread的todo队列中。

binder_work *tcomplete:作用告诉client进程数据已经成功的交给了目标。

binder_size_t *offp, *off_end,binder_size_t off_min:在对方法的参数是的binder服务(Binder)或binder服务引用(BBinder)进行转换时需要用到。

以target开头的变量代表“目标”相关信息。

查找“目标”的流程

根据上层传递的handle(若handle为0则代表查找的是serviceManager),在当前的binder_proc的refs红黑树中找到,binder_ref

根据binder_ref找到目标binder_node,进而找到目标binder_proc,binder_thread。

若目标binder_thread找到了,则使用它的事务队列来存放事务t;否则使用目标binder_proc的事务队列存放事务t

5.2 拷贝数据,构造binder_transaction

既然“目标”找到了,那就需要把上层传递的数据(code,data)拷贝到内核空间,进而构造一个binder_transaction结构体来存放这些数据,来分析下拷贝和构造流程,还依然是binder_transaction方法,只显示了相关代码

static void binder_transaction(struct binder_proc *proc,
             struct binder_thread *thread,
             struct binder_transaction_data *tr, int reply)
{
  // t里面的数据会存放到目标binder_proc或binder_thread的队列中
  struct binder_transaction *t;
    // tcomplete用来告诉client数据已经成功的交给了目标
  struct binder_work *tcomplete;
    // 用来对binder服务,binder服务引用做转换
  binder_size_t *offp, *off_end;
  binder_size_t off_min;
​
  // 目标
  struct binder_proc *target_proc;
  struct binder_thread *target_thread = NULL;
  struct binder_node *target_node = NULL;
  struct list_head *target_list;
  wait_queue_head_t *target_wait;
​
  省略查找“目标”代码...
​
    // 为t分配空间
  t = kzalloc(sizeof(*t), GFP_KERNEL);
  if (t == NULL) {
    return_error = BR_FAILED_REPLY;
    goto err_alloc_t_failed;
  }
  binder_stats_created(BINDER_STAT_TRANSACTION);
​
    // 分配空间
  tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
  if (tcomplete == NULL) {
    return_error = BR_FAILED_REPLY;
    goto err_alloc_tcomplete_failed;
  }
  binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE);
​
  省略代码...
​
  // 不是回复并且是同步,则给from赋值
  if (!reply && !(tr->flags & TF_ONE_WAY))
    t->from = thread;
  else
    // 否则不需要from信息
    t->from = NULL;
​
  省略代码...
​
  // 为buffer分配空间,主要是用来存放方法参数,target_node
  t->buffer = binder_alloc_buf(target_proc, tr->data_size,
    tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));
  if (t->buffer == NULL) {
    return_error = BR_FAILED_REPLY;
    goto err_binder_alloc_buf_failed;
  }
​
  // 对buffer部分信息赋值
  t->buffer->allow_user_free = 0;
  t->buffer->debug_id = t->debug_id;
  t->buffer->transaction = t;
  t->buffer->target_node = target_node;
  trace_binder_transaction_alloc_buf(t->buffer);
  if (target_node)
    binder_inc_node(target_node, 1, 0, NULL);
​
  offp = (binder_size_t *)(t->buffer->data +
         ALIGN(tr->data_size, sizeof(void *)));
​
  // 拷贝上层方法参数信息,
  if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t)
         tr->data.ptr.buffer, tr->data_size)) {
    binder_user_error("%d:%d got transaction with invalid data ptr\n",
        proc->pid, thread->pid);
    return_error = BR_FAILED_REPLY;
    goto err_copy_data_failed;
  }
​
  // 拷贝参数为binder服务或服务引用信息,为binder服务,binder服务引用之间的转换做准备
  if (copy_from_user(offp, (const void __user *)(uintptr_t)
         tr->data.ptr.offsets, tr->offsets_size)) {
    binder_user_error("%d:%d got transaction with invalid offsets ptr\n",
        proc->pid, thread->pid);
    return_error = BR_FAILED_REPLY;
    goto err_copy_data_failed;
  }
​
    省略代码...
​
  off_end = (void *)offp + tr->offsets_size;
  off_min = 0;
​
    // 读取参数是binder服务或binder服务引用
  for (; offp < off_end; offp++) {
    struct flat_binder_object *fp;
​
    if (*offp > t->buffer->data_size - sizeof(*fp) ||
        *offp < off_min ||
        t->buffer->data_size < sizeof(*fp) ||
        !IS_ALIGNED(*offp, sizeof(u32))) {
      binder_user_error("%d:%d got transaction with invalid offset, %lld (min %lld, max %lld)\n",
            proc->pid, thread->pid, (u64)*offp,
            (u64)off_min,
            (u64)(t->buffer->data_size -
            sizeof(*fp)));
      return_error = BR_FAILED_REPLY;
      goto err_bad_offset;
    }
​
    // binder扁平化信息
    fp = (struct flat_binder_object *)(t->buffer->data + *offp);
    off_min = *offp + sizeof(struct flat_binder_object);
    switch (fp->type) {
​
    // 对binder服务进行判断转换
    case BINDER_TYPE_BINDER:
    case BINDER_TYPE_WEAK_BINDER: {
      struct binder_ref *ref;
      struct binder_node *node = binder_get_node(proc, fp->binder);
​
      if (node == NULL) {
        node = binder_new_node(proc, fp->binder, fp->cookie);
        if (node == NULL) {
          return_error = BR_FAILED_REPLY;
          goto err_binder_new_node_failed;
        }
        node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;
        node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
      }
​
            省略代码...
​
            // 查找ref,不存在则创建
      ref = binder_get_ref_for_node(target_proc, node);
      if (ref == NULL) {
        return_error = BR_FAILED_REPLY;
        goto err_binder_get_ref_for_node_failed;
      }
            // 修改fp的值为handle类型
      if (fp->type == BINDER_TYPE_BINDER)
        fp->type = BINDER_TYPE_HANDLE;
      else
        fp->type = BINDER_TYPE_WEAK_HANDLE;
            // 把desc赋值给handle
      fp->handle = ref->desc;
      binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,
               &thread->todo);
​
      省略代码...
​
    } break;
​
    // 对handle类型binder服务引用进行转换
    case BINDER_TYPE_HANDLE:
    case BINDER_TYPE_WEAK_HANDLE: {
            // 根据handle找到当前binder_proc中的binder_ref
      struct binder_ref *ref = binder_get_ref(proc, fp->handle);
​
      if (ref == NULL) {
        binder_user_error("%d:%d got transaction with invalid handle, %d\n",
            proc->pid,
            thread->pid, fp->handle);
        return_error = BR_FAILED_REPLY;
        goto err_binder_get_ref_failed;
      }
      if (security_binder_transfer_binder(proc->tsk,
                  target_proc->tsk)) {
        return_error = BR_FAILED_REPLY;
        goto err_binder_get_ref_failed;
      }
            // 若ref的binder_node指向的binder_proc与目标proc是一样的
      if (ref->node->proc == target_proc) {
                // 则把binder服务引用转换为binder服务
        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);
        trace_binder_transaction_ref_to_node(t, ref);
        binder_debug(BINDER_DEBUG_TRANSACTION,
               "        ref %d desc %d -> node %d u%016llx\n",
               ref->debug_id, ref->desc, ref->node->debug_id,
               (u64)ref->node->ptr);
      } else {
                // 不是同一个binder_proc,则在目标binder_proc中创建binder_ref
        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->handle = new_ref->desc;
        binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL);
        trace_binder_transaction_ref_to_ref(t, ref,
                    new_ref);
​
      }
    } break;
​
    case BINDER_TYPE_FD: {
​
      省略代码...
​
    } break;
​
    default:
      省略代码...
    }
  }
  if (reply) {
​
    省略代码...
​
  } else if (!(t->flags & TF_ONE_WAY)) {
    // 同步的请求
    BUG_ON(t->buffer->async_transaction != 0);
    t->need_reply = 1;
    t->from_parent = thread->transaction_stack;
    // 在 thread 的事务栈的最顶端存放当前的事务,回复时候使用
    thread->transaction_stack = t;
  } else {
    BUG_ON(target_node == NULL);
    BUG_ON(t->buffer->async_transaction != 1);
    // 异步,添加到list中
    if (target_node->has_async_transaction) {
      target_list = &target_node->async_todo;
      target_wait = NULL;
    } else
      target_node->has_async_transaction = 1;
  }
   省略代码...
}

这部分代码相对比较长,主要做了下面几件事情:

1.为变量t(binder_transaction),tcomplete(binder_work)分配空间。

2.为t的buffer分配空间,buffer主要用来存放参数,target_node以及等。

3.调用copy_from_user方法把上层的参数信息拷贝到t的buffer的data中

4.调用copy_from_user方法拷贝参数是binder服务(Binder对象)或binder引用(BpBinder对象)的位置信息

5.遍历所有参数类型是binder服务或binder服务引用,对它们进行转换。

6.对同步请求和异步请求分别处理,若为同步请求对t的need_reply,thread->transaction_stack(用作回复数据)做处理。

binder服务或binder服务引用转换规则
flat_binder_object

fp = (struct flat_binder_object *)(t->buffer->data + *offp);

执行上面代码从Parcel中把 flat_binder_object (主要存放Binder或BpBinder)读出来。
flat_binder_object的type为BINDER_TYPE_BINDER或BINDER_TYPE_WEAK_BINDER,代表是Binder。

flat_binder_object的type为BINDER_TYPE_HANDLE或BINDER_TYPE_WEAK_HANDLE,代表是BpBInder。

转换规则
1.type是Binder,则调用binder_get_node方法从当前binder_proc中取binder_node,若不存在则创建,并且把它插入当前binder_proc的nodes红黑树中。调用binder_get_ref_for_node(target_proc, node)在目标binder_proc中查找binder_ref,若不存在则创建并插入目标binder_proc的refs红黑树中,并且把最终的binder_ref的desc赋值给flat_binder_object的handle。(Binder转换为BpBinder)

2.type是BpBinder,则调用binder_get_ref(proc, fp->handle)查找binder_ref。若当前binder_proc与目标binder_proc相同,则把BpBinder转为Binder;否则,在目标binder_proc创建binder_ref并且插到它的refs红黑树中,并且把最终的binder_ref的desc赋值给flat_binder_object的handle,BpBinder转为BpBinder。(BpBinder转换为Binder或BpBinder)

为回复做准备
若当前的请求是同步,则会执行

t->need_reply = 1;
t->from_parent = thread->transaction_stack;
// 在 thread 的事务栈的最顶端存放当前的事务,回复时候使用
thread->transaction_stack = t;

记住它,在回复流程时,会用到。

5.3 把binder_transaction交给“目标”

看下代码,代码依然在binder_transaction方法中

static void binder_transaction(struct binder_proc *proc,
             struct binder_thread *thread,
             struct binder_transaction_data *tr, int reply)
{
  省略代码...
​
  // 赋值type
  t->work.type = BINDER_WORK_TRANSACTION;
  list_add_tail(&t->work.entry, target_list);
​
  // 通知上层发送BR_TRANSACTION_COMPLETE 信息
  tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
  list_add_tail(&tcomplete->entry, &thread->todo);
  // 目标是处于等待状态,则去唤醒
  if (target_wait)
    wake_up_interruptible(target_wait);
  return;
    省略代码...
}

上面代码主要做了两件事:

给t(binder_transaction)的work.type赋值BINDER_WORK_TRANSACTION并且把最终的binder_work加入"目标“binder_proc或binder_thread的todo队列中。driver层内binde_proc或binder_thread之间通信时的协议是binder_work,协议的type值是以BINDER_WORK开头的,BINDER_WORK_TRANSACTION用于请求或回复环节。最终数据成功的交给了“目标”。

给tcomplete的type赋值BINDER_WORK_TRANSACTION_COMPLETE,并且把最终的binder_work加入到当前binder_thread的todo队列中。BINDER_WORK_TRANSACTION_COMPLETE主要用来告诉上层请求或回复数据已经成功的交给了“目标”。

至此binder_transaction和binder_thread_write方法执行完毕,它们执行出栈操作。

clientInvokeStac中的方法有:binder_ioctl_write_read,binder_ioctl。

接下来会并行着执行两个任务:1. “目标”处理收到的client请求数据(“driver层server代理”);2. 给client回复"complete"信息(“driver层client代理”)。

6.发送“complete”给client

这里的“complete”是指:BINDER_WORK_TRANSACTION_COMPLETE和BR_TRANSACTION_COMPLETE。

为什么不直接等待回复数据,而要发送“complete”信息给client?主要原因是:把driver层的处理状态发给上层,上层根据请求的类型(异步还是同步),来决定是否继续监听回复数据。

6.1 再次回到binder_ioctl_write_read

那来分析下发送“complete”信息的流程。clientInvokeStac当前栈顶的方法是binder_ioctl_write_read,那来看下这方法剩下的逻辑

​static int binder_ioctl_write_read(struct file *filp,
        unsigned int cmd, unsigned long arg,
        struct binder_thread *thread)
{
  省略代码...
  if (bwr.read_size > 0) {
    // bwr binder_write_read
    ret = binder_thread_read(proc, thread, bwr.read_buffer,
           bwr.read_size,
           &bwr.read_consumed,
           filp->f_flags & O_NONBLOCK);
    trace_binder_read_done(ret);
    // 不为空,继续唤醒读取事物
    if (!list_empty(&proc->todo))
      wake_up_interruptible(&proc->wait);
    // ret小于0,一般都是==0
    if (ret < 0) {
      if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
        ret = -EFAULT;
      goto out;
    }
  }
  省略代码...
​
}

最终进入binder_thread_read方法,该方法入栈。

clientInvokeStac中的方法有:binder_thread_read,binder_ioctl_write_read,binder_ioctl。

6.2 收到BINDER_WORK_TRANSACTION_COMPLETE

进入binder_thread_read方法主要用来接收binder_work,根据type值来分别执行不同的操作,进而把处理结果返回给上层,我们先只分析"complete"相关代码

static int binder_thread_read(struct binder_proc *proc,
            struct binder_thread *thread,
            binder_uintptr_t binder_buffer, size_t size,
            binder_size_t *consumed, int non_block)
{
  void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
  void __user *ptr = buffer + *consumed;
  void __user *end = buffer + size;
​
  int ret = 0;
  int wait_for_proc_work;
​
  if (*consumed == 0) {
    if (put_user(BR_NOOP, (uint32_t __user *)ptr))
      return -EFAULT;
    ptr += sizeof(uint32_t);
  }
​
retry:
    // transaction_stack代表事务栈(主要用在回复流程上),  wait_for_proc_work为true,代表当前线程没有任何事务需要处理
  // 即将进入等待状态
  wait_for_proc_work = thread->transaction_stack == NULL &&
        list_empty(&thread->todo);
​
  省略代码...
​
  // BINDER_LOOPER_STATE_WAITING代表当前线程进入等待状态
  thread->looper |= BINDER_LOOPER_STATE_WAITING;
  // ready_threads空闲线程数
  if (wait_for_proc_work)
    proc->ready_threads++;
​
  省略代码...
​
  // 需要等待
  if (wait_for_proc_work) {
    // 只有binder 主线程和通过driver层通知上层启动的线程才可以进入 等待状态
    // BINDER_LOOPER_STATE_REGISTERED:代表driver层通知上层启动线程
    // BINDER_LOOPER_STATE_ENTERED: 代表binder主线程
    if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
          BINDER_LOOPER_STATE_ENTERED))) {
      binder_user_error("%d:%d ERROR: Thread waiting for process work before calling BC_REGISTER_LOOPER or BC_ENTER_LOOPER (state %x)\n",
        proc->pid, thread->pid, thread->looper);
      wait_event_interruptible(binder_user_error_wait,
             binder_stop_on_user_error < 2);
    }
    // 线程进入等待状态,等着被唤醒
    binder_set_nice(proc->default_priority);
    if (non_block) {
      if (!binder_has_proc_work(proc, thread))
        ret = -EAGAIN;
    } else
      ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
  } else {
    // 非阻塞
    if (non_block) {
      if (!binder_has_thread_work(thread))
        ret = -EAGAIN;
    } else
    // 阻塞,则进入等待状态
      ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread));
  }
​
  binder_lock(__func__);
​
    // 线程进入工作状态
  if (wait_for_proc_work)
    proc->ready_threads--;
  thread->looper &= ~BINDER_LOOPER_STATE_WAITING;
​
  if (ret)
    return ret;
​
  // 进入循环中,从todo队列中取事务
  while (1) {
    uint32_t cmd;
    struct binder_transaction_data tr;
    struct binder_work *w;
    struct binder_transaction *t = NULL;
    // 线程的todo不为空,从todo中拿binder_work
    if (!list_empty(&thread->todo)) {
      w = list_first_entry(&thread->todo, struct binder_work,
               entry);
    } else if (!list_empty(&proc->todo) && wait_for_proc_work) {
      // 否则从进程的todo队列中拿binder_work
      w = list_first_entry(&proc->todo, struct binder_work,
               entry);
    } else {
      // BINDER_LOOPER_STATE_NEED_RETURN:可以理解为当前binder线程的工作还没处理完毕的标志
      /* no data added */
      if (ptr - buffer == 4 &&
          !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN))
        // ptr-buffer==4并且当前binder线程的工作处理完毕了才会继续执行retry,否则跳出while循环
        goto retry;
      break;
    }
​
    if (end - ptr < sizeof(tr) + 4)
      break;
​
    switch (w->type) {
​
    省略代码...
​
    case BINDER_WORK_TRANSACTION_COMPLETE: {
      // 把cmd为BR_TRANSACTION_COMPLETE返回给上层
      cmd = BR_TRANSACTION_COMPLETE;
      // 把命令拷贝到用户空间
      if (put_user(cmd, (uint32_t __user *)ptr))
        return -EFAULT;
      ptr += sizeof(uint32_t);
​
      省略代码...
​
      // 把事物移除掉
      list_del(&w->entry);
      // 清除内存
      kfree(w);
    } break;
​
    省略代码...
​
    }
​
    if (!t)
      continue;
​
    省略代码...
  }
​
  省略代码... 
  return 0;
}

上面代码主要做了以下几件事:

1.判断当前binder_thread的transaction_stack是否为null(transaction_stack主要用于回复阶段)以及todo队列是否有事务,没有则代表要进入等待状态

2.根据wait_for_proc_work调用不同的方法内核线程进入等待状态,进而导致binder线程进入等待状态。

3.内核线程被唤醒后,从当前的binder_thread或binder_proc的todo队列中获取binder_work,进而执行;没有获取到满足一定条件后进而进入retry环节

因为上面 5.4.3 小结 已经往当前线程的todo队列中放入type值为BINDER_WORK_TRANSACTION_COMPLETE的binder_work,因此进入binder_thread_read方法后不会阻塞,从todo中取出binder_work,进入BINDER_WORK_TRANSACTION_COMPLETE对应的case,该case中做了两件事情:

1.把cmd置为BR_TRANSACTION_COMPLETE(凡是返回给上层的命令都是以BR开头的)通过put_user把cmd放回到用户空间。

2.把todo队列中的binder_wrok删除掉,并且清除它占用的空间。

执行完后,跳出switch,再次进入while循环,会执行下面代码

 if (!list_empty(&thread->todo)) {
      w = list_first_entry(&thread->todo, struct binder_work,
               entry);
    } else if (!list_empty(&proc->todo) && wait_for_proc_work) {
      // 否则从进程的todo队列中拿binder_work
      w = list_first_entry(&proc->todo, struct binder_work,
               entry);
    } else {
      // BINDER_LOOPER_STATE_NEED_RETURN:可以理解为当前binder线程的工作还没处理完毕的标志
      /* no data added */
      if (ptr - buffer == 4 &&
          !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN))
        // ptr-buffer==4并且当前binder线程的工作处理完毕了才会继续执行retry,否则跳出while循环
        goto retry;
      break;
    }

因为thread->todo和proc->todo都为empty,因此进入else中,因为thread->looper为BINDER_LOOPER_STATE_NEED_RETURN,因此跳出while循环。

到此binder_thread_read方法执行完毕,执行出栈操作,binder_ioctl_write_read方法也随之执行完毕,同样执行出栈操作。

clientInvokeStac中的方法有:binder_ioctl。

6.3 回到binder_ioctl方法

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
​
  省略代码...
​
err:
    // 改下thread状态,BINDER_LOOPER_STATE_NEED_RETURN标明binder线程的处理已经完毕
  if (thread)
    thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
  binder_unlock(__func__);
  wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
​
  省略代码...
​
err_unlocked:
  trace_binder_ioctl_done(ret);
  return ret;
}

回到binder_ioctl方法后,把找到的binder_thread的loopr状态置为~BINDER_LOOPER_STATE_NEED_RETURN。binder_ioctl方法执行完毕,clientInvokeStac中没有任何方法。

6.4 client进程收到BR_TRANSACTION_COMPLETE

Android底层:通熟易懂的分析binder--2. binder进程通信协议及“记录链路”结构体 这篇讲过binder_ioctl方法执行完毕后,会切换到上层线程执行 2.3.2 节waitForResponse 方法,来看下它里面的代码

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    uint32_t cmd;
    int32_t err;
​
    while (1) {
        if ((err=talkWithDriver()) < NO_ERROR) break;
        err = mIn.errorCheck();
        if (err < NO_ERROR) break;
        if (mIn.dataAvail() == 0) continue;
​
        cmd = (uint32_t)mIn.readInt32();
​
        switch (cmd) {
        // driver层处理完毕 BC_TRANSACTION后返回BR_TRANSACTION_COMPLETE命令
        case BR_TRANSACTION_COMPLETE:
            // !reply && !acquireResult 异步处理不需要结果,直接结束
            if (!reply && !acquireResult) goto finish;
            break;
        省略代码...
    }
​
  省略代码...
}

上面代码从talkWithDriver方法返回后,继续下面执行下面代码,从mIn中拿到cmd,cmd就是BR_TRANSACTION_COMPLETE。

(!reply && !acquireResult)代表不是回复并且是异步请求时,则直接结束,异步请求到此就结束了;否则继续执行while循环(咱们讨论的请求是同步的),因此继续进入talkWithDriver方法中继续与driver层通信。

6.5 再次进入driver层等待回复

因为请求是同步的上层还没收到回复消息,因此再次进入driver层索要回复信息,再次从binder_ioctl----> binder_ioctl_write_read ----> binder_thread_read方法,进入binder_thread_read方法后,耐心的等待回复结果,没有进入binder_thread_write方法是因为上层没传递数据。

这时候的clientInvokeStac中的方法有:binder_thread_read,binder_ioctl_write_read,binder_ioctl。

到此整个发送“complete”信息给client流程结束,记住“driver层client代理”还在等着回复消息呢。后面我们还会回到这。同时记住clientInvokeStac的方法。

7.“目标”处理收到的数据

这里的“目标”就是“driver层server代理”,数据其实已经不单单是请求方法的code,参数,还有binder_node等。

Android底层:通熟易懂分析binder:1.binder准备工作 里面提到过,当app启动后,就会启动binder主线程,在driver层会有对应的内核线程进入等待状态,等待着事务的到来,因此“driver层server代理”至少有一个binder线程和内核线程处于等待状态来接收事务。

像上面的clientInvokeStack一样serverInvokeStack存放“driver层server代理”方法的调用,那当前serverInvokeStack内的方法有:binder_thread_read,binder_ioctl_write_read,binder_ioctl。后面会用到serverInvokeStack。

7.1 把请求数据传给上层

6.3 节 把binder_transaction交给“目标” 节中 讲到已经把数据放到了“driver层server代理”的binder_thread或binder_proc的todo队列中,并且把对应的内核线程唤醒了,binder_thread_read方法被唤醒,这个方法上面已经提到过了,因此只看相关代码

static int binder_thread_read(struct binder_proc *proc,
            struct binder_thread *thread,
            binder_uintptr_t binder_buffer, size_t size,
            binder_size_t *consumed, int non_block)
{
  省略代码...
​
  while (1) {
    uint32_t cmd;
    struct binder_transaction_data tr;
    struct binder_work *w;
    struct binder_transaction *t = NULL;
    // 不为empty
    if (!list_empty(&thread->todo)) {
      w = list_first_entry(&thread->todo, struct binder_work,
               entry);
    } else if (!list_empty(&proc->todo) && wait_for_proc_work) {
      // 不为empty
      w = list_first_entry(&proc->todo, struct binder_work,
               entry);
    } else {
      /* no data added */
      if (ptr - buffer == 4 &&
          !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN))
        goto retry;
      break;
    }
​
    if (end - ptr < sizeof(tr) + 4)
      break;
​
    switch (w->type) {
    case BINDER_WORK_TRANSACTION: {
      t = container_of(w, struct binder_transaction, work);
    } break;
​
    省略代码...
​
    }
​
    if (!t)
        // 没有需要处理的事物则继续读写
      continue;
​
    // 有目标node
    if (t->buffer->target_node) {
      struct binder_node *target_node = t->buffer->target_node;
      // 对binder_transaction_data的目标赋值
      tr.target.ptr = target_node->ptr;
      tr.cookie =  target_node->cookie;
      t->saved_priority = task_nice(current);
      if (t->priority < target_node->min_priority &&
          !(t->flags & TF_ONE_WAY))
        binder_set_nice(t->priority);
      else if (!(t->flags & TF_ONE_WAY) ||
         t->saved_priority > target_node->min_priority)
        binder_set_nice(target_node->min_priority);
      cmd = BR_TRANSACTION;
    } else {
      // 没有则认为是ServiceManager
      tr.target.ptr = 0;
      tr.cookie = 0;
      cmd = BR_REPLY;
    }
    tr.code = t->code;
    tr.flags = t->flags;
    tr.sender_euid = from_kuid(current_user_ns(), t->sender_euid);
​
​
    if (t->from) {
      struct task_struct *sender = t->from->proc->tsk;
​
      tr.sender_pid = task_tgid_nr_ns(sender,
              task_active_pid_ns(current));
    } else {
      tr.sender_pid = 0;
    }
​
    // 对参数进行赋值
    tr.data_size = t->buffer->data_size;
    tr.offsets_size = t->buffer->offsets_size;
    tr.data.ptr.buffer = (binder_uintptr_t)(
          (uintptr_t)t->buffer->data +
          proc->user_buffer_offset);
    tr.data.ptr.offsets = tr.data.ptr.buffer +
          ALIGN(t->buffer->data_size,
              sizeof(void *));
​
    if (put_user(cmd, (uint32_t __user *)ptr))
      return -EFAULT;
    ptr += sizeof(uint32_t);
​
    // 把tr引用拷贝到ptr中
    if (copy_to_user(ptr, &tr, sizeof(tr)))
      return -EFAULT;
    ptr += sizeof(tr);
​
    省略代码...
​
        // 删除,释放空间处理
    list_del(&t->work.entry);
    t->buffer->allow_user_free = 1;
    if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {
      t->to_parent = thread->transaction_stack;
      t->to_thread = thread;
      thread->transaction_stack = t;
    } else {
      t->buffer->transaction = NULL;
      kfree(t);
      binder_stats_deleted(BINDER_STAT_TRANSACTION);
    }
    break;
  }
​
done:
​
  *consumed = ptr - buffer;
  // 当前与上层的通信即将结束,在结束之际去尝试告诉上层继续开启与driver的通信
  if (proc->requested_threads + proc->ready_threads == 0 &&
      proc->requested_threads_started < proc->max_threads &&
    // 只有是driver驱动创建的线程和 本身native 自己创建的线程才有发起创建线程的权利
      (thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
       BINDER_LOOPER_STATE_ENTERED)) /* the user-space code fails to */
       /*spawn a new thread if we leave this out */) {
    proc->requested_threads++;
​
    if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer))
      return -EFAULT;
    binder_stat_br(proc, thread, BR_SPAWN_LOOPER);
  }
  return 0;
}

这方法依然还是这么长,那来说下上面代码主要做了哪些事情:

1.从todo中取出binder_work,进入BINDER_WORK_TRANSACTION case,从binder_work中取出binder_transaction

2.若binder_transaction的buffer->target_node(binder_node)存在,则把target_node->ptr,target_node->cookie赋值给binder_transaction_data的target.ptr和cookie。尤其是cookie很重要,它其实就是上层的binder服务(BBinder),没有它就不能进行后面的环节

3.再把binder_transaction的请求方法code,请求参数赋值给binder_transaction_data

4.把cmd为BR_TRANSACTION通过put_user拷贝给上层,同时把binder_transaction_data的引用拷贝给上层

5.做清除工作

6.在结束之前需要判断当前是否有多余的空闲binder线程(不能说当前的事务处理完毕,拍拍屁股就不管别的事务了吧),没有则通过put_user发送BR_SPAWN_LOOPER命令给上层,让它启动binder线程。

到此binder_thread_read方法执行完毕,出栈,相应的binder_ioctl_write_read和binder_ioctl方法都出栈,serverInvokeStack没有任何方法。

这时候的数据由 type:BINDER_WORK_TRANSACTION,code,data(参数),target_node(binder_node) ----> cmd:BR_TRANSACTION,cookie,code,data。也就是在server进程从下往上的过程是一个拆包的过程,在client进程从上往下是一个封包过程(每层增加自己的协议字段)

那接下来请求进入server进程。

8.请求到达server进程native层

下面发生于server进程

请求数据终于到达了server进程的native层,到达app层还有一段路程,先来看下native层是怎么把请求抛给上层的(上层指jni层和app层)。

8.1 native层把请求传递给上层

上面driver层的binder_ioctl方法执行完毕后,切换到binder线程继续执行,binder线程不是在waitForResponse方法处理数据,而是在joinThreadPool方法,来看下相关代码

void IPCThreadState::joinThreadPool(bool isMain)
{
    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
​
    status_t result;
    do {
        processPendingDerefs();
        // now get the next command to be processed, waiting if necessary
        result = getAndExecuteCommand();
​
        if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
            ALOGE("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
                  mProcess->mDriverFD, result);
            abort();
        }
​
        // Let this thread exit the thread pool if it is no longer
        // needed and it is not the main process thread.
        if(result == TIMED_OUT && !isMain) {
            break;
        }
    } while (result != -ECONNREFUSED && result != -EBADF);
​
    LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%d\n",
        (void*)pthread_self(), getpid(), result);
​
    mOut.writeInt32(BC_EXIT_LOOPER);
    talkWithDriver(false);
}

上面代码主要做了以下几件事情:

1.启动一个循环,在循环里面调用getAndExecuteCommand方法(从driver层拿到命令后,执行命令)

2.执行完命令,若不是主线程并且result == TIMED_OUT则退出

3.发送退出命令 BC_EXIT_LOOPER 给driver层
进入getAndExecuteCommand方法,看下怎么获取并执行命令。

8.1.1 getAndExecuteCommand

看下getAndExecuteCommand这个方法,

status_t IPCThreadState::getAndExecuteCommand()
{
    status_t result;
    int32_t cmd;
​
    result = talkWithDriver();
    if (result >= NO_ERROR) {
        size_t IN = mIn.dataAvail();
        if (IN < sizeof(int32_t)) return result;
        cmd = mIn.readInt32();
​
        省略代码...
​
        result = executeCommand(cmd);
​
        省略代码...
    }
​
    return result;
}

这方法也很简单,通过talkWithDriver从driver层拿到数据后,进入executeCommand方法,看下executeCommand方法

8.1.2 把请求传递给上层

executeCommand方法会把driver层传递的命令和数据进行解析,最终把请求传递给上层,下面展示了executeCommand与请求处理相关代码

status_t IPCThreadState::executeCommand(int32_t cmd)
{
    BBinder* obj;
    RefBase::weakref_type* refs;
    status_t result = NO_ERROR;
​
    switch ((uint32_t)cmd) {
​
    省略代码...
​
    case BR_TRANSACTION:
        {
            binder_transaction_data tr;
            result = mIn.read(&tr, sizeof(tr));
​
            if (result != NO_ERROR) break;
​
            Parcel buffer;
            buffer.ipcSetDataReference(
                reinterpret_cast(tr.data.ptr.buffer),
                tr.data_size,
                reinterpret_cast(tr.data.ptr.offsets),
                tr.offsets_size/sizeof(binder_size_t), freeBuffer, this);
​
            const pid_t origPid = mCallingPid;
            const uid_t origUid = mCallingUid;
            const int32_t origStrictModePolicy = mStrictModePolicy;
            const int32_t origTransactionBinderFlags = mLastTransactionBinderFlags;
​
            mCallingPid = tr.sender_pid;
            mCallingUid = tr.sender_euid;
            mLastTransactionBinderFlags = tr.flags;
​
            //ALOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid);
​
            Parcel reply;
            status_t error;
​
            省略代码...
​
      // ptr有值,进入这
            if (tr.target.ptr) {
                if (reinterpret_cast(
                        tr.target.ptr)->attemptIncStrong(this)) {
          // tr.cookie其实就是BBinder对象,这时候开始调用BBinder的transact方法,这是通往上层的入口
                    error = reinterpret_cast(tr.cookie)->transact(tr.code, buffer,
                            &reply, tr.flags);
                    reinterpret_cast(tr.cookie)->decStrong(this);
                } else {
                    error = UNKNOWN_TRANSACTION;
                }
​
            } else {
        // 请求的是ServiceManager
                error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
            }
​
      // 同步请求则开始把结果返回
            if ((tr.flags & TF_ONE_WAY) == 0) {
                LOG_ONEWAY("Sending reply to %d!", mCallingPid);
                if (error < NO_ERROR) reply.setError(error);
                sendReply(reply, 0);
            } else {
        // 异步不需要返回结果
                LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
            }
​
            mCallingPid = origPid;
            mCallingUid = origUid;
            mStrictModePolicy = origStrictModePolicy;
            mLastTransactionBinderFlags = origTransactionBinderFlags;
​
            省略代码...
​
        }
        break;
​
    省略代码...
    }
​
    if (result != NO_ERROR) {
        mLastError = result;
    }
​
    return result;
}

上面代码主要做了以下几件事:

1.拿到driver层传递的cmd:BR_TRANSACTION,进入处理cmd:BR_TRANSACTION的流程

2.把binder_transaction_data从driver层读出来,

3.若binder_transaction_data.target.ptr有值(请求是进入这),调用binder_transaction_data的cookie(BBinder的对象)的transact方法,把code,buffer(参数),&reply,flag传递进去。这也是进入上层的入口,稍后从这个方法分析请求最终是怎么到上层的。

4.等待返回结果发送给driver层进行回复。

通过cookie->transact(code,buffer,reply,flag)。 把code,参数等值传递给上层,executeCommand方法就等待上层处理环节,在上层返回结果后会回到这。那我们去看看请求是怎么到上层的。

cookie是BBinder的对象,那我们进入BBinder的transact方法看下。

8.1.2 BBinder的transact方法

进入transact方法,看下它的代码

/ NOLINTNEXTLINE(google-default-arguments)
status_t BBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    data.setDataPosition(0);
​
    if (reply != nullptr && (flags & FLAG_CLEAR_BUF)) {
        reply->markSensitive();
    }
​
    status_t err = NO_ERROR;
    switch (code) {
        case PING_TRANSACTION:
            err = pingBinder();
            break;
        case EXTENSION_TRANSACTION:
            err = reply->writeStrongBinder(getExtension());
            break;
        case DEBUG_PID_TRANSACTION:
            err = reply->writeInt32(getDebugPid());
            break;
        default:
            // 进入这
            err = onTransact(code, data, reply, flags);
            break;
    }
​
    // In case this is being transacted on in the same process.
    if (reply != nullptr) {
        reply->setDataPosition(0);
    }
​
    return err;
}

这方法非常的简单,code就是请求方法的int值。而我们请求的code值肯定不是上面三种,最终进入default 进而调用onTransact方法,而BBinder的onTransact方法是一个虚方法,因此肯定是有子类实现了这个方法,这个子类是JavaBBinder。

最终进入JavaBBinder的onTransact方法。JavaBBinder是位于jni层,因此请求就传递到jni层。(关于JavaBBinder怎么产生的会在下面分析)

9.“真正”方法收到请求

“真正”方法是相对client调用的是代理方法而言,是指client最终调用的server的方法。

有一个前提需要把JavaBBinder是什么讲解清楚,对于后面的流程就会更容易理解。

9.1 JavaBBinder是什么?

JavaBBinder是什么,它的作用是什么?

在解答之前先说下app层的binder服务。在app层,binder服务的其中一个条件就是继承Binder类,这时候的binder服务是一个java类的对象。在driver层binder_node结构体中存储的binder服务是BBinder对象(如果别的进程获取了当前进程的binder服务引用,那这个binder服务在driver层的binder_node中是有记录的)。

那现在的问题就是app层的Binder对象怎么与native层或者driver层的BBinder对象产生联系呢?JavaBBinder就是来解决此问题的。

JavaBBinder位于jni层,在Binder与BBinder之间搭了一做桥

9.1.1 Binder与jni层建立联系

先来看下Binder类的一段代码

public Binder(@Nullable String descriptor)  {
        // 从native获取JavaBBinderHolder指针
        mObject = getNativeBBinderHolder();
        省略代码...
 }

上面代码是Binder的构造函数,其中mObject = getNativeBBinderHolder()这段代码很关键,一看带Native字眼的就知道是调用jni层的native方法。那我们来看下相应代码

android_util_Binder.cpp
​
static jlong android_os_Binder_getNativeBBinderHolder(JNIEnv* env, jobject clazz
{
    JavaBBinderHolder* jbh = new JavaBBinderHolder();
    return (jlong) jbh;
}

上面代码会new一个JavaBBinderHolder,并且返回指针。

最终Binder的mObject属性保存了jni层的JavaBBinderHolder的指针,这样Binder对象就与jni层的JavaBBinderHolder建立了联系。JavaBBinderHolder的作用后面会提到。

9.1.2 Binder与JavaBBinder建立联系

client进程如果想使用server进程的binder服务,其实有一个过程就是获取binder服务(这个会在后面章节讲到),获取binder服务流程其实就是把binder服务写入Parcel中,通过Parcel传递到driver层,最终在driver层的binder_node存下binder服务。

那Binder与JavaBBinder建立联系就发生于Parcel写入binder服务这一过程,看下Parce的native代码,java层代码省略

android_os_parcel
​
static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
{
    Parcel* parcel = reinterpret_cast(nativePtr);
    if (parcel != NULL) {
        // 调用ibinderForJavaObject方法
        const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
        if (err != NO_ERROR) {
            signalExceptionForError(env, clazz, err);
        }
    }
}

上面代码调用了ibinderForJavaObject方法,其中的参数jobject就是app层的Binder对象,在看下ibinderForJavaObject方法

android_util_Binder.cpp
​
sp ibinderForJavaObject(JNIEnv* env, jobject obj)
{
    if (obj == NULL) return NULL;
​
    // Instance of Binder?
    if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
        JavaBBinderHolder* jbh = (JavaBBinderHolder*)
            env->GetLongField(obj, gBinderOffsets.mObject);
        return jbh->get(env, obj);
    }
​
    // Instance of BinderProxy?
    if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
        return getBPNativeData(env, obj)->mObject;
    }
​
    ALOGW("ibinderForJavaObject: %p is not a Binder object", obj);
    return NULL;
}

上面代码的参数jobject同样是app层Binder对象,这时候是不是看到了JavaBBinderHolder,通过Binder对象的mObject进而获取到JavaBBinderHolder,

进而调用它的get(env,obj)方法。看下这段代码

 sp get(JNIEnv* env, jobject obj)
{
    AutoMutex _l(mLock);
    sp b = mBinder.promote();
    if (b == NULL) {
        b = new JavaBBinder(env, obj);
        mBinder = b;
    }
​
    return b;
}

这段代码很简单,若能获取到JavaBBinder则返回,否则创建JavaBBinder,创建JavaBBinder时会把app层的Binder对象传入。

小结

从而JavaBBinder就拥有了一个上层的Binder对象,并且写入Parcel中的对象不是app层的Binder而是JavaBBinder(它继承了BBinder),最终driver层的binder_node中保存的也是JavaBBinder。

9.2 把请求交给“真正”方法

9.2.1 JavaBBinder的onTransact方法

终于把JavaBBinder讲解清楚了,咱们回到它的onTransact方法

status_t onTransact(
        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) override
{
        JNIEnv* env = javavm_to_jnienv(mVM);
​
        ALOGV("onTransact() on %p calling object %p in env %p vm %p\n", this, mObject, env, mVM);
​
        IPCThreadState* thread_state = IPCThreadState::self();
        const int32_t strict_policy_before = thread_state->getStrictModePolicy();
        // 调用Binder对象的execTransact方法
        jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
            code, reinterpret_cast(&data), reinterpret_cast(reply), flags);
​
        省略代码...
​
        return res != JNI_FALSE ? NO_ERROR : UNKNOWN_TRANSACTION;
}

上面方法代码,最重要的一段代码是

env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
            code, reinterpret_cast(&data), reinterpret_cast(reply), flags);

这里的mObject是app层的Binder对象,gBinderOffsets.mExecTransact是Binder的execTransact方法,上面代码其实最终调用了Binder对象的execTransact方法,并且把code,参数等值作为参数。

9.2.2 “真正”方法收到请求

看下execTransact这方法

private boolean execTransact(int code, long dataObj, long replyObj,
            int flags) {
        省略代码...
​
        Parcel data = Parcel.obtain(dataObj);
        Parcel reply = Parcel.obtain(replyObj);
​
        省略代码...
​
        try {
            // 调用onTransact方法
            res = onTransact(code, data, reply, flags);
        } catch (RemoteException|RuntimeException e) {
           省略代码...
        } finally {
            if (tracingEnabled) {
                Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);
            }
        }
        checkParcel(this, code, reply, "Unreasonably large binder reply buffer");
        reply.recycle();
        data.recycle();
​
    省略代码...
​
        return res;
    }

上面代码主要做了以下几件事:

1.把dataObj, replyObj转化为Parcel

2.调用onTransact方法

3.调用完毕回收Parcel

这里的onTransact方法是 1.请求从app层到framework层 这一节中通过aidl生成的Stub类的方法,如下:

public static abstract class Stub extends android.os.Binder implements IXXX {
        private static final java.lang.String DESCRIPTOR
                        = "...IXXX";
/**
          * Construct the stub at attach it to the interface.
          */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }
​
        @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply,
                int flags) throws android.os.RemoteException {
            switch (code) {
              case TRANSACTION_methodXX: {
                    data.enforceInterface(descriptor);
                    // xxx 代表某一类型, data.readXXX代表读取参数
                    xxx _result = this.methodXX(data.readXXX());
                    reply.writeNoException();
                    reply.writeInt(_result);
                    return true;
                }
            }
        }  
 }      

上面代码中,从data中把参数读出来后,最终调用到methodXX方法,该方法的实现是Stub的子类中。

真是不容易,到此client的请求终于是到达了“真正”方法。

10.请求流程总结

请求从client进程到driver层,经历了app,framework,jni,native,driver这五层,在这五层传递请求数据时,在每一层基本都会增加本层的一些字段,把数据和增加字段封包到本层协议中。方法调用流程是:

1.serverProxy.methodXX

2.binderProxy.transact ---> transactNative

3.android_os_BinderProxy_transact (android_util_Binder.cpp)

4.BpBinder::transact

5.IPCThreadState::self()->transact 分别调用了writeTransactionData和waitForResponse

6.IPCThreadState::self()->waitForResponse内调用talkWithDriver发送接收消息从driver层,并阻塞于waitForResponse方法,等待回复数据。

请求从“driver层client代理“到”driver层server代理“进行了一次数据拷贝,并且会对参数中的BBinder或BpBinder转换为BpBinder或者BBinder。并且会封包相应的协议。“driver层client代理“到”driver层server代理“的方法调用流程:

1.binder_ioctl ---> binder_ioctl_write_read(发生于“driver层client代理”)

2.binder_thread_write 把数据拷贝并赋给“driver层server代理”(发生于“driver层client代理”)

3.binder_thread_read 进入等待状态,等待回复数据(发生于“driver层client代理”)

请求从driver层到server进程,经历了driver,native,jni,framework,app这五层,在这五层中会层层拆包,最终成功的把请求数据交给“真正”方法。方法调用流程是:

1.binder_thread_read 读取从“driver层client代理”传递的数据

2.binder_ioctl_write_read,binder_ioctl方法结束调用,把数据返回给上层

3.IPCThreadState的execCommand 执行从driver层传递的命令和数据(前提IPCThreadState的joinThreadPool 调用了 getAndExecuteCommand ,这方法又调用了execCommand)

4.BBinder的transact

5.JavaBBinder的onTransact

6.Stub的onTransact

7.server.methodXX

请求已经成功的到达了具体的方法,但是整个binder进程通信流程还没结束,client进程还在等待返回结果。会在 探究binder全流程通信之回复篇 分析回复流程。

你可能感兴趣的:(Android底层:通熟易懂的分析binder--3. 探究binder全流程通信之请求篇)