Android底层:通熟易懂的分析binder--2. binder进程通信协议及“记录链路”结构体

前言

binder的准备工作主要介绍了binder进程通信之前需要做的准备工作有哪些,既然binder准备工作做好了,那下一步就是通信了,在讲解通信之前,我希望先把通信的基础知识讲清楚,比如进程与driver层之间的通信协议是啥?binder_node,binder_ref,binder_thread,binder_proc这些东西到底都是啥?在通信过程中起啥作用?Binder,BinderProxy,BpBinder,BBinder又是啥?只有把这些基础知识了解清楚,对于后面的内容理解才能胸有成竹。

本篇内容

  1. 从“表面”看binder服务/引用是啥?
  2. 协议
    2.1 进程与driver层的通信协议
    2.2 "driver层代理进程"之间的通信协议
    2.3 binder通信协议总结
  3. "记录链路"结构体
    3.1 binder_node
    3.2 binder_ref
    3.3 binder_thread
    3.4 binder_proc
    3.5 总结
  4. 总结

会用到的词语:
client进程:binder进程通信的client端(使用binder服务)
server进程:binder进程通信的server端(提供binder服务)
driver层代理进程:driver层中其实是有一个结构体(binder_proc)与上层进程有一个对应关系的,这个东东我就起了个名字叫 driver层代理进程。

1. 从“表面”看binder服务/引用是啥?

从“表面”看是指我们从app开发的角度来看,这个角度是我们能看的着,并且经常用的着。
来看一段代码

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

      public static IXXX asInterface(android.os.IBinder obj) {
          if ((obj == null)) {
              return null;
          }
          android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
          if (((iin != null) && (iin instanceof IXXX))) {
              return ((IXXX) iin);
          }
          return new IXXX.Stub.Proxy(obj);
      }

      @Override
      public android.os.IBinder asBinder() {
          return this;
      }

      @Override
      public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply,
              int flags) throws android.os.RemoteException {
          java.lang.String descriptor = DESCRIPTOR;
          switch (code) {
              case INTERFACE_TRANSACTION: {
                  reply.writeString(descriptor);
                  return true;
              }
              case TRANSACTION_methodXX: {
                  data.enforceInterface(descriptor);
                  this.methodXX(arg);
                  reply.writeNoException();
                  return true;
              }
              default: {
                  return super.onTransact(code, data, reply, flags);
              }
          }
      }

      // 对方进程使用代理类
      private static class Proxy implements IXXX {

          private android.os.IBinder mRemote;

          Proxy(android.os.IBinder remote) {
              mRemote = remote;
          }

          @Override
          public android.os.IBinder asBinder() {
              return mRemote;
          }

          public java.lang.String getInterfaceDescriptor() {
              return DESCRIPTOR;
          }

          @Override
          public void 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();
              } 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;
}

上面的代码是android 的aidl工具解析aidl文件生成的一个java文件,整个文件很清晰,定义了

  1. IXXX (这个接口定义了进程之间通信的协议)
  2. Stub (继承了Binder类)
  3. Proxy (实现了IXXX)

Stub
Stub这个类大家肯定不陌生,在Service组件中的onBind方法中会返回这个类的子类的对象(这个对象就是服务的提供者),Stub是定义在server进程中的,因此在java层可以理解为只要是继承了Binder类的类它就可以作为binder服务。

Proxy
Proxy这个类,从类名上就能看出它是在client进程中用到的,里面有一个很重要的属性

android.os.IBinder mRemote

这个属性从名字上更能看出它是指代server进程的Stub的子类对象的,mRemote它具体的类型是BinderProxy

binder服务
java层中只要继承了Binder类就可以作为binder服务了,native层Binder对应的类是BBinder。咱们通常的用法是把Binder通过Service组件的onBind方法返回,Binder类的对象还可以在Activity或者其他代码中通过Parcel传递到driver层,作为binder进程通信的binder服务

binder服务引用
binder服务引用在java层是BinderProxy,在native层是BpBinder。BinderProxy的对象是由jni层生成的,它会指向native层的BpBinder,BpBinder有一个很重要的属性mHandle,后面会着中说它的作用,以及生成规则。

