Android底層:通熟易懂的分析binder--2. binder進程通信協(xié)議及“記錄鏈路”結(jié)構(gòu)體

前言

binder的準備工作主要介紹了binder進程通信之前需要做的準備工作有哪些菇怀,既然binder準備工作做好了,那下一步就是通信了续室,在講解通信之前熊泵,我希望先把通信的基礎知識講清楚甫匹,比如進程與driver層之間的通信協(xié)議是啥造虎?binder_node块攒,binder_ref谦疾,binder_thread南蹂,binder_proc這些東西到底都是啥?在通信過程中起啥作用念恍?Binder六剥,BinderProxy,BpBinder峰伙,BBinder又是啥疗疟?只有把這些基礎知識了解清楚,對于后面的內(nèi)容理解才能胸有成竹瞳氓。

本篇內(nèi)容

  1. 從“表面”看binder服務/引用是啥策彤?
  2. 協(xié)議
    2.1 進程與driver層的通信協(xié)議
    2.2 "driver層代理進程"之間的通信協(xié)議
    2.3 binder通信協(xié)議總結(jié)
  3. "記錄鏈路"結(jié)構(gòu)體
    3.1 binder_node
    3.2 binder_ref
    3.3 binder_thread
    3.4 binder_proc
    3.5 總結(jié)
  4. 總結(jié)

會用到的詞語:
client進程:binder進程通信的client端(使用binder服務)
server進程:binder進程通信的server端(提供binder服務)
driver層代理進程:driver層中其實是有一個結(jié)構(gòu)體(binder_proc)與上層進程有一個對應關系的,這個東東我就起了個名字叫 driver層代理進程匣摘。

1. 從“表面”看binder服務/引用是啥店诗?

從“表面”看是指我們從app開發(fā)的角度來看,這個角度是我們能看的著音榜,并且經(jīng)常用的著庞瘸。
來看一段代碼

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 (這個接口定義了進程之間通信的協(xié)議)
  2. Stub (繼承了Binder類)
  3. Proxy (實現(xiàn)了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茅诱,后面會著中說它的作用,以及生成規(guī)則搬卒。

Binder與BinderProxy是對應關系瑟俭, BBinder與BpBinder是對應關系,binder進程通信從表面上看實際是Binder與BinderProxy 或 BBinder與BpBinder之間的通信契邀。

Binder摆寄,BinderProxy,BBinder坯门,BpBinder都可以被寫入Parcel中微饥,傳遞到driver層。

2. 協(xié)議

不管是socket通信還是web通信古戴,它們都需要定義自己的協(xié)議畜号,比如socket通信中,client與server端需要定義好協(xié)議允瞧,如code值都有啥,數(shù)據(jù)以啥開頭以啥結(jié)尾蛮拔,數(shù)據(jù)長度是多少述暂。web通信的協(xié)議就很多了比如http,tcp建炫,udp等等畦韭。那同理binder進程之間通信也需要定義自己的協(xié)議,因為binder進程通信分為:

  1. 進程與driver層通信
  2. “driver層代理進程”之間通信

那我們從這兩方面來介紹下肛跌。

driver層代理進程:driver層中其實是有一個結(jié)構(gòu)體(binder_proc)與上層進程有一個對應關系的艺配,這個東東我就起了個名字叫 driver層代理進程

2.1 進程與driver層通信的協(xié)議

binder的準備工作 提到進程與driver層通信中最為頻繁的結(jié)構(gòu)體是binder_write_read察郁,binder_write_read中的write_buffer是進程發(fā)送給driver層的數(shù)據(jù),read_buffer是driver層發(fā)送給進程的數(shù)據(jù)转唉。我們通過socket通信時皮钠,客戶端和服務端傳輸?shù)臄?shù)據(jù)是需要定義一些協(xié)議,比如下面的協(xié)議

cmd + 數(shù)據(jù)長度 + 數(shù)據(jù)

這樣根據(jù)cmd就需要調(diào)用哪些功能了赠法,其次在把數(shù)據(jù)拿出來進行處理麦轰。

