淺析Binder(二)——基礎數據結構

Binder是通過AIDL來描述進程間通信的接口的,Binder作為一個特殊的字符設備,設備節(jié)點是/dev/binder。

一張從大牛那搬來的圖,很形象也解釋了很多東西。

binder_4relationship.jpg

在驅動程序中有幾個數據結構還是很有必要分析一下的
kernel/goldfish/drivers/staging/android/binder.c

1 binder_work

struct binder_work{
  struct list_head entry;
  enum{
    BINDER_WORK_TRANSACTION=1;
    BINDER_WORK_TRANSACTION_COMPLETE;
    BINDER_WORK_NODE;
    BINDER_WORK_DEAD_BINDER;
    BINDER_WORK_DEAD_BINDER_AND_CLEAR;
    BINDER_WORK_CLEAR_DEATH_NOTIFICATION;
  }
}

該結構體用來描述待處理的工作項,這些工作項有可能屬于一個進程,也可能屬于某個進程的線程。成員entry 用來將這些結構體嵌入到宿主結構中,成員變量type用來描述工作項的類型。根據type的取值,binder驅動程序可以判斷出一個binder_work嵌入到什么類型的宿主結構中。

2 binder_node

struct binder_node {
 int debug_id; 
struct binder_work work; 
union { 
    struct rb_node rb_node; // 如果這個Binder實體還在使用,則將該節(jié)點鏈接到proc->nodes中。相當于紅黑二叉樹的節(jié)點
    struct hlist_node dead_node; // 如果這個Binder實體所屬的進程已經銷毀,而這個Binder實體又被其它進程所引用,則這個Binder實體通過dead_node進入到一個哈希表中去存放 
}; 
struct binder_proc *proc; // 該binder實體所屬的Binder進程 
struct hlist_head refs; // 該Binder實體的所有Binder引用所組成的鏈表 int 
//強引用計數和弱引用計數管理Binder對象生命周期
internal_strong_refs; 
int local_weak_refs; 
int local_strong_refs; 
void __user *ptr; // Binder實體在用戶空間的地址(為Binder實體對應的Server在用戶空間的本地Binder的引用) 
void __user *cookie; // Binder實體在用戶空間的其他數據(為Binder實體對應的Server在用戶空間的本地Binder自身)
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實體對象。每一個Service在驅動程序中都對應一個Binder實體對象,用來描述他在內核中的狀態(tài)。

  • ** proc:指向一個Binder實體對象的宿主進程*。
  • rb_node: 宿主進程是通過一個紅黑二叉樹來管理binder實體對象的,而這個成員變量就是這個紅黑二叉樹的一個節(jié)點
  • dead_node:如果Binder實體對象的宿主進程死亡,但是這個這個Binder實體對象需要暫存一下自己,這樣不用再次使用原宿主進程的時候再重新創(chuàng)建Binder實體對象,所以它通過變量dead_node來將自己保存在一個全局的hash類表中。
  • refs: Binder實體對象有可能被多個Client組件引用,所以需要使用refs來描述這些引用關系,并且將它們保存在同一個hash列表中。Binder驅動可以通過它知道那些client組件引用了同一個Binder實體對象。
  • ** cookie*:指向該Service組件的地址
  • ** ptr:指向該Service組件內部的一個引用計數對象*的地址
  • has_async_transaction:用來描述一個Binder實體對象是否正在處理一個異步事務,如果是則他的值等于1。
  • aysnc_todo:描述異步事務隊列。每一個事務都關聯(lián)著一個Binder實體對象,要求這個Binder實體對象對應的Service組件在指定的線程中處理該事物。但是異步事務只會有一個得到處理,所以其余等待的異步事務都保存在該隊列中。
  • accept_fds:用來描述一個Binder實體對象是否可以接收包含有文件描述符的進程通信你數據,1表示可以
  • min_priority : 表示Binder實體對象在處理一個來自Client進程的請求時,他所要求的處理線程(即Server進程中的一個線程)應該具備的最小線程優(yōu)先級。

Binder驅動通過強應用和弱引用技術來維護他們的生命周期。internal_strong_refslocal_strong_refs均是用來描述一個Binder實體的強引用計數;local_weak_refs用來描述弱引用計數。當Binder實體對象請求一個Service組件來執(zhí)行某一個操作時,會增加強引用計數或弱引用計數,相應的has_strong_refhas_weak_ref的值會至[1]。當Service組件完成操作后,就會減少強引用或者弱引用計數。Binder實體對象在請求Service組件增加或減少強引用(或弱引用)計數的過程中 pending_strong_refpending_weak_ref的值置[1],使用之后Binder實體對象會將這兩個成員變量的值設置為[0]。當引用計數0變1或1變0時,work的值就變?yōu)?strong>BINDER_WORK_NODE,并將它添加到todo隊列中等待處理

3 binder_ref