Binder与BinderProxy是对应关系, BBinder与BpBinder是对应关系,binder进程通信从表面上看实际是Binder与BinderProxy 或 BBinder与BpBinder之间的通信。

Binder,BinderProxy,BBinder,BpBinder都可以被写入Parcel中,传递到driver层。

2. 协议

不管是socket通信还是web通信,它们都需要定义自己的协议,比如socket通信中,client与server端需要定义好协议,如code值都有啥,数据以啥开头以啥结尾,数据长度是多少。web通信的协议就很多了比如http,tcp,udp等等。那同理binder进程之间通信也需要定义自己的协议,因为binder进程通信分为:

  1. 进程与driver层通信
  2. “driver层代理进程”之间通信

那我们从这两方面来介绍下。

driver层代理进程:driver层中其实是有一个结构体(binder_proc)与上层进程有一个对应关系的,这个东东我就起了个名字叫 driver层代理进程

2.1 进程与driver层通信的协议

binder的准备工作 提到进程与driver层通信中最为频繁的结构体是binder_write_read,binder_write_read中的write_buffer是进程发送给driver层的数据,read_buffer是driver层发送给进程的数据。我们通过socket通信时,客户端和服务端传输的数据是需要定义一些协议,比如下面的协议

cmd + 数据长度 + 数据

这样根据cmd就需要调用哪些功能了,其次在把数据拿出来进行处理。

同理,通过binder_write_read进行进程与driver层通信时,也需要定义一些协议,协议如下:

cmd + 数据(binder_transaction_data)
  1. 进程发送给driver层的数据时,cmd是格式是 BC_XX ,以BC开头,
  2. driver层返回给进程的数据格式是 BR_XX, 以BR开头

cmd

cmd有BR_TRANSACTION,BR_TRANSACTION_COMPLETE,BR_REPLY,BR_OK
BC_TRANSACTION,BC_REPLY,BC_FREE_BUFFER等,
其中BR_TRANSACTION,BR_REPLY,BC_TRANSACTION,BC_REPLY使用最多主要用来进程之间通信的。

数据

数据是存放在binder_transaction_data,这里的数据其实主要是上层传递的binder服务(BBinder)或binder服务引用(BpBinder),方法code值,方法参数,看下它的定义

struct binder_transaction_data 
{
      // handle,ptr 分别对应BpBinder,BBinder
      union {
        __u32 handle;
        binder_uintptr_t ptr;
      } target;
      binder_uintptr_t cookie;
      // code 调用的服务的方法对应的code值
      __u32 code;
      __u32 flags;
      // 发送者的进程id
      pid_t sender_pid;
      uid_t sender_euid;
      // 参数长度相关信息
      binder_size_t data_size;
      binder_size_t offsets_size;
     // 参数具体数据
      union {
        struct {
          binder_uintptr_t buffer;
          binder_uintptr_t offsets;
        } ptr;
        __u8 buf[8];
      } data;
};

target 存放了 binder服务 或者binder服务引用,里面的handle,ptr 分别对应BpBinderBBinder,target的主要作用就是在告诉driver层我要调用哪个服务

code 对应的是方法的code值
sender_pid 发送者的进程id
data_sizeoffsets_size 参数长度信息
data 就是具体的参数信息了。

2.2 "driver层代理进程"之间的通信协议

"driver层代理进程"之间的通信是binder进程通信的基础,每个"driver层代理进程"可以理解为代表者上层的一个进程。它们之间通信协议也是

  cmd + 数据

只不过协议是被放在binder_work结构体中的。

cmd

cmd有BINDER_WORK_TRANSACTION,BINDER_WORK_TRANSACTION_COMPLETE,BINDER_WORK_NODE,BINDER_WORK_DEAD_BINDER等,它们都是以BINDER_WORK开头的。

数据

数据是存放在binder_transaction结构体中的,先看下它的结构,后面会着中介绍它