同理,通過binder_write_read進行進程與driver層通信時砖织,也需要定義一些協(xié)議款侵,協(xié)議如下:

cmd + 數(shù)據(jù)(binder_transaction_data)
  1. 進程發(fā)送給driver層的數(shù)據(jù)時,cmd是格式是 BC_XX 侧纯,以BC開頭新锈,
  2. driver層返回給進程的數(shù)據(jù)格式是 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使用最多主要用來進程之間通信的。

數(shù)據(jù)

數(shù)據(jù)是存放在binder_transaction_data茂腥,這里的數(shù)據(jù)其實主要是上層傳遞的binder服務(BBinder)或binder服務引用(BpBinder)狸涌,方法code值,方法參數(shù)最岗,看下它的定義

struct binder_transaction_data 
{
      // handle帕胆,ptr 分別對應BpBinder,BBinder
      union {
        __u32 handle;
        binder_uintptr_t ptr;
      } target;
      binder_uintptr_t cookie;
      // code 調(diào)用的服務的方法對應的code值
      __u32 code;
      __u32 flags;
      // 發(fā)送者的進程id
      pid_t sender_pid;
      uid_t sender_euid;
      // 參數(shù)長度相關信息
      binder_size_t data_size;
      binder_size_t offsets_size;
     // 參數(shù)具體數(shù)據(jù)
      union {
        struct {
          binder_uintptr_t buffer;
          binder_uintptr_t offsets;
        } ptr;
        __u8 buf[8];
      } data;
};

target 存放了 binder服務 或者binder服務引用般渡,里面的handle懒豹,ptr 分別對應BpBinderBBinder驯用,target的主要作用就是在告訴driver層我要調(diào)用哪個服務

code 對應的是方法的code值
sender_pid 發(fā)送者的進程id
data_size脸秽,offsets_size 參數(shù)長度信息
data 就是具體的參數(shù)信息了。

2.2 "driver層代理進程"之間的通信協(xié)議

"driver層代理進程"之間的通信是binder進程通信的基礎蝴乔,每個"driver層代理進程"可以理解為代表者上層的一個進程记餐。它們之間通信協(xié)議也是

  cmd + 數(shù)據(jù)

只不過協(xié)議是被放在binder_work結(jié)構(gòu)體中的。

cmd

cmd有BINDER_WORK_TRANSACTION薇正,BINDER_WORK_TRANSACTION_COMPLETE片酝,BINDER_WORK_NODE囚衔,BINDER_WORK_DEAD_BINDER等,它們都是以BINDER_WORK開頭的雕沿。

數(shù)據(jù)

數(shù)據(jù)是存放在binder_transaction結(jié)構(gòu)體中的练湿,先看下它的結(jié)構(gòu),后面會著中介紹它

struct binder_transaction {
    int debug_id;
    struct binder_work work;
    // from信息是用來進行回復給對方信息用的晦炊,使用在同步通信環(huán)節(jié)
    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 */
    // 參數(shù)信息
    struct binder_buffer *buffer;
    // 方法code值
    unsigned int    code;
    unsigned int    flags;
    long    priority;
    long    saved_priority;
    kuid_t  sender_euid;
};

from鞠鲜,from_parentto_proc等信息是用來在driver層幫助確認通信的來源和去向的断国。
code 還是方法的對應的code值
binder_buffer 存放binder服務和方法的參數(shù)等信息贤姆,它的定義在下面

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;
    // 主要是參數(shù)信息
    size_t data_size;
    size_t offsets_size;
    uint8_t data[0];
};

allow_user_free 是否允許上層釋放占有的空間稳衬。
async_transaction 代表是同步還是異步通信霞捡。
target_node 指向binder服務。
data_size薄疚,offsets_size碧信,data[0] 參數(shù)相關信息

2.3 binder通信協(xié)議總結(jié)

