寫binder的初衷
提起binder氮采,應(yīng)該會有很多人說鹰椒,binder這都已經(jīng)多么老的技術(shù)了宝鼓,并且分析binder的文章是一搜一大堆轩性,你這完全沒必要寫binder方面的文章昂拖薄格遭!
我其實對于這種觀點不以為然,說下我的理由吧:
- 對自己看過的留瞳,學(xué)過的binder知識需要有一個總結(jié)拒迅,這個總結(jié)是非常必要的,不信大家可以想想她倘,若沒有總結(jié)璧微,以前學(xué)過的知識是不是已經(jīng)忘記了很多,沒有總結(jié)那你學(xué)過的知識就是零散的硬梁,不成系統(tǒng)前硫。
- 即時binder很老了,依然會有很多人不了解荧止,有可能你會說屹电,了解它有啥用。我想說binder是android基石中的基石跃巡,android中到處都可以看到binder的身影(AMS危号,WMS等等),若了解了binder素邪,你可以對android會有一個很深的認(rèn)識外莲,進程與進程之間的交互邏輯,進程與系統(tǒng)服務(wù)之間交互邏輯等等兔朦。
- Android系統(tǒng)架構(gòu)是分為app偷线,framework,native烘绽,linux kernel層淋昭,這四層之間到底是一個什么聯(lián)系,當(dāng)了解了binder(binder貫穿了這四層)后安接,您就會對這四層之間是怎么樣協(xié)同工作來保證系統(tǒng)正常運行的翔忽。
疑惑點
在學(xué)習(xí)binder的過程中或多或少都會遇到一些疑惑點英融,設(shè)計者為什么這樣來設(shè)計,我遇到了以下的疑惑點:
- 兩個進程(client和server進程)之間通信歇式,client進程拿到的是server進程的代理類(其實是一個handle)驶悟,那這個handle是在什么時候生成的,生成規(guī)則是啥材失?
- app進程是怎么與驅(qū)動層建立一一對應(yīng)關(guān)系的
- 驅(qū)動層中client是怎么樣傳遞數(shù)據(jù)并且喚醒server的
- client進程調(diào)用server進程方法時是怎么樣導(dǎo)致阻塞的
- 驅(qū)動層的 binder_proc, binder_thread和上層(非驅(qū)動層)的進程痕鳍,線程是一個什么關(guān)系。binder_node, binder_ref, binder_nodes, binder_refs作用是啥龙巨?
- app進程是在啥時候open driver(打開驅(qū)動層)的
- ServiceManager進程起什么作用笼呆,ServiceManager存儲的是系統(tǒng)服務(wù)的代理binder,還是真正的系統(tǒng)服務(wù)對象
- app進程與系統(tǒng)服務(wù)(如AMS)進行通信時旨别,是每次都要經(jīng)過ServiceManager去拿到系統(tǒng)服務(wù)的binder嗎诗赌?
- client進程與server進程通信是否要經(jīng)過ServiceManager進程
通過閱讀源碼以及參考大牛的文章(比如gityuan,老羅)等,基本上把上面的疑惑點都解決了秸弛,因此希望能在這個系列文章中把這些疑惑給解決铭若。同時也希望自己能從一個通熟易懂的角度來給大家分析binder,這也是我在文章的題目中要加 通熟易懂 的目的递览。
當(dāng)然如果想通過一篇文章把binder講解的很清楚是不可能的叼屠,因此這會是一個系列的文章。
android的源碼是9.0.0_r3/
binder_driver層的源碼需要單獨去google官網(wǎng)下載绞铃,不要選擇goldfish(模擬器)的版本镜雨,選擇其他的版本
驅(qū)動層代碼: binder.c
首先我們從binder的準(zhǔn)備工作開始這個系列文章。為啥要從準(zhǔn)備工作講起憎兽,因為我覺得追溯一個事物要從它的根源追起冷离。
本篇內(nèi)容
- binder準(zhǔn)備工作
- 系統(tǒng)調(diào)用
- 第一個準(zhǔn)備工作:open binder driver
- 第二個準(zhǔn)備工作:mmap(內(nèi)存映射)
- 進程與driver層通信
- 第三個準(zhǔn)備工作:啟動binder主線程,接收數(shù)據(jù)
- binder準(zhǔn)備工作何時被調(diào)用
- 總結(jié)
1.binder準(zhǔn)備工作
binder在能進行進程通信之前纯命,是需要做一些準(zhǔn)備工作的西剥,這些工作大致上有下面3個:
1. open binder driver
2. mmap
3. 啟動binder主線程,接收數(shù)據(jù)
在講準(zhǔn)備工作之前亿汞,先講下系統(tǒng)調(diào)用
2.系統(tǒng)調(diào)用
app進程或系統(tǒng)進程是屬于兩個不同的進程瞭空,進程之間是沒辦法通信的,因此需要一個中間者來參與疗我,這個中間者就是linux內(nèi)核咆畏,如下圖:
app進程或系統(tǒng)進程又被稱為用戶空間, linux內(nèi)核被稱為內(nèi)核空間吴裤,
用戶空間在調(diào)用內(nèi)核空間程序的過程被稱為系統(tǒng)調(diào)用(syscall)在進行系統(tǒng)調(diào)用時旧找,用戶空間會陷入內(nèi)核態(tài)。
陷入內(nèi)核態(tài)簡單理解就是:用戶空間的線程暫停執(zhí)行(處于中斷狀態(tài))麦牺,切換到內(nèi)核線程執(zhí)行內(nèi)核程序钮蛛,當(dāng)內(nèi)核程序執(zhí)行完畢后鞭缭,切換到用戶空間,用戶空間線程恢復(fù)執(zhí)行魏颓;反之若內(nèi)核程序處于阻塞狀態(tài)岭辣,則用戶空間的線程也一直處于中斷狀態(tài)。
binder用戶空間調(diào)用到內(nèi)核空間方法的對應(yīng)關(guān)系是:
open-> binder_open, ioctl->binder_ioctl甸饱,mmap->binder_mmap 等等
系統(tǒng)調(diào)用可以說是binder的核心原理沦童。
內(nèi)核空間是共享內(nèi)存的
3. 第一個準(zhǔn)備工作:open binder driver
第一個準(zhǔn)備工作為啥是open binder driver呢?我們從代碼上分析下都做了哪些事情叹话,分析完后自然就能知道了偷遗,對應(yīng)的類是ProcessState,這個類是一個單例的驼壶,因此一個進程中只存在一個實例鹦肿,調(diào)用打開驅(qū)動的代碼如下:
static int open_driver(const char *driver){
// 打開binder driver的關(guān)鍵方法,最終會調(diào)用driver層的binder_open方法, 返回的fd很關(guān)鍵辅柴,后面與driver的交互都需要帶上它
int fd = open(driver, O_RDWR | O_CLOEXEC);
if (fd >= 0) {
int vers = 0;
// 獲取binder版本號
status_t result = ioctl(fd, BINDER_VERSION, &vers);
if (result == -1) {
ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
close(fd);
fd = -1;
}
if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
ALOGE("Binder driver protocol(%d) does not match user space protocol(%d)! ioctl() return value: %d",
vers, BINDER_CURRENT_PROTOCOL_VERSION, result);
close(fd);
fd = -1;
}
size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
// 告訴driver層可以啟動的最大的線程數(shù)
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
if (result == -1) {
ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
}
} else {
ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno));
}
return fd;
}
調(diào)用open方法后會返回一個fd值卓鹿,這個值很重要复局,后面的每次與driver通信都會用到它。
open方法最終會調(diào)到driver層的binder_open方法:
static int binder_open(struct inode *nodp, struct file *filp){
// 聲明binder_proc傍念,后續(xù)對它分配空間歪架,初始化等操作
struct binder_proc *proc;
省略代碼 ...
proc = kzalloc(sizeof(*proc), GFP_KERNEL);
if (proc == NULL)
return -ENOMEM;
get_task_struct(current);
proc->tsk = current;
proc->vma_vm_mm = current->mm;
INIT_LIST_HEAD(&proc->todo);
init_waitqueue_head(&proc->wait);
省略代碼 ...
hlist_add_head(&proc->proc_node, &binder_procs);
proc->pid = current->group_leader->pid;
INIT_LIST_HEAD(&proc->delivered_death);
filp->private_data = proc;
省略代碼 ...
return 0;
}
open binder driver這一個過程股冗,做了幾件很重要的事情:
1.在driver層對binder_proc(binder_proc記錄了很多的信息,后續(xù)會著中介紹它)進行了初始化和蚪,對binder_proc中的todo隊列等信息做了初始化止状。
2.把上層的pid(進程id)記錄在了binder_proc中
3.把binder_proc賦值給了filp->private_data,filp是和返回給上層的fd值是存在一定關(guān)系的攒霹,通過fd是可以找到filp怯疤,進而找到當(dāng)前進程的binder_proc。
4.ProcessState把返回的fd存在內(nèi)存中催束,以便與driver層進行通信
5.獲取driver層的版本信息(ioctl獲取)進行對比
6.通知driver層上層最多啟動幾個binder線程(ioctl通知)
open binder driver后集峦,上層的進程在driver層就有了記錄,后續(xù)上層進程就可以與driver層通信了(通信基本都是通過ioctl進行的)抠刺。
4. 第二個準(zhǔn)備工作:mmap(內(nèi)存映射)
ProcessState::ProcessState(const char *driver){
省略代碼...
// 打開驅(qū)動成功后
if (mDriverFD >= 0) {
// 進行內(nèi)存映射
// mmap the binder, providing a chunk of virtual address space to receive transactions.
mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
if (mVMStart == MAP_FAILED) {
// *sigh*
ALOGE("Using %s failed: unable to mmap transaction memory.\n", mDriverName.c_str());
close(mDriverFD);
mDriverFD = -1;
mDriverName.clear();
}
}
省略代碼...
}
在ProcessState中塔淤,打開binder驅(qū)動后,緊接著做mmap工作速妖。
對應(yīng)driver層的方法是: binder_mmap
binder在性能方面能優(yōu)于其他進程通信的其中一個因素是進程通信中的數(shù)據(jù)只拷貝一次高蜂,拷貝一次的重要原因就是mmap(內(nèi)存映射),關(guān)于mmap的介紹網(wǎng)上有好多的介紹罕容,這邊就不贅述了备恤。
5.進程與driver層通信
在講啟動binder主線程稿饰,接收數(shù)據(jù)內(nèi)容之前,需要把一個基礎(chǔ)的一直提到的進程與driver層通信內(nèi)容講清楚烘跺,這樣非常有利于我們理解后面的內(nèi)容湘纵。
不像socket通信,client和server端在連接建立后是可以互相發(fā)送消息的滤淳,binder進程與driver層通信原理是系統(tǒng)調(diào)用(syscall)梧喷,通信的發(fā)起方只能是上層的進程。
5.1發(fā)送數(shù)據(jù)給driver層
主要是通過ioctl方法傳遞數(shù)據(jù)脖咐,調(diào)用過程是ioctl-->binder_ioctl(driver層方法)铺敌,
ioctl(fd, cmd,數(shù)據(jù))
ioctl的參數(shù)如上屁擅,fd不用說了就是打開binder驅(qū)動返回的值(用于查找當(dāng)前進程在driver層的binder_proc)偿凭,cmd的值有BINDER_WRITE_READ,BINDER_SET_MAX_THREADS等等派歌,數(shù)據(jù)對應(yīng)的結(jié)構(gòu)體有binder_write_read等弯囊。
5.2driver層返回數(shù)據(jù)
有些調(diào)用是需要driver層返回數(shù)據(jù)的,比如cmd為BINDER_WRITE_READ的調(diào)用胶果,driver層把需要返回的數(shù)據(jù)調(diào)用copy_to_user方法copy 用戶空間中匾嘱,當(dāng)binder_ioctl方法執(zhí)行完畢后,切換到用戶空間線程早抠,這時候從binder_write_read.read_buffer中取數(shù)據(jù)霎烙。
5.3 binder_write_read
上面講完了上層進程與driver層的通信方式,為什么要說binder_write_read呢蕊连,因為binder_write_read是binder通信過程中使用最頻繁的結(jié)構(gòu)體悬垃,進程之間通信都用的是它,咱們先有一個初步的了解甘苍,后面還會在詳細介紹尝蠕,看下它的定義
struct binder_write_read {
//write開頭和傳遞給driver層的數(shù)據(jù)有關(guān)系
binder_size_t write_size;
binder_size_t write_consumed;
//write_buffer傳遞給driver層數(shù)據(jù)
binder_uintptr_t write_buffer;
//read開頭和driver層返回的數(shù)據(jù)有關(guān)系
binder_size_t read_size;
binder_size_t read_consumed;
//read_buffer driver層返回的數(shù)據(jù)
binder_uintptr_t read_buffer;
};
那我們從代碼流程上來看下是怎么樣在上層進程與driver層傳遞binder_write_read的,我們只是先簡單看下這一流程载庭,在后面部分還會著中細說這一流程細節(jié)趟佃。這個流程主要是在IPCThreadState這個類中
status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
writeTransactionData方法先把進程之間交互的關(guān)鍵數(shù)據(jù)寫入binder_transaction_data這個結(jié)構(gòu)體中,在把binder_transaction_data寫入mOut昧捷,mOut的數(shù)據(jù)最終寫入binder_write_read的write_buffer中闲昭,最終調(diào)用:
status_t IPCThreadState::talkWithDriver(bool doReceive)
talkWithDriver方法從方法名就能看出是與driver層進行通信的,doReceive為true代表等待driver層返回數(shù)據(jù)靡挥,否則不等待序矩。數(shù)據(jù)最終寫入binder_write_read中,該方法中最終調(diào)用下面方法:
ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)
ioctl最終調(diào)用到driver層的binder_ioctl方法
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
binder_ioctl方法中因為當(dāng)前的cmd是BINDER_WRITE_READ跋破,因此會執(zhí)行binder_ioctl_write_read方法
static int binder_ioctl_write_read(struct file *filp,
unsigned int cmd, unsigned long arg,
struct binder_thread *thread)
binder_ioctl_write_read方法中簸淀,binder_thread_write方法會讀取上層傳遞的數(shù)據(jù)瓶蝴,binder_thread_read方法會根據(jù)情況返回給上層數(shù)據(jù)。
binder_thread_write非常的重要租幕,比如進程通信完成通知driver層做收尾工作舷手,回復(fù)數(shù)據(jù)給對方進程,以及driver層通知上層啟動binder線程等等劲绪。先暫時簡單的介紹下這方面內(nèi)容男窟,以便于我們能更好的理解后面的內(nèi)容,在后面時我們還會詳細講解相關(guān)的內(nèi)容贾富。
6. 第三個準(zhǔn)備工作:啟動binder主線程歉眷,接收數(shù)據(jù)
6.1為什么啟動binder主線程
為什么要啟動binder主線程,拿socket通信來說颤枪,socket的client和server兩端要想進行通信汗捡,server端必須先啟動以等待client端連接進而通信。同理binder進程之間通信分為client進程和server進程的畏纲,那server進程需要監(jiān)聽client進程傳遞過來的數(shù)據(jù)扇住,那這個監(jiān)聽行為就需要放在一個線程中,那這個線程就是binder主線程盗胀,binder主線程就是一個接收者。
6.2 啟動binder主線程流程分析
那我們就從代碼上分析下读整,分析的時候會用到剛剛提到的 進程與driver層通信,binder_write_read內(nèi)容咱娶,
void ProcessState::startThreadPool()
{
AutoMutex _l(mLock);
if (!mThreadPoolStarted) {
mThreadPoolStarted = true;
// true代表啟動binder主線程
spawnPooledThread(true);
}
}
再來看下spawnPooledThread方法
void ProcessState::spawnPooledThread(bool isMain)
{
// binder主線程啟動后執(zhí)行
if (mThreadPoolStarted) {
// binder線程的名字膘侮,格式: binder:pid_x(x代表第幾個線程)
String8 name = makeBinderThreadName();
ALOGV("Spawning new pooled thread, name=%s\n", name.string());
// new一個線程isMain是否是binder主線程
sp<Thread> t = new PoolThread(isMain);
t->run(name.string());
}
}
看下PoolThread類
class PoolThread : public Thread
{
public:
explicit PoolThread(bool isMain)
: mIsMain(isMain)
{
}
protected:
virtual bool threadLoop()
{
// 線程啟動后昧诱,執(zhí)行IPCThreadState的方法
IPCThreadState::self()->joinThreadPool(mIsMain);
return false;
}
const bool mIsMain;
};
啟動線程后盏档,最終調(diào)用IPCThreadState::self()->joinThreadPool(mIsMain)方法,上面的流程主要是在ProcessState類中,現(xiàn)在切換到IPCThreadState類中
void IPCThreadState::joinThreadPool(bool isMain)
{
// mOut的數(shù)據(jù)會發(fā)送給driver層道川,BC_ENTER_LOOPER:代表是binder主線程,
//BC_REGISTER_LOOPER:代表是driver底發(fā)命令啟動的binder線程
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
status_t result;
do {
processPendingDerefs();
// 等待driver層傳遞的數(shù)據(jù),進行處理,沒數(shù)據(jù)則處于等待狀態(tài)
// now get the next command to be processed, waiting if necessary
result = getAndExecuteCommand();
省略代碼...
// 若當(dāng)前線程不再用于了并且是非主線程,則之間退出
// 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);
// binder線程退出了装诡,需要通知drive層渔伯,以便做一些處理
mOut.writeInt32(BC_EXIT_LOOPER);
// 傳false代表通知driver層后玄叠,立馬返回舀寓,不等待driver層數(shù)據(jù)
talkWithDriver(false);
}
joinThreadPool()方法,若isMain為true代表binder主線程,則不會退出育谬,基本會隨著整個進程一直存在(除非發(fā)生錯誤)膛檀。在線程退出時咖刃,也是需要通知driver層的。著中看下getAndExecuteCommand()這個方法
status_t IPCThreadState::getAndExecuteCommand()
{
status_t result;
int32_t cmd;
// 發(fā)送數(shù)據(jù)給driver層古拴,并且等待返回數(shù)據(jù)
result = talkWithDriver();
if (result >= NO_ERROR) {
size_t IN = mIn.dataAvail();
if (IN < sizeof(int32_t)) return result;
cmd = mIn.readInt32();
省略代碼...
//拿到cmd進行處理
result = executeCommand(cmd);
省略代碼...
}
return result;
}
getAndExecuteCommand()方法會調(diào)用talkWithDriver()來發(fā)送數(shù)據(jù)給driver層,并且等待driver層的返回數(shù)據(jù)油额,調(diào)用executeCommand(cmd)方法會處理返回的cmd,咱們暫時不討論這個過程芹扭,看下talkWithDriver()方法:
// doReceive默認(rèn)值為true
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
if (mProcess->mDriverFD <= 0) {
return -EBADF;
}
// 聲明一個binder_write_read
binder_write_read bwr;
// Is the read buffer empty?
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
// We don't want to write anything if we are still reading
// from data left in the input buffer and the caller
// has requested to read the next data.
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data();
// doReceive && needRead都為true,代表會等待driver層的返回數(shù)據(jù)份汗,沒返回之前處于阻塞狀態(tài)
// This is what we'll read.
if (doReceive && needRead) {
bwr.read_size = mIn.dataCapacity();
// 返回數(shù)據(jù)最終從mIn中讀取
bwr.read_buffer = (uintptr_t)mIn.data();
} else {
bwr.read_size = 0;
bwr.read_buffer = 0;
}
省略代碼...
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
省略代碼...
// 與driver層通信
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
else
err = -errno;
省略代碼...
} while (err == -EINTR);
省略代碼...
if (err >= NO_ERROR) {
if (bwr.write_consumed > 0) {
if (bwr.write_consumed < mOut.dataSize())
mOut.remove(0, bwr.write_consumed);
else {
mOut.setDataSize(0);
processPostWriteDerefs();
}
}
// 是否有返回數(shù)據(jù)
if (bwr.read_consumed > 0) {
mIn.setDataSize(bwr.read_consumed);
mIn.setDataPosition(0);
}
省略代碼...
return NO_ERROR;
}
return err;
}
talkWithDriver()方法中最終會調(diào)用ioctl與driver層通信寄猩,發(fā)送BC_ENTER_LOOPER給driver層,在講 進程與driver層通信泊柬,binder_write_read 時講到最終會走到driver層的** binder_ioctl_write_read**方法,binder_thread_write方法讀數(shù)上層的數(shù)據(jù)(暫時不介紹)荤堪,現(xiàn)在著中看下binder_thread_read方法
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
binder_size_t *consumed, int non_block)
{
省略代碼...
retry:
// wait_for_proc_work 為true,標(biāo)明當(dāng)前內(nèi)核線程沒有要處理的事務(wù)肮塞,因此即將進入等待狀態(tài)
wait_for_proc_work = thread->transaction_stack == NULL &&
list_empty(&thread->todo);
省略代碼...
if (wait_for_proc_work) {
// 當(dāng)前內(nèi)核線程進入等待狀態(tài)恋谭,等待新事務(wù)加入被喚醒
if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
BINDER_LOOPER_STATE_ENTERED))) {
binder_user_error("%d:%d ERROR: Thread waiting for process work before calling BC_REGISTER_LOOPER or BC_ENTER_LOOPER (state %x)\n",
proc->pid, thread->pid, thread->looper);
wait_event_interruptible(binder_user_error_wait,
binder_stop_on_user_error < 2);
}
binder_set_nice(proc->default_priority);
if (non_block) {
if (!binder_has_proc_work(proc, thread))
ret = -EAGAIN;
} else
ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
} else {
省略代碼...
}
省略代碼...
// 說明被喚醒了
thread->looper &= ~BINDER_LOOPER_STATE_WAITING;
if (ret)
return ret;
while (1) {
// 下面省略的代碼取出事務(wù)開始執(zhí)行
省略代碼...
}
done:
// 下面省略的代碼根據(jù)條件來通知上層進程是否開啟新的binder線程
省略代碼...
return 0;
}
binder_thread_read方法攘乒,若當(dāng)前內(nèi)核線程沒有事務(wù)要處理贤牛,則內(nèi)核線程進入等待狀態(tài),因此會導(dǎo)致上層進程對應(yīng)的binder線程也進入等待狀態(tài)则酝,若有事務(wù)了則內(nèi)核線程會被喚醒殉簸,緊接著處理事務(wù)(這部分內(nèi)容我們會在后面介紹)。
到此為止啟動binder主線程的流程基本分析完成沽讹,我們來總結(jié)下:
1.首先會在當(dāng)前進程啟動binder主線程般卑,主線程生命周期和進程是一致的。
2.進程之間畢竟是隔離的爽雄,即時啟動了binder主線程蝠检,主線程在沒有binder驅(qū)動的協(xié)調(diào)下也不會收到別的進程的數(shù)據(jù),因此binder主線程啟動完畢后會通知driver層盲链,driver層的對應(yīng)內(nèi)核線程進入等待狀態(tài)蝇率,進而導(dǎo)致上層的binder主線程進入等待狀態(tài)。
3.driver層的內(nèi)核線程收到事務(wù)后刽沾,處理后把相關(guān)的數(shù)據(jù)返回給上層進程中的對應(yīng)binder線程本慕。
4.binder線程分為主線程和普通線程,普通線程執(zhí)行完畢后一般會銷毀
7. binder準(zhǔn)備工作何時被調(diào)用
至此binder的準(zhǔn)備工作已經(jīng)完畢了侧漓,但是還有一個很重要的工作沒做锅尘,那就是binder的準(zhǔn)備工作什么時候被調(diào)用,具體調(diào)用是在app_main.cpp文件中的AppRuntime類中
virtual void onZygoteInit()
{
sp<ProcessState> proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
proc->startThreadPool();
}
onZygoteInit方法中布蔗,ProcessState::self() ProcessState構(gòu)造函數(shù)開始初始化藤违,初始化時會open binder driver,mmap纵揍,這些工作做完后執(zhí)行
proc->startThreadPool()顿乒,這個方法會啟動binder主線程,接收數(shù)據(jù)泽谨。
AppRuntime的onZygoteInit方法是在app進程zygote之后立馬就調(diào)用的璧榄,因此每個app進程只要被zygote出來后特漩,都會立馬把binder的準(zhǔn)備工作做好。
8. 總結(jié)
下面我用一張圖來總結(jié)下本篇的內(nèi)容
open binder driver 后上層進程就可以與driver層通信了骨杂,啟動binder主線程 當(dāng)前的進程就可以作為binder進程通信的server端了涂身,可以接收client進程的數(shù)據(jù)了。
不管是server進程還是client進程搓蚪,在driver層都有對應(yīng)的內(nèi)核線程處于中斷狀態(tài)蛤售,在等待事務(wù)(binder_transcation后面會著中介紹),為什么client進程也需要一個等待的內(nèi)核線程呢妒潭?這是因為client在進行進程通信時悴能,只要傳遞給別的進程的數(shù)據(jù)中包含binder(此binder是BBinder,非BpBinder代理類)對象時雳灾,client進程隨時都會變?yōu)閎inder服務(wù)的提供者搜骡。