struct binder_transaction {
    int debug_id;
    struct binder_work work;
    // from信息是用来进行回复给对方信息用的,使用在同步通信环节
    struct binder_thread *from;
    struct binder_transaction *from_parent;
    // to信息存放目标方面信息
    struct binder_proc *to_proc;
    struct binder_thread *to_thread;
    struct binder_transaction *to_parent;
    unsigned need_reply:1;
    /* unsigned is_dead:1; */   /* not used at the moment */
    // 参数信息
    struct binder_buffer *buffer;
    // 方法code值
    unsigned int    code;
    unsigned int    flags;
    long    priority;
    long    saved_priority;
    kuid_t  sender_euid;
};

fromfrom_parentto_proc等信息是用来在driver层帮助确认通信的来源和去向的。
code 还是方法的对应的code值
binder_buffer 存放binder服务和方法的参数等信息,它的定义在下面

struct binder_buffer {
    struct list_head entry; /* free and allocated entries by address */
    struct rb_node rb_node; /* free entry by size or allocated entry */
                /* by address */
    unsigned free:1;
    // 是否允许上层释放空间
    unsigned allow_user_free:1;
    // 异步/同步
    unsigned async_transaction:1;
    unsigned debug_id:29;

    struct binder_transaction *transaction;
    // 目标node,会对应上层的binder服务
    struct binder_node *target_node;
    // 主要是参数信息
    size_t data_size;
    size_t offsets_size;
    uint8_t data[0];
};

allow_user_free 是否允许上层释放占有的空间。
async_transaction 代表是同步还是异步通信。
target_node 指向binder服务。
data_sizeoffsets_sizedata[0] 参数相关信息

2.3 binder通信协议总结

1.client请求server 协议cmd+数据 封包拆包过程

  1. client进程把 BC_TRANSACTION + binder_transaction_databinder服务引用 handle,方法code,方法参数) 传递到driver层
  2. "driver层代理进程 clent"收到数据后把binder_transaction_data的数据进行拆包,把binder服务引用 handle,方法code,方法参数以及driver层的其他数据数据封包到binder_transaction中,把cmd为** BINDER_WORK_TRANSACTIONbinder_transaction放入binder_work**中。
  3. “driver层代理进程 server”收到binder_work后(具体是怎么收到这个数据的后面的 “记录链路”结构体 会讲),把它拆包,把code,方法参数,binder服务(这时候handle已经转换为binder服务了) 放入 binder_transaction_data中。
  4. “driver层代理进程 server” 把 BR_TRANSACTION + binder_transaction_data 传递给 server进程,server进程在它自己的biner线程中 把 code,方法参数,binder服务解析出来后开始执行binder服务方法。

cmd转换过程 BC_TRANSACTION--->BINDER_WORK_TRANSACTION--->BR_TRANSACTION

2.server返回结果给client 协议cmd+数据 封包拆包过程

  1. server进程把 BC_REPLY + binder_transaction_data返回结果) 传递到driver层
  2. "driver层代理进程 server"收到数据后把binder_transaction_data的数据进行拆包,把返回结果和driver层的一些数据封包到binder_transaction中,把cmd为BINDER_WORK_TRANSACTIONbinder_transaction封包到binder_work中。
  3. “driver层代理进程 client”收到binder_work后(具体是怎么收到这个数据的后面的 “记录链路”结构体 会讲),把它拆包,把返回结果 放入 binder_transaction_data中。
  4. “driver层代理进程 client” 把 BR_REPLY + binder_transaction_data 传递给 client进程,client进程把返回结果解析出来

cmd转换过程 BC_REPLY--->BINDER_WORK_TRANSACTION--->BR_REPLY

3. "记录链路"结构体

为什么要叫做 "记录链路"结构体, 我个人理解driver层的结构体主要有两个关键作用:

  1. 记录上层进程中的信息,从而在driver层能够有信息与上层进程的信息对应起来。
  2. “链路”是指这些结构体为binder进程通信搭建了一条链路,那通信协议等可以在链路上传输了。

3.1 binder_node

3.1.1 binder_node结构体

binder_node记录了 进程中binder服务(Binder,BBinder) 的关键信息,这样就可以与Binder,BBinder形成了对应关系,它的定义如下:

