前言
binder的準備工作主要介紹了binder進程通信之前需要做的準備工作有哪些菇怀,既然binder準備工作做好了,那下一步就是通信了续室,在講解通信之前熊泵,我希望先把通信的基礎知識講清楚甫匹,比如進程與driver層之間的通信協(xié)議是啥造虎?binder_node块攒,binder_ref谦疾,binder_thread南蹂,binder_proc這些東西到底都是啥?在通信過程中起啥作用念恍?Binder六剥,BinderProxy,BpBinder峰伙,BBinder又是啥疗疟?只有把這些基礎知識了解清楚,對于后面的內(nèi)容理解才能胸有成竹瞳氓。
本篇內(nèi)容
- 從“表面”看binder服務/引用是啥策彤?
- 協(xié)議
2.1 進程與driver層的通信協(xié)議
2.2 "driver層代理進程"之間的通信協(xié)議
2.3 binder通信協(xié)議總結(jié) - "記錄鏈路"結(jié)構(gòu)體
3.1 binder_node
3.2 binder_ref
3.3 binder_thread
3.4 binder_proc
3.5 總結(jié) - 總結(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文件,整個文件很清晰囊咏,定義了
- IXXX (這個接口定義了進程之間通信的協(xié)議)
- Stub (繼承了Binder類)
- 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進程通信分為:
- 進程與driver層通信
- “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)
- 進程發(fā)送給driver層的數(shù)據(jù)時,cmd是格式是 BC_XX 侧纯,以BC開頭新锈,
- 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 分別對應BpBinder,BBinder驯用,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_parent,to_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ù) 封包拆包過程
- client進程把 BC_TRANSACTION + binder_transaction_data(binder服務引用 handle,方法code街夭,方法參數(shù)) 傳遞到driver層
- "driver層代理進程 clent"收到數(shù)據(jù)后把binder_transaction_data的數(shù)據(jù)進行拆包砰碴,把binder服務引用 handle,方法code板丽,方法參數(shù)以及driver層的其他數(shù)據(jù)數(shù)據(jù)封包到binder_transaction中呈枉,把cmd為** BINDER_WORK_TRANSACTION和binder_transaction放入binder_work**中。
- “driver層代理進程 server”收到binder_work后(具體是怎么收到這個數(shù)據(jù)的后面的 “記錄鏈路”結(jié)構(gòu)體 會講)埃碱,把它拆包猖辫,把code,方法參數(shù)砚殿,binder服務(這時候handle已經(jīng)轉(zhuǎn)換為binder服務了) 放入 binder_transaction_data中啃憎。
- “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ù) 封包拆包過程
- server進程把 BC_REPLY + binder_transaction_data(返回結(jié)果) 傳遞到driver層
- "driver層代理進程 server"收到數(shù)據(jù)后把binder_transaction_data的數(shù)據(jù)進行拆包羡藐,把返回結(jié)果和driver層的一些數(shù)據(jù)封包到binder_transaction中叹阔,把cmd為BINDER_WORK_TRANSACTION和binder_transaction封包到binder_work中。
- “driver層代理進程 client”收到binder_work后(具體是怎么收到這個數(shù)據(jù)的后面的 “記錄鏈路”結(jié)構(gòu)體 會講)传睹,把它拆包,把返回結(jié)果 放入 binder_transaction_data中岸晦。
- “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)體主要有兩個關鍵作用:
- 記錄上層進程中的信息,從而在driver層能夠有信息與上層進程的信息對應起來邢隧。
- “鏈路”是指這些結(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ù)還會介紹,上面是摘取了其中一段代碼吼驶,這段代碼有以下幾個作用:
- 把當前proc(binder_proc)的數(shù)據(jù)拷貝到target_proc惩激,這也是一直說的binder進程通信數(shù)據(jù)只拷貝一次的地方。
- 若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對應的進程 - 若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遥皂,nodes,refs_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_threads,requested_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)體與上層進程各對象的是一個一一對應的關系
3.5.1 "記錄鏈路"結(jié)構(gòu)體是怎么樣鏈路的
binder_proc颁井,binder_node,binder_ref這幾個結(jié)構(gòu)體一起在binder進程通信過程中起一個“鏈路”的作用蠢护。我們來簡單描述下這個“鏈路”過程(下面的流程分析都是基于client進程已經(jīng)拿到了binder服務引用BinderProxy雅宾,關于怎么拿到它后面還會介紹):
- 進程client最終通過 ioctl(fd,BINDER_WRITE_READ糊余,binder_write_read)把數(shù)據(jù)傳遞到driver層
- 通過fd把對應的binder_proc找到
- 從binder_write_read中拿到handle值
- 根據(jù)handle從binder_proc的refs紅黑樹中取出binder_ref
- 根據(jù)binder_ref取到binder_node
- 根據(jù)binder_node取到target_proc(binder_proc)
- 把binder_node秀又,通信數(shù)據(jù)等放入target_proc的todo隊列中中或者target_proc的target_thread的todo隊列中
- 喚醒target_proc中處于等待的內(nèi)核線程,從binder_transaction中拿出binder服務傳遞給 上層進程贬芥,這樣在binder線程中調(diào)用binder服務的相應方法吐辙。
這樣只要這個 "鏈路"打通了,那在“鏈路”上就可以傳遞數(shù)據(jù)了(協(xié)議)
4. 總結(jié)
我們用一張圖來總結(jié)本篇內(nèi)容