struct binder_ref { 
    int debug_id; 
    struct rb_node rb_node_desc; // 關聯(lián)到binder_proc->refs_by_desc紅黑樹中
    struct rb_node rb_node_node; // 關聯(lián)到binder_proc->refs_by_node紅黑樹中 
    struct hlist_node node_entry; // 關聯(lián)到binder_node->refs哈希表中,hash列表的節(jié)點
    struct binder_proc *proc; // 該Binder引用所屬的Binder進程 
    struct binder_node *node; // 該Binder引用對應的Binder實體 
    uint32_t desc; // 描述 
    int strong; //強引用計數
    int weak; //弱引用計數
    struct binder_ref_death *death; //指向一個Service組件的死亡通知
};

前面有介紹是用來描述Binder引用對象。宿主進程使用兩個紅黑樹來保存它內部所有的Binder引用對象。分別是句柄值(用來描述一個Binder引用對象)和Binder實體對象的地址,rb_node_desc和rb_node_node就正好是這兩個紅黑樹的節(jié)點。

4 binder_ref_death

struct binder_ref_death{
    struct binder_work work;
    void _user *cookie; //保存負責接受死亡通知的對象的地址
}

用來描述一個Service組件的死亡通知。
因為Client無法控制他所引用的Service組件的生命周期,所以當Service意外崩潰的時候只能向Binder驅動程序中注冊一個死亡通知,將其保存在cookie指正指向位置。然后根據這個通知work會取相應的值。

5 binder_buffer

struct binder_buffer { 
    struct list_head entry; // 和binder_proc->buffers關聯(lián)到同一鏈表,從而使Binder進程對內存進行管理。 
    struct rb_node rb_node; // 和binder_proc->free_buffers或binder_proc->allocated_buffers關聯(lián)到同一紅黑樹,從而對已有內存和空閑內存進行管理。
    unsigned free:1; // 空閑與否的標記 
    unsigned allow_user_free:1; 
    unsigned async_transaction:1;  //異步事務置"1"
    unsigned debug_id:29; 
    struct binder_transaction *transaction; //描述該緩沖區(qū)正在交給那個緩沖區(qū)處理
    struct binder_node *target_node;  //目標Binder實體對象
    size_t data_size; 
    size_t offsets_size;
    uint8_t data[0];};

描述一個內核緩沖區(qū),用來在進程件傳遞數據。

6. binder_proc

struct binder_proc { 
struct hlist_node proc_node; // 根據proc_node,可以獲取該進程在"全局哈希表binder_procs(統(tǒng)計了所有的binder proc進程)"中的位置 
struct rb_root threads; // binder_proc進程內用于處理用戶請求的線程組成的紅黑樹(關聯(lián)binder_thread->rb_node) 
struct rb_root nodes; // binder_proc進程內的binder實體組成的紅黑樹(關聯(lián)binder_node->rb_node) 
struct rb_root refs_by_desc; // binder_proc進程內的binder引用組成的紅黑樹,該引用以句柄來排序(關聯(lián)binder_ref->rb_node_desc) 
struct rb_root refs_by_node; // binder_proc進程內的binder引用組成的紅黑樹,該引用以它對應的binder實體的地址來排序(關聯(lián)binder_ref->rb_node)
int pid; // 進程id 
struct vm_area_struct *vma; // 進程的內核虛擬內存 
struct mm_struct *vma_vm_mm; 
struct task_struct *tsk; // 進程控制結構體(每一個進程都由task_struct 數據結構來定義)。 
struct files_struct *files; // 保存了進程打開的所有文件表數據 
struct hlist_node deferred_work_node; int deferred_work; void *buffer; // 該進程映射的物理內存在內核空間中的起始位置 
ptrdiff_t user_buffer_offset; // 內核虛擬地址與進程虛擬地址之間的差值 // 內存管理的相關變量 
struct list_head buffers; // 和binder_buffer->entry關聯(lián)到同一鏈表,從而對Binder內存進行管理 
struct rb_root free_buffers; // 空閑內存,和binder_buffer->rb_node關聯(lián)。 
struct rb_root allocated_buffers; // 已分配內存,和binder_buffer->rb_node關聯(lián)。 
size_t free_async_space; struct page **pages; // 映射內存的page頁數組,page是描述物理內存的結構體 
size_t buffer_size; // 映射內存的大小 
uint32_t buffer_free; 
struct list_head todo; // 該進程的待處理事件隊列。
 wait_queue_head_t wait; // 等待隊列。 
struct binder_stats stats; 
struct list_head delivered_death; 
int max_threads; // 最大線程數。定義threads中可包含的最大進程數。 int requested_threads; 
int requested_threads_started; 
int ready_threads; 
long default_priority; // 默認優(yōu)先級。 
struct dentry *debugfs_entry;
};

該結構體用來描述一個正在使用Binder進程間通信機制的進程。可以借此查考一下如何用結構體內來描述一個進程

7. binder_thread

struct binder_thread { 
struct binder_proc *proc; // 線程所屬的Binder進程 
struct rb_node rb_node; // 紅黑樹節(jié)點,關聯(lián)到紅黑樹binder_proc->threads中。 
int pid; // 進程id int looper; // 線程狀態(tài)??梢匀INDER_LOOPER_STATE_REGISTERED等值 
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 */ 
wait_queue_head_t wait; // 等待隊列 
struct binder_stats stats; // 保存一些統(tǒng)計信息};

該結構用來描述一個線程池中的一個線程

8. binder_transaction

struct binder_transaction{
    int debug_id;
    struct binder_work work; //當Binder驅動程序為目標進程或者目標線程創(chuàng)建一個事務時,就會將work的值設置為BINDER_WORK_TRANSACTION

    struct binder_thread *from; //發(fā)起事務線程,稱為源線程
    sturct binder_proc *to_proc; //負責處理該事物的進程
    sturct binder_thread *to_thread; //負責處理該事物的線程

    struct binser_transaction *from_parent; //依賴事務
    struct binder_transaction *to_parent; //目標線程需要處理的下一個事務

    unsigned need_reply : 1; //區(qū)分事務是同步還是異步;1表示同步事務,需要等待對方回應。
    struct binder_buffer *buffer; //驅動程序為該事務分配的一塊內核緩沖區(qū)
    unsigned int code;
    unsigned int flags;

    long priority; //源線程優(yōu)先級
    long saved_priority; //線程處理一個事務時,需要先修改他的線程優(yōu)先級,來滿足Service組件的要求,所以需要使用這個變量來保存原先的優(yōu)先級
    uid_t sender_euid; //用戶ID
};
該結構提用來描述進程間通信過程,又叫事務。

9. binder_write_read

struct binder_write_read { 
    signed long write_size; 
    signed long write_consumed; 
    unsigned long write_buffer; 
    signed long read_size; 
    signed long read_consumed; 
    unsigned long read_buffer;
};

該結構體用來描述進程間通信過程中所傳輸的數據。write_buffer和read_buffer都是一個數組,數組的每一個元素都是由一個通信協(xié)議代碼及其通信數據組成。

10.binder_transaction_data

struct binder_transaction_data { 
union { 
    size_t handle; // 當binder_transaction_data是由用戶空間的進程發(fā)送給Binder驅動時, 
                   // handle是該事務的發(fā)送目標在Binder驅動中的信息,即該事務會交給handle來處理;
                   // handle的值是目標在Binder驅動中的Binder引用。 
    void *ptr; // 當binder_transaction_data是有Binder驅動反饋給用戶空間進程時, 
               // ptr是該事務的發(fā)送目標在用戶空間中的信息,即該事務會交給ptr對應的服務來處理;
               // ptr是處理該事務的服務的服務在用戶空間的本地Binder對象。 
} target;      // 該事務的目標對象(即,該事務數據包是給該target來處理的) 
void *cookie; // 只有當事務是由Binder驅動傳遞給用戶空間時,cookie才有意思,它的值是處理該事務的Server位于C++層的本地Binder對象 
unsigned int code; // 事務編碼。如果是請求,則以BC_開頭;如果是回復,則以BR_開頭。 
unsigned int flags; //標志值,用來描述京城間通信行為特征
pid_t sender_pid;  //發(fā)起進程間通信請求的進程的PID
uid_t sender_euid;  //發(fā)起進程間通信請求的進程的UID
size_t data_size; // 數據大小 
size_t offsets_size; // 數據中包含的對象的個數 
union { 
    struct { 
      const void *buffer; 
      const void *offsets; 
    } ptr; //
    uint8_t buf[8]; 
} data; // 數據
};

該結構體用來描述進程間通信過程中所傳輸的數據

11.flat_binder_object

struct flat_binder_object { 
unsigned long type; // binder類型:可以為BINDER_TYPE_BINDER或BINDER_TYPE_HANDLE等類型 
unsigned long flags; // 標記 
union { 
    void *binder; // 當type=BINDER_TYPE_BINDER時,它指向Binder對象位于C++層的本地Binder對象(即BBinder對象)的弱引用。 
    signed long handle; // 當type=BINDER_TYPE_HANDLE時,它等于Binder對象在Binder驅動中對應的Binder實體的Binder引用的描述。 
}; 
void *cookie; // 當type=BINDER_TYPE_BINDER時才有效,它指向Binder對象位于C++層的本地Binder對象(即BBinder對象)。 
};

該結構體除了可以描述一個Binder實體對象和Binder引用對象之外,還可以用來描述一個文件描述符,可以通過type來區(qū)別

通信協(xié)議代碼

kerner/goldfish/drivers/staging/android/binder.h

1. BinderDriverCommandProtocol

命令協(xié)議代碼,在輸入緩沖區(qū)write_buffer中使用

2. BinderDriverReturnProtocol

返回協(xié)議代碼,在輸出緩沖區(qū)read_buffer中使用

內容有點枯燥,但是對于后面的學習很有幫助

</br>
</br>

參考:
http://wangkuiwu.github.io/2014/09/02/Binder-Datastruct/#anchor1_7
《Android系統(tǒng)源代碼情景分析》羅升陽大神著

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容