1.client請求server 協(xié)議cmd+數(shù)據(jù) 封包拆包過程

  1. client進程把 BC_TRANSACTION + binder_transaction_databinder服務引用 handle,方法code街夭,方法參數(shù)) 傳遞到driver層
  2. "driver層代理進程 clent"收到數(shù)據(jù)后把binder_transaction_data的數(shù)據(jù)進行拆包砰碴,把binder服務引用 handle,方法code板丽,方法參數(shù)以及driver層的其他數(shù)據(jù)數(shù)據(jù)封包到binder_transaction中呈枉,把cmd為** BINDER_WORK_TRANSACTIONbinder_transaction放入binder_work**中。
  3. “driver層代理進程 server”收到binder_work后(具體是怎么收到這個數(shù)據(jù)的后面的 “記錄鏈路”結(jié)構(gòu)體 會講)埃碱,把它拆包猖辫,把code,方法參數(shù)砚殿,binder服務(這時候handle已經(jīng)轉(zhuǎn)換為binder服務了) 放入 binder_transaction_data中啃憎。
  4. “driver層代理進程 server” 把 BR_TRANSACTION + binder_transaction_data 傳遞給 server進程,server進程在它自己的biner線程中 把 code似炎,方法參數(shù)辛萍,binder服務解析出來后開始執(zhí)行binder服務方法。

cmd轉(zhuǎn)換過程 BC_TRANSACTION--->BINDER_WORK_TRANSACTION--->BR_TRANSACTION

2.server返回結(jié)果給client 協(xié)議cmd+數(shù)據(jù) 封包拆包過程

  1. server進程把 BC_REPLY + binder_transaction_data返回結(jié)果) 傳遞到driver層
  2. "driver層代理進程 server"收到數(shù)據(jù)后把binder_transaction_data的數(shù)據(jù)進行拆包羡藐,把返回結(jié)果和driver層的一些數(shù)據(jù)封包到binder_transaction中叹阔,把cmd為BINDER_WORK_TRANSACTIONbinder_transaction封包到binder_work中。
  3. “driver層代理進程 client”收到binder_work后(具體是怎么收到這個數(shù)據(jù)的后面的 “記錄鏈路”結(jié)構(gòu)體 會講)传睹,把它拆包,把返回結(jié)果 放入 binder_transaction_data中岸晦。
  4. “driver層代理進程 client” 把 BR_REPLY + binder_transaction_data 傳遞給 client進程欧啤,client進程把返回結(jié)果解析出來

cmd轉(zhuǎn)換過程 BC_REPLY--->BINDER_WORK_TRANSACTION--->BR_REPLY

3. "記錄鏈路"結(jié)構(gòu)體

為什么要叫做 "記錄鏈路"結(jié)構(gòu)體睛藻, 我個人理解driver層的結(jié)構(gòu)體主要有兩個關鍵作用:

  1. 記錄上層進程中的信息,從而在driver層能夠有信息與上層進程的信息對應起來邢隧。
  2. “鏈路”是指這些結(jié)構(gòu)體為binder進程通信搭建了一條鏈路店印,那通信協(xié)議等可以在鏈路上傳輸了。

3.1 binder_node

3.1.1 binder_node結(jié)構(gòu)體

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;
    // 引用數(shù)值相關信息
    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服務 關聯(lián)后炫贤,driver層內(nèi)核線程收到事務后,binder_node就可以把信息傳遞給 進程中binder服務了付秕。