struct binder_node {
    int debug_id;
    struct binder_work work;
    union {
        struct rb_node rb_node;
        struct hlist_node dead_node;
    };
    // 所属进程相关信息
    struct binder_proc *proc;
    struct hlist_head refs;
    int internal_strong_refs;
    int local_weak_refs;
    int local_strong_refs;
    // 指向上层的binder服务
    binder_uintptr_t ptr;
    binder_uintptr_t cookie;
    // 引用数值相关信息
    unsigned has_strong_ref:1;
    unsigned pending_strong_ref:1;
    unsigned has_weak_ref:1;
    unsigned pending_weak_ref:1;
    unsigned has_async_transaction:1;
    unsigned accept_fds:1;
    unsigned min_priority:8;
    struct list_head async_todo;
};

binder_node与 进程中binder服务 关联后,driver层内核线程收到事务后,binder_node就可以把信息传递给 进程中binder服务了。

has_strong_refhas_weak_ref等主要用来记录binder_node引用方面的信息的。

binder_node只在当前的“driver层代理进程”中存在,它封装的是Binder(java层),BBinder(native层)的信息

3.1.2 binder_node生成时机

先来看段代码:

static void binder_transaction(struct binder_proc *proc,
                   struct binder_thread *thread,
                   struct binder_transaction_data *tr, int reply)
{

    省略代码...

    for (; offp < off_end; offp++) {
        struct flat_binder_object *fp;

        省略代码... 

        // fp 存储着上层进程的binder实例,这个binder是Binder,BBinder,BinderProxy,BpBinder类型中的某一个实例
        fp = (struct flat_binder_object *)(t->buffer->data + *offp);
        off_min = *offp + sizeof(struct flat_binder_object);
        switch (fp->type) {
        // 若当前是BINDER_TYPE_BINDER或者BINDER_TYPE_WEAK_BINDER,则能说明这个binder实例是binder服务(Binder,BBinder)
        case BINDER_TYPE_BINDER:
        case BINDER_TYPE_WEAK_BINDER: {
            struct binder_ref *ref;
            struct binder_node *node = binder_get_node(proc, fp->binder);
            // 若从当前的binder_proc中没有取到binder_node,则创建一个binder_node来封装上层进程的binder实例信息,并把它存放于binder_proc的nodes红黑树中
            if (node == NULL) {
                node = binder_new_node(proc, fp->binder, fp->cookie);
                
        省略代码...

            }
            
            // 从target_proc(binder_proc)中获取binder_ref,没有则依据binder_node创建binder_ref,并且把创建的binder_ref放入target_proc的refs红黑树中
            ref = binder_get_ref_for_node(target_proc, node);
            
      省略代码...

            // 因为binder_ref是传递给 target_proc的,因此它是一个引用,它传递到 上层进程后的binder实例是(BinderProxy,BpBinder)
            if (fp->type == BINDER_TYPE_BINDER)
                fp->type = BINDER_TYPE_HANDLE;
            else
                fp->type = BINDER_TYPE_WEAK_HANDLE;
            // 把desc赋值给handle
            fp->handle = ref->desc;
            
            省略代码...

        } break;
        // 若当前是BINDER_TYPE_HANDLE或者BINDER_TYPE_WEAK_HANDLE,则能说明这个binder实例是binder服务引用(BinderProxy,BpBinder)
        case BINDER_TYPE_HANDLE:
        case BINDER_TYPE_WEAK_HANDLE: {
            struct binder_ref *ref = binder_get_ref(proc, fp->handle);

            省略代码...
      
            // 若target_proc就是当前进程,则需要把binder实例是binder服务引用类型的转为 binder服务类型
            if (ref->node->proc == target_proc) {
                if (fp->type == BINDER_TYPE_HANDLE)
                    fp->type = BINDER_TYPE_BINDER;
                else
                    fp->type = BINDER_TYPE_WEAK_BINDER;
                fp->binder = ref->node->ptr;
                fp->cookie = ref->node->cookie;
                binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL);
                
                省略代码...

            } else {
                struct binder_ref *new_ref;
                // 从target_proc(binder_proc)中获取binder_ref,没有则依据binder_node创建binder_ref,并且把创建的binder_ref放入target_proc的refs红黑树中
                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;
                
                省略代码...
            }
        } break;

        省略代码...

    }
    
}

