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

​前言

Android底层:通熟易懂的分析binder--3. 探究binder全流程通信之请求篇已经把请求流程分析完毕了,接下来分析回复流程。

本篇内容

  1. 方法调用栈
  2. 收到回复数据并发送
  3. 回复数据到达driver层
  4. server收尾工作
  5. client收到回复数据
  6. 全流程总结

1.方法调用栈

在分析回复流程之前需要把请求流程后,各个环节现在所处的方法调用栈讲清楚,这样可以作为我们后面分析的基础。

分别用clientInvokeStack(client进程方法调用栈),serverInvokeStack(server进程方法调用栈),clientDriInvokeStack(“driver层client代理“方法调用栈),serverDriInvokeStack(”driver层server代理“方法调用栈)表示方法调用栈,位于方法栈前面的就是最近调用的方法。

serverInvokeStack的方法有:

1.server.methodXX(“真正”方法执行者)
2.Stub的onTransact
3.JavaBBinder的onTransact
4.BBinder的transact
5.IPCThreadState的execCommand
6.IPCThreadState的getAndExecuteCommand
7.IPCThreadState的joinThreadPool

serverDriInvokeStack中暂时没有任何方法,因为driver层把请求数据传递给上层后就结束了。

clientDriInvokeStack的方法有:

1.binder_thread_read (进入等待状态,等待回复消息)
2.binder_ioctl_write_read
3.binder_ioctl

clientInvokeStack的方法有:

1.IPCThreadState::self()-> waitForResponse(进入等待状态,等待回复消息)
2.IPCThreadState::self()->transact
3.BpBinder::transact
4.android_os_BinderProxy_transact (android_util_Binder.cpp)
5.binderProxy.transactNative
6.binderProxy.transact
7.serverProxy.methodXX

在分析回复流程中,其实是上面的方法栈的方法出栈的过程,因此上面的方法栈会伴随着我们的分析流程

2.收到回复数据并发送

发生于server进程

下面分析用到了serverInvokeStack方法调用栈。

收到回复数据是指server.methodXX方法已经处理完,并且把回复数据写入reply(Parcel)中,native层收到了这个回复数据,发送回复数据是指native层开始把回复发送给client。

2.1 收到回复数据

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

上面代码,Stub的子类对象(server)的methodXX方法处理完毕后,把回复数据写入reply(Parcel)中,这两方法从serverInvokeStack中出栈,进而进入JavaBBinder的onTransact和BBinder的transact方法,这两方法也基本没做啥处理,直接返回出栈,那现在serverInvokeStack中的方法有:

1.IPCThreadState的execCommand
2.IPCThreadState的getAndExecuteCommand
3.IPCThreadState的joinThreadPool

那我们进入execCommand方法,看下它未执行完的代码

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:
        {
            省略代码...
​
            // 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 {
              省略代码...
            }
​
           // 同步请求则开始把结果返回
            if ((tr.flags & TF_ONE_WAY) == 0) {
                if (error < NO_ERROR) reply.setError(error);
                sendReply(reply, 0);
            } else {
               省略代码...
            }
            省略代码...
​
        }
        break;
​
    省略代码...
    }
    return result;
}

上面代码,执行完

error = reinterpret_cast(tr.cookie)->transact(tr.code, buffer,
                            &reply, tr.flags);

后,若没有error,并且是同步请求,则调用sendReply发送回复数据,reply中存储了回复数据,sendReply方法入栈,那现在serverInvokeStack中的方法有:

1.IPCThreadState的sendReply
2.IPCThreadState的execCommand
3.IPCThreadState的getAndExecuteCommand
4.IPCThreadState的joinThreadPool

2.2 发送回复数据

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

status_t IPCThreadState::sendReply(const Parcel& reply, uint32_t flags)
{
    status_t err;
    status_t statusBuffer;
  // 把数据写入binder_transaction_data中,准备写入driver层
    err = writeTransactionData(BC_REPLY, flags, -1, 0, reply, &statusBuffer);
    if (err < NO_ERROR) return err;
  // waitForResponse中最终调用talkWithDriver方法把数据传递给driver层
    return waitForResponse(NULL, NULL);
}

上面代码把cmd为BC_REPLY(这时候给driver层的命令是BC_REPLY),reply等写入binder_transaction_data中后,调用waitForResponse方法,注意它的参数是null,null。waitForResponse调用talkWithDriver方法后把回复数据写入driver层,waitForResponse进入等待状态(等待driver层返回命令)

waitForResponse方法入栈,那现在serverInvokeStack中的方法有:

1.IPCThreadState的waitForResponse(进入等待状态)
2.IPCThreadState的sendReply
3.IPCThreadState的execCommand
4.IPCThreadState的getAndExecuteCommand
5.IPCThreadState的joinThreadPool

小结

到此server进程已经把回复数据发送给了driver层,server进程内的binder线程进入等待状态,停留于waitForResponse方法,后面还会进入这方法。

3.回复数据到达driver层

发生于“driver层server代理”

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

下面分析用到了serverDriInvokeStack方法调用栈。