has_strong_ref兰珍,has_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,則創(chuàng)建一個binder_node來封裝上層進程的binder實例信息,并把它存放于binder_proc的nodes紅黑樹中
            if (node == NULL) {
                node = binder_new_node(proc, fp->binder, fp->cookie);
                
        省略代碼...

            }
            
            // 從target_proc(binder_proc)中獲取binder_ref奉瘤,沒有則依據(jù)binder_node創(chuàng)建binder_ref勾拉,并且把創(chuàng)建的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服務引用類型的轉(zhuǎn)為 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肌访,沒有則依據(jù)binder_node創(chuàng)建binder_ref找默,并且把創(chuàng)建的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這個方法后續(xù)還會介紹,上面是摘取了其中一段代碼吼驶,這段代碼有以下幾個作用:

  1. 把當前proc(binder_proc)的數(shù)據(jù)拷貝到target_proc惩激,這也是一直說的binder進程通信數(shù)據(jù)只拷貝一次的地方。
  2. 若proc中的數(shù)據(jù)是binder服務(Binder,BBinder)蟹演,
    2.1 則創(chuàng)建binder_node(封裝了binder實例)风钻,把創(chuàng)建的binder_node存放在proc的nodes紅黑樹中。
    2.2 在target_proc中創(chuàng)建binder_ref(指向剛剛創(chuàng)建的binder_node)酒请,創(chuàng)建成功binder_ref后會返回一個desc(這個值就是binder服務引用的handle)骡技,在把binder_ref放入target_proc的refs_by_desc紅黑樹中
    2.3 把binder服務轉(zhuǎn)換為binder服務引用(fp-type變?yōu)锽INDER_TYPE_HANDLE),fp->handle = ref->desc,這樣binder服務引用就會返回給target_proc對應的進程
  3. 若proc中的數(shù)據(jù)是binder服務引用(BinderProxy,BpBinder)
    3.1 若proc與target_proc相等布朦,則把binder服務引用轉(zhuǎn)為binder服務囤萤。
    3.2 否則,重復2.2--2.3過程

從上面的流程可以分析得知,當binder通信過程中,傳遞的參數(shù)數(shù)據(jù)中包含binder服務時就會創(chuàng)建binder_node匣沼。

3.2 binder_ref
3.2.1 binder_ref結(jié)構(gòu)體

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創(chuàng)建時機

從上面 2.4.1.2 binder_node生成時機 可以得知远剩,當兩個binder_proc之間進行通信時通信數(shù)據(jù)包含binder服務或binder引用并且通信這兩個binder_proc不相等,則會在目標binder_proc中創(chuàng)建binder_ref骇窍。binder_ref瓜晤,及binder服務引用它們的創(chuàng)建都是一個被動的過程,binder服務引用是driver層創(chuàng)建成功后腹纳,把創(chuàng)建成功實例傳給上層進程痢掠,因此BinderProxy它是被jni層代碼初始化的。

3.3 binder_thread

3.3.1 binder_thread結(jié)構(gòu)體

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主線程成功后發(fā)送給driver層這個值
    BINDER_LOOPER_STATE_ENTERED     = 0x02,
    // 進程中的binder線程離開時佃牛,發(fā)送此值給driver層
    BINDER_LOOPER_STATE_EXITED      = 0x04,
    BINDER_LOOPER_STATE_INVALID     = 0x08,
   // 內(nèi)核線程處于等待狀態(tài)淹辞,沒有任何事務時 是這個值
    BINDER_LOOPER_STATE_WAITING     = 0x10,
    // 需要返回結(jié)果的looper
    BINDER_LOOPER_STATE_NEED_RETURN = 0x20
};

之一,它根據(jù) 收到進程binder線程的狀態(tài)值 來改變自己的狀態(tài)值俘侠。

transaction_stack 主要用于binder進程同步通信時象缀,等待binder服務的結(jié)果時,它的值是發(fā)送給binder服務時的binder_transaction爷速。

todo 這個有點意思央星,它其實就是一個隊列,主要存放binder_work惫东,就是一個生產(chǎn)者/消費者模式莉给,其他“driver層代理進程”往todo里面放binder_work,這個內(nèi)核線程消費binder_work。

3.3.2 binder_thread創(chuàng)建時機

上層進程ProcessState孵化一個binder線程后禁谦,binder線程通過IPCThreadState與driver層通信后胁黑,就會在driver層創(chuàng)建binder_thread。

3.4 binder_proc

3.4.1 binder_proc結(jié)構(gòu)體

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線程數(shù)漂洋,這個值是 ProcessState發(fā)送的
    int max_threads;
    // 正在請求 ProcessState開啟binder線程的 請求數(shù)量
    int requested_threads;
    // 已經(jīng)啟動的binder線程數(shù)
    int requested_threads_started;
    // 當前空閑的處于等待事務的binder線程數(shù)
    int ready_threads;
    long default_priority;
    struct dentry *debugfs_entry;
};

threads遥皂,nodesrefs_by_desc刽漂,refs_by_node分別是binder_thread演训,binder_node,binder_ref的紅黑樹贝咙,也就是binder_proc中存儲了binder_thread样悟,binder_node,binder_ref等信息庭猩,只不過為了效率是以紅黑樹的形式存儲的窟她。