binder_transaction这个方法后续还会介绍,上面是摘取了其中一段代码,这段代码有以下几个作用:

  1. 把当前proc(binder_proc)的数据拷贝到target_proc,这也是一直说的binder进程通信数据只拷贝一次的地方。
  2. 若proc中的数据是binder服务(Binder,BBinder),
    2.1 则创建binder_node(封装了binder实例),把创建的binder_node存放在proc的nodes红黑树中。
    2.2 在target_proc中创建binder_ref(指向刚刚创建的binder_node),创建成功binder_ref后会返回一个desc(这个值就是binder服务引用的handle),在把binder_ref放入target_proc的refs_by_desc红黑树中
    2.3 把binder服务转换为binder服务引用(fp-type变为BINDER_TYPE_HANDLE),fp->handle = ref->desc,这样binder服务引用就会返回给target_proc对应的进程
  3. 若proc中的数据是binder服务引用(BinderProxy,BpBinder)
    3.1 若proc与target_proc相等,则把binder服务引用转为binder服务。
    3.2 否则,重复2.2--2.3过程

从上面的流程可以分析得知,当binder通信过程中,传递的参数数据中包含binder服务时就会创建binder_node。

3.2 binder_ref
3.2.1 binder_ref结构体

binder_ref记录了 进程中binder服务引用(BinderProxy, BpBinder) 的关键信息(其实就是handle),从而与BinderProxy,BpBinder形成对应关系,看下它的定义

struct binder_ref {
    /* Lookups needed: */
    /*   node + proc => ref (transaction) */
    /*   desc + proc => ref (transaction, inc/dec ref) */
    /*   node => refs + procs (proc exit) */
    int debug_id;
    struct rb_node rb_node_desc;
    struct rb_node rb_node_node;
    struct hlist_node node_entry;
    // ref所属的进程
    struct binder_proc *proc;
    // 所指向的binder_node
    struct binder_node *node;
    // desc就是上层的handle
    uint32_t desc;
    int strong;
    int weak;
    struct binder_ref_death *death;
};

binder_ref是指向binder_node的引用,它存在于 使用binder服务的 “driver层代理进程”中。

desc就是BpBinder中的handle,因此在进行binder进程通信时,上层进程传递下来的BpBinder中的handle传递到driver层后,通过handle找到binder_ref,进而找到binder_node。关于查找过程后面会有讲解。

3.2.2 binder_ref创建时机

从上面 2.4.1.2 binder_node生成时机 可以得知,当两个binder_proc之间进行通信时通信数据包含binder服务或binder引用并且通信这两个binder_proc不相等,则会在目标binder_proc中创建binder_ref。binder_ref,及binder服务引用它们的创建都是一个被动的过程,binder服务引用是driver层创建成功后,把创建成功实例传给上层进程,因此BinderProxy它是被jni层代码初始化的。

3.3 binder_thread

3.3.1 binder_thread结构体

binder_thread与 进程中的binder线程(IPCThreadState) 是一一对应关系,binder线程是由ProcessState类孵化出来的,它的定义如下:

struct binder_thread {
  // 所属进程信息
    struct binder_proc *proc;
    struct rb_node rb_node;
    int pid;
    int looper;
    struct binder_transaction *transaction_stack;
    struct list_head todo;
    uint32_t return_error; /* Write failed, return error code in read buf */
    uint32_t return_error2; /* Write failed, return error code in read */
        /* buffer. Used when sending a reply to a dead process that */
        /* we are also waiting on */
    wait_queue_head_t wait;
    struct binder_stats stats;
};

looper的值是

enum {
    // driver层通知 进程启动binder线程,启动成功后进程返回这个值
    BINDER_LOOPER_STATE_REGISTERED  = 0x01,
    //  ProcessState启动binder主线程成功后发送给driver层这个值
    BINDER_LOOPER_STATE_ENTERED     = 0x02,
    // 进程中的binder线程离开时,发送此值给driver层
    BINDER_LOOPER_STATE_EXITED      = 0x04,
    BINDER_LOOPER_STATE_INVALID     = 0x08,
   // 内核线程处于等待状态,没有任何事务时 是这个值
    BINDER_LOOPER_STATE_WAITING     = 0x10,
    // 需要返回结果的looper
    BINDER_LOOPER_STATE_NEED_RETURN = 0x20
};

之一,它根据 收到进程binder线程的状态值 来改变自己的状态值。

transaction_stack 主要用于binder进程同步通信时,等待binder服务的结果时,它的值是发送给binder服务时的binder_transaction。

todo 这个有点意思,它其实就是一个队列,主要存放binder_work,就是一个生产者/消费者模式,其他“driver层代理进程”往todo里面放binder_work,这个内核线程消费binder_work。

3.3.2 binder_thread创建时机

上层进程ProcessState孵化一个binder线程后,binder线程通过IPCThreadState与driver层通信后,就会在driver层创建binder_thread。

3.4 binder_proc

3.4.1 binder_proc结构体

binder_proc与 进程(ProcessState) 是一一对应关系,ProcessState是单例的,先看下它的定义:

struct binder_proc {
    struct hlist_node proc_node;
    // binder_thread 红黑树
    struct rb_root threads;
    // binder_node 红黑树
    struct rb_root nodes;
    // binder_ref 红黑树
    struct rb_root refs_by_desc;
    struct rb_root refs_by_node;
    // 上层进程id
    int pid;

    省略代码...

    struct page **pages;
    size_t buffer_size;
    uint32_t buffer_free;
    // 存放binder_work队列
    struct list_head todo;
    wait_queue_head_t wait;
    struct binder_stats stats;
    struct list_head delivered_death;
    // 能开启的最大binder线程数,这个值是 ProcessState发送的
    int max_threads;
    // 正在请求 ProcessState开启binder线程的 请求数量
    int requested_threads;
    // 已经启动的binder线程数
    int requested_threads_started;
    // 当前空闲的处于等待事务的binder线程数
    int ready_threads;
    long default_priority;
    struct dentry *debugfs_entry;
};

threadsnodesrefs_by_descrefs_by_node分别是binder_thread,binder_node,binder_ref的红黑树,也就是binder_proc中存储了binder_thread,binder_node,binder_ref等信息,只不过为了效率是以红黑树的形式存储的。

todo同binder_thread中的队列一样,是用来存储binder_work的。

max_threadsrequested_threadsrequested_threads_startedready_threads都是与binder线程有关的信息。

3.4.2 binder_proc创建时机

其实binder的准备工作讲解了,在open binder driver后就会创建binder_proc。

3.5 总结

用一张图来总结下讲的"记录链路"结构体的内容吧


"记录链路"结构体.jpg

虚线代表各结构体与上层进程各对象的是一个一一对应的关系

3.5.1 "记录链路"结构体是怎么样链路的

binder_proc,binder_node,binder_ref这几个结构体一起在binder进程通信过程中起一个“链路”的作用。我们来简单描述下这个“链路”过程(下面的流程分析都是基于client进程已经拿到了binder服务引用BinderProxy,关于怎么拿到它后面还会介绍):

  1. 进程client最终通过 ioctl(fd,BINDER_WRITE_READ,binder_write_read)把数据传递到driver层
  2. 通过fd把对应的binder_proc找到
  3. 从binder_write_read中拿到handle值
  4. 根据handle从binder_proc的refs红黑树中取出binder_ref
  5. 根据binder_ref取到binder_node
  6. 根据binder_node取到target_proc(binder_proc)
  7. 把binder_node,通信数据等放入target_proc的todo队列中中或者target_proc的target_thread的todo队列中
  8. 唤醒target_proc中处于等待的内核线程,从binder_transaction中拿出binder服务传递给 上层进程,这样在binder线程中调用binder服务的相应方法。

这样只要这个 "链路"打通了,那在“链路”上就可以传递数据了(协议)

4. 总结

我们用一张图来总结本篇内容


binder协议链路过程.jpg
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269