下面的流程分析起来就特别容易了,和请求流程基本是一模一样的,因此只把不一样的地方着中介绍下。

和请求流程一样binder_ioctl,binder_ioctl_write_read,binder_thread_write方法入serverDriInvokeStack方法调用栈中。

binder_thread_write

进入binder_thread_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)
{
  省略代码
​
  // thread->return_error == BR_OK 这个很关键, BR_OK代表还没把信息返回给上层
  while (ptr < end && thread->return_error == BR_OK) {
    if (get_user(cmd, (uint32_t __user *)ptr))
      return -EFAULT;
    省略代码...
    switch (cmd) {
​
    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(proc, thread, &tr, cmd == BC_REPLY);
      break;
    }
​
    省略代码...
  }
  return 0;
}

因为从上层传递的cmd是BC_REPLY,因此进入binder_transaction方法,是不是和BC_TRANSACTION cmd的流程是一样的。binder_transaction方法进入serverDriInvokeStack方法调用栈中。

3.1 查找接收回复数据的“目标”

这里的“目标”当然是“driver层client代理”,下面来看下查找过程,查找代码依然在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;
​
  // 回复相关
  struct binder_transaction *in_reply_to = NULL;
​
  省略代码...
​
​
  // 回复结果
  if (reply) {
        // transaction_stack存放 事务栈, 主要用于回复阶段
    in_reply_to = thread->transaction_stack;
    if (in_reply_to == NULL) {
      binder_user_error("%d:%d got reply transaction with no transaction stack\n",
            proc->pid, thread->pid);
      return_error = BR_FAILED_REPLY;
      goto err_empty_call_stack;
    }
    binder_set_nice(in_reply_to->saved_priority);
        // 判断是否是一样的binder_thread
    if (in_reply_to->to_thread != thread) {
      binder_user_error("%d:%d got reply transaction with bad transaction stack, transaction %d has target %d:%d\n",
        proc->pid, thread->pid, in_reply_to->debug_id,
        in_reply_to->to_proc ?
        in_reply_to->to_proc->pid : 0,
        in_reply_to->to_thread ?
        in_reply_to->to_thread->pid : 0);
      return_error = BR_FAILED_REPLY;
      in_reply_to = NULL;
      goto err_bad_call_stack;
    }
    thread->transaction_stack = in_reply_to->to_parent;
        // 找到target_thread
    target_thread = in_reply_to->from;
    if (target_thread == NULL) {
      return_error = BR_DEAD_REPLY;
      goto err_dead_binder;
    }
        // 容错判断
    if (target_thread->transaction_stack != in_reply_to) {
      binder_user_error("%d:%d got reply transaction with bad target transaction stack %d, expected %d\n",
        proc->pid, thread->pid,
        target_thread->transaction_stack ?
        target_thread->transaction_stack->debug_id : 0,
        in_reply_to->debug_id);
      return_error = BR_FAILED_REPLY;
      in_reply_to = NULL;
      target_thread = NULL;
      goto err_dead_binder;
    }
        // 找到目标binder_proc
    target_proc = target_thread->proc;
  }
}

上面代码很简单,主要做了以下几件事情:

1.因为当前是reply是true,进入reply环节
2.thread->transaction_stack保存了请求时的事务
3.查找“目标”binder_thread, binder_proc

查找到“目标”后,与请求流程一样,会把回复数据拷贝(对BBinder,BpBinder进行转换)后组装成type为BINDER_WORK_TRANSACTION,的binder_work放入“目标”的todo队列中。同时把type为

BINDER_WORK_TRANSACTION_COMPLETE的binder_work放入当前binder_thread的todo队列中。除此之外回复流程还做了从thread->transaction_stack中移除reply事务的操作。

binder_transaction,binder_thread_write方法从serverDriInvokeStack中出栈。

小结

到此回复数据已经放入了“目标”的binder_thread(“driver层client代理”)的todo队列中(注意此时的binder_transaction->buffer->target_node为null)

“driver层server代理”的binder_thread的todo队列放入type为BINDER_WORK_TRANSACTION_COMPLETE的binder_work(它的binder_transaction为null)。

因此这个时候形成了“driver层client代理”与“driver层server代理”并行执行的情况。我们先把“driver层server代理”的流程分析完毕,再来专注分析“driver层client代理”这条线。

serverDriInvokeStack方法调用栈包含的方法有:

1.binder_ioctl
2.binder_ioctl_write_read

4.server收尾工作

发生于server进程和“driver层server代理”

会用到serverInvokeStack,serverDriInvokeStack方法调用栈。

“driver层server代理”把回复数据传递给了“driver层client代理”,server进程还需要做一些收尾工作。

4.1 发送“complete”事件给上层

与处理请求的逻辑一样,“driver层server代理”收到BINDER_WORK_TRANSACTION_COMPLETE的binder_wrok后,会发送BR_TRANSACTION_COMPLETE的cmd给上层,binder_thread_read,binder_ioctl_write_read,binder_ioctl方法先后从serverDriInvokeStack出栈,serverDriInvokeStack方法调用栈中没有任何方法,“driver层server代理”的处理流程结束。

4.2 server收尾工作

收到BR_TRANSACTION_COMPLETE cmd后进入server的收尾工作。先回顾下

serverInvokeStack中的方法有哪些:

1.IPCThreadState的waitForResponse(进入等待状态)
2.IPCThreadState的sendReply
3.IPCThreadState的execCommand
4.IPCThreadState的getAndExecuteCommand
5.IPCThreadState的joinThreadPool

咱们依次从这些方法入手,看执行收尾工作的流程

回到waitForResponse,先看下相关代码

case BR_TRANSACTION_COMPLETE:
            if (!reply && !acquireResult) goto finish;
            break;

因为reply和acquireResult都是null,因此直接finish。从serverInvokeStack中出栈

其他的sendReply,execCommand,getAndExecuteCommand方法也先后从serverInvokeStack中出栈,

回到joinThreadPool,看下相关代码

void IPCThreadState::joinThreadPool(bool isMain)
{
​
    省略代码...
​
    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);
​
    省略代码...
​
    mOut.writeInt32(BC_EXIT_LOOPER);
    talkWithDriver(false);
}

若getAndExecuteCommand方法执行的结果result正常,则进入

if(result == TIMED_OUT && !isMain) {
            break;
}

这块代码分为两个逻辑:

1.若isMain为false(不是binder主线程),则从do循环中跳出,往mOut中写入BC_EXIT_LOOPER cmd通过talkWithDriver方法传递给driver层,注意talkWithDriver方法这时候的参数是false,false代表不需要等待driver层的返回数据,只要把数据成功发送给driver层后就直接结束。当前的binder线程结束,joinThreadPool方法从serverInvokeStack中出栈,serverInvokeStack中没有任何方法。

2.若isMain为true(binder主线程),则继续与driver层通信,driver层最终进入binder_thread_read方法进入等待状态,监听新的事务。

小结

到此,binder进程通信中的server进程回复阶段处理完毕,server进程中的binder线程若为非主线程,则一般会直接结束,否则浪费资源;若为主线程,则继续与driver层通信,等待着新的事务(最起码得有一个binder线程来接收事务)。

5.client收到回复数据

发生于client进程和“driver层client代理”

会用到clientInvokeStack,clientDriInvokeStack方法调用栈。

clientDriInvokeStack的方法有:

1.binder_thread_read (进入等待状态,等待回复消息)
2.binder_ioctl_write_read
3.binder_ioctl

5.1 “driver层client代理”发送回复数据给上层

3.1 节 中"driver层client代理“的binder_thread的todo队列中收到回复binder_work后,binder_thread_read方法被唤醒,拿到回复binder_transaction数据后把其中相关的数据赋值给binder_transaction_data结构体,把cmd为BR_REPLY和

binder_transaction_data数据发送给上层,binder_thread_read,binder_ioctl_write_read,binder_ioctl方法先后从clientDriInvokeStack出栈,clientDriInvokeStack没有任何方法。

5.2 client收到回复数据

先来看下clientInvokeStack方法调用栈,包含的方法有哪些:

1.IPCThreadState::self()-> waitForResponse(进入等待状态,等待回复消息)
2.IPCThreadState::self()->transact
3.BpBinder::transact
4.android_os_BinderProxy_transact (android_util_Binder.cpp)
5.binderProxy.transactNative
6.binderProxy.transact
7.serverProxy.methodXX

咱们依次从这些方法入手,来分析收到回复数据流程。

client native层在waitForResponse方法中处于等待状态,等待回复数据,看下相关代码

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult){
​
   uint32_t cmd;
    int32_t err;
​
    while (1) {
    省略代码...
​
    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;
  }
  省略代码...
}

因为driver层传递的cmd是BR_REPLY,进入该case,最终进入下面的代码流程

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

reply(Parcel对象)调用ipcSetDataReference方法把driver层传递的回复数据写入reply中,进而结束waitForResponse方法的调用,该方法执行出栈操作。

IPCThreadState::self()->transact,BpBinder::transact,android_os_BinderProxy_transact,binderProxy.transactNative,binderProxy.transact先后执行出栈操作,最终在serverProxy.methodXX方法中,把reply回复数据读取出来。

clientInvokeStack内没有任何方法。

至此,整个回复流程结束,因为有请求流程作为基础,因此回复流程分析起来相对简单了很多。

6.全流程总结

到此binder进程通信全流程分析完毕,我用一张图来总结下整个流程


Android binder简版 (1).jpg

图中解析

1.黑色直线箭头代表client请求server的过程,绿色直线箭头代表server处理完毕返回结果给client的过程
2.红色的框和红色字体代表每层之间传递的数据的变化
3.粉色框代表哪层,比如framework层

  1. 蓝色字体是对关键信息的说明
  2. client是c/s中的client是一个进程,同理server就是server端,也是一个进程

上面这张图看上去确实比较复杂(即时我去掉了一些无关紧要的流程),它展示了client请求server服务及server把结果返回给client的过程。在这个过程中,每层(app,framework,jni,native,driver)之间协议的变化,每层之间是怎么联系起来的,native与driver层都做了哪些处理等。

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