todo同binder_thread中的隊列一樣,是用來存儲binder_work的蔼水。

max_threads震糖,requested_threadsrequested_threads_started趴腋,ready_threads都是與binder線程有關的信息吊说。

3.4.2 binder_proc創(chuàng)建時機

其實binder的準備工作講解了,在open binder driver后就會創(chuàng)建binder_proc优炬。

3.5 總結(jié)

用一張圖來總結(jié)下講的"記錄鏈路"結(jié)構(gòu)體的內(nèi)容吧


"記錄鏈路"結(jié)構(gòu)體.jpg

虛線代表各結(jié)構(gòu)體與上層進程各對象的是一個一一對應的關系

3.5.1 "記錄鏈路"結(jié)構(gòu)體是怎么樣鏈路的

binder_proc颁井,binder_node,binder_ref這幾個結(jié)構(gòu)體一起在binder進程通信過程中起一個“鏈路”的作用蠢护。我們來簡單描述下這個“鏈路”過程(下面的流程分析都是基于client進程已經(jīng)拿到了binder服務引用BinderProxy雅宾,關于怎么拿到它后面還會介紹):

  1. 進程client最終通過 ioctl(fd,BINDER_WRITE_READ糊余,binder_write_read)把數(shù)據(jù)傳遞到driver層
  2. 通過fd把對應的binder_proc找到
  3. 從binder_write_read中拿到handle值
  4. 根據(jù)handle從binder_proc的refs紅黑樹中取出binder_ref
  5. 根據(jù)binder_ref取到binder_node
  6. 根據(jù)binder_node取到target_proc(binder_proc)
  7. 把binder_node秀又,通信數(shù)據(jù)等放入target_proc的todo隊列中中或者target_proc的target_thread的todo隊列中
  8. 喚醒target_proc中處于等待的內(nèi)核線程,從binder_transaction中拿出binder服務傳遞給 上層進程贬芥,這樣在binder線程中調(diào)用binder服務的相應方法吐辙。

這樣只要這個 "鏈路"打通了,那在“鏈路”上就可以傳遞數(shù)據(jù)了(協(xié)議)

4. 總結(jié)

我們用一張圖來總結(jié)本篇內(nèi)容


binder協(xié)議鏈路過程.jpg
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蘸劈,一起剝皮案震驚了整個濱河市昏苏,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖贤惯,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件洼专,死亡現(xiàn)場離奇詭異,居然都是意外死亡孵构,警方通過查閱死者的電腦和手機屁商,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來颈墅,“玉大人蜡镶,你說我怎么就攤上這事⌒羯福” “怎么了官还?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長毒坛。 經(jīng)常有香客問我望伦,道長,這世上最難降的妖魔是什么煎殷? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任屯伞,我火速辦了婚禮,結(jié)果婚禮上蝌数,老公的妹妹穿的比我還像新娘愕掏。我一直安慰自己,他們只是感情好顶伞,可當我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布饵撑。 她就那樣靜靜地躺著,像睡著了一般唆貌。 火紅的嫁衣襯著肌膚如雪滑潘。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天锨咙,我揣著相機與錄音语卤,去河邊找鬼。 笑死酪刀,一個胖子當著我的面吹牛粹舵,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播骂倘,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼眼滤,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了历涝?” 一聲冷哼從身側(cè)響起诅需,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤漾唉,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后堰塌,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體赵刑,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年场刑,在試婚紗的時候發(fā)現(xiàn)自己被綠了般此。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡牵现,死狀恐怖恤煞,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情施籍,我是刑警寧澤,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布概漱,位于F島的核電站丑慎,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏瓤摧。R本人自食惡果不足惜竿裂,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望照弥。 院中可真熱鬧腻异,春花似錦、人聲如沸这揣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽给赞。三九已至机打,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間片迅,已是汗流浹背残邀。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留柑蛇,地道東北人芥挣。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像耻台,于是被迫代替她去往敵國和親空免。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,689評論 2 354