首先聲明一下這是一個(gè)討論帖,我只是論述一下個(gè)人的觀點(diǎn),歡迎大家講事實(shí)擺道理。
前言
大家都知道App進(jìn)程是AMS通過通過Socket通信通知Zygote孵化出來的,借用gityuan的圖就是圖中的第2步,能否用Binder通信替換Socket通信?我們只討論技術(shù)上實(shí)現(xiàn)的可能性,不討論兩者性能上的差異。
我的觀點(diǎn)
能替換成Binder通信。
我的論據(jù)
我實(shí)在是想不出用Binder通信替換Socket通信的缺陷在哪里?
別人觀點(diǎn)
既然我想不出,肯定網(wǎng)上有人持否定態(tài)度,我們看看他們說的有沒有道理。
觀點(diǎn)1:并發(fā)問題
鏈接:
https://blog.csdn.net/qq_39037047/article/details/88066589
觀點(diǎn)描述:
怕父進(jìn)程binder線程有鎖,然后子進(jìn)程的主線程一直在等其子線程(從父進(jìn)程拷貝過來的子進(jìn)程)的資源,但是其實(shí)父進(jìn)程的子進(jìn)程并沒有被拷貝過來,造成死鎖,所以fork不允許存在多線程。而非常巧的是Binder通訊偏偏就是多線程,所以干脆父進(jìn)程(Zygote)這個(gè)時(shí)候就不使用binder線程
反駁:
我們完全可以將Zygote進(jìn)程的主線程作為唯一的Binder線程,這樣子也就沒有這個(gè)問題了。
觀點(diǎn)2:父子進(jìn)程共享FD問題(其實(shí)這個(gè)是我以前早期的觀點(diǎn))
觀點(diǎn)描述:
因?yàn)閆ygote在open("dev/binder")中帶有的flag是O_CLOEXEC,fork之后,在子進(jìn)程執(zhí)行EXEC的時(shí)候,會(huì)因?yàn)镺_CLOEXEC的條件關(guān)閉這個(gè)共享FD,就會(huì)調(diào)用binder_release的代碼,順帶清空父進(jìn)程的FD對(duì)應(yīng)file結(jié)構(gòu)體中private_data對(duì)象保存的binder_proc,影響父進(jìn)程的Binder通信功能。
/frameworks/native/libs/binder/ProcessState.cpp
static int open_driver(const char *driver)
{
int fd = open(driver, O_RDWR | O_CLOEXEC);
return fd;
}
drivers/staging/android/binder.c
static int binder_release(struct inode *nodp, struct file *filp)
{
struct binder_proc *proc = filp->private_data;
debugfs_remove(proc->debugfs_entry);
binder_defer_work(proc, BINDER_DEFERRED_RELEASE);//調(diào)用到代碼1.1
return 0;
}
//1.1
binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer)
{
mutex_lock(&binder_deferred_lock);
proc->deferred_work |= defer;
if (hlist_unhashed(&proc->deferred_work_node)) {
hlist_add_head(&proc->deferred_work_node,
&binder_deferred_list);
//發(fā)起一個(gè)workqueue去執(zhí)行binder_deferred_work,也就是代碼1.2
queue_work(binder_deferred_workqueue, &binder_deferred_work);
}
mutex_unlock(&binder_deferred_lock);
}
//1.2
static DECLARE_WORK(binder_deferred_work, binder_deferred_func);
static void binder_deferred_func(struct work_struct *work)
{
...
do {
...
if (defer & BINDER_DEFERRED_RELEASE)
binder_deferred_release(proc); /* frees proc */ //代碼1.3
...
} while (proc);
}
//1.3
static void binder_deferred_release(struct binder_proc *proc)
{
...
kfree(proc);//這里會(huì)釋放父進(jìn)程的binder_proc
}
反駁:
鏈接:https://blog.csdn.net/scarecrow_byr/article/details/91410131
上述的觀點(diǎn)對(duì)O_CLOEXEC的理解有些偏差,正確的理解應(yīng)該是在linux系統(tǒng)中,父進(jìn)程打開一個(gè)文件fd可以帶上O_CLOEXEC標(biāo)志位,fork之后,子進(jìn)程得到父進(jìn)程的完整拷貝,對(duì)于父進(jìn)程已經(jīng)open的文件,子進(jìn)程也可以得到一樣的fd。內(nèi)核里,子進(jìn)程只是把fd對(duì)應(yīng)的file指針指向父進(jìn)程fd對(duì)應(yīng)的struct file,并且把file的引用加1。子進(jìn)程中用exec系列系統(tǒng)調(diào)用加載新的可執(zhí)行程序之前,會(huì)關(guān)閉子進(jìn)程中父進(jìn)程O_CLOEXEC標(biāo)志打開的fd。子進(jìn)程關(guān)閉該fd時(shí)候,但是因?yàn)楦高M(jìn)程還持有fd的引用計(jì)數(shù),所以這個(gè)關(guān)閉的動(dòng)作只會(huì)執(zhí)行fops的flush回調(diào)函數(shù),并沒有真正調(diào)用fops的release回調(diào)函數(shù)。
看Binder驅(qū)動(dòng)中實(shí)現(xiàn)的flush回調(diào)函數(shù)binder_flush,最后調(diào)用的binder_deferred_flush方法中,并沒有釋放binder_proc,只是喚醒一下父進(jìn)程的Binder線程而已。
static void binder_deferred_flush(struct binder_proc *proc)
{
struct rb_node *n;
int wake_count = 0;
for (n = rb_first(&proc->threads); n != NULL; n = rb_next(n)) {
struct binder_thread *thread = rb_entry(n, struct binder_thread, rb_node);
thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN;
if (thread->looper & BINDER_LOOPER_STATE_WAITING) {
wake_up_interruptible(&thread->wait);
wake_count++;
}
}
wake_up_interruptible_all(&proc->wait);
binder_debug(BINDER_DEBUG_OPEN_CLOSE,
"binder_flush: %d woke %d threads\n", proc->pid,
wake_count);
}
總結(jié)
以上就是我覺得看似合理的兩個(gè)觀點(diǎn)的反駁,如果你們有新的觀點(diǎn),或者覺得我的反駁中的論據(jù)有問題。
歡迎留言交流。