我覺得,chatgpt的答案好像更適合答題。
為什么zygote使用socket而不是binder
Zygote是Android中的一個重要進程,它是啟動應用程序進程的父進程。Zygote使用Socket來與應用程序進程進行通信,而不是使用Android中的IPC機制Binder,這是因為Socket和Binder有不同的優(yōu)缺點,而在Zygote進程中使用Socket可以更好地滿足Zygote進程的需求。
首先,Socket具有良好的跨平臺性,能夠在不同的操作系統(tǒng)和語言之間進行通信。這對于Zygote進程來說非常重要,因為它需要在不同的設備和架構(gòu)上運行,并且需要與不同的應用程序進程進行通信。使用Socket可以讓Zygote進程更加靈活和可擴展,因為它不需要考慮Binder所帶來的特定限制和要求。
其次,Socket具有簡單的API和易于使用的特點。Zygote進程需要快速啟動并與應用程序進程建立通信,Socket提供了快速、可靠的通信方式,并且使用Socket API也很容易實現(xiàn)。相比之下,Binder需要更多的配置和維護工作,這對于Zygote進程來說可能會增加不必要的復雜性和開銷。
最后,Socket在數(shù)據(jù)傳輸時具有更低的延遲和更高的吞吐量,這對于Zygote進程來說非常重要。Zygote進程需要在較短的時間內(nèi)啟動應用程序進程,并且需要傳輸大量的數(shù)據(jù)和代碼,Socket的高性能和低延遲使其成為更好的選擇。
總之,Zygote進程使用Socket而不是Binder是基于其優(yōu)點和需求而做出的選擇。雖然Binder在Android中扮演著重要的角色,但在某些情況下,使用Socket可以提供更好的性能和更大的靈活性。
——分割線——
看完《安卓傳奇:Android締造團隊回憶錄》后,我覺得這個問題的答案書中給出了.這段歷史是這樣的...
先來看看書中關于Zygote的靈感來源,Emacs.
是Dalvik小組為Android 1.0 開發(fā)的另一個東西。Zygote就像你做三明治時用的面包片。當然,你也可以在每次做三明治時從頭開始烤面包,但如果是這樣的話,每次你想吃三明治都要花大量的時間和精力。很明顯,如果有現(xiàn)成的面包,你只需要把它切成片,并更快更容易地做出三明治。Zygote就像做三明治用的面包。
Dan的這個想法來自Emacs(UNIX系統(tǒng)上的一個非常流行的文本編輯器)的一個特性,我們可以隨時轉(zhuǎn)儲編輯器的狀態(tài),稍后可以從這個保存點啟動Emacs(這個過程被巧妙地稱為反轉(zhuǎn)儲(undump))。這意味著Emacs可以更快地啟動,因為它只需要從磁盤上恢復狀態(tài),
不需要在啟動時重新執(zhí)行一大堆代碼邏輯?!拔业南敕ㄊ俏覀儗崿F(xiàn)一個具有反轉(zhuǎn)儲功能的系統(tǒng),就像Emacs最‘著名’(至少對我來說)的那個特性。Mike Fleming說:‘我們跳過轉(zhuǎn)儲和重新加載這些步驟,怎么樣?’說完他就開干了?!?br> Mike 讓系統(tǒng)跑了起來,從根本上改變了應用程序的啟動方式。原先的每個應用程序在啟動時都需要加載必要的代碼,并進行初始化。Zygote 創(chuàng)建了一個包含大部分核心平臺代碼的進程,并幾乎預加載和初始化了所有這些代碼。每當有應用程序啟動時,都會通過分叉
(將其復制到一個新進程中)Zygote 進程,讓應用程序立即進入即將就緒的狀態(tài)。
而binder的來源.
Binder 的概念可以追溯到 Be 公司。George Hoffman 是 Be 公司圖形和框架團隊的負責人,他需要一種機制讓 Be 的互聯(lián)網(wǎng)設備的 JavaScript UI 層與底層系統(tǒng)服務發(fā)生交互,于是就有了 Binder。隨著 Be 公司的工程師后來加入 PalmSource 開發(fā) Palm OS,再到后來加入 Android,Binder 也都一直在演化。George 最終沒有參與開發(fā) Android,但他與 Be 和 PalmSource 的未來 Android 工程師一起設計了許多概念,這些概念最終都出現(xiàn)在 Android 上,比如 Activity 和 Intent。
Android 設備上始終運行著許多進程,負責處理系統(tǒng)的各種任務。系統(tǒng)進程負責進程的管理、應用的啟動、窗口的管理和其他底層的操作系統(tǒng)功能。電話進程負責保持通話正常連接。運行中的前臺應用進程為用戶提供交互功能。系統(tǒng) UI 進程負責處理導航按鈕、狀態(tài)欄和通知。還有很多其他進程,它們都需要在某個時刻與其他流程通信。
通常來說,IPC 機制是一種簡單而底層的東西,而這也正是 Danger 前工程師們想要的。
黃威說:“Danger 做事喜歡速戰(zhàn)速決,但主要還是要簡單?!钡珌碜?Be 公司的工程師,包括 Jeff、Joe 和 Dianne,更喜歡他們在 PalmSource 實現(xiàn)的功能更全面(也更復雜)的 Binder。
況且,Binder 是開源的,可以直接用在這個新平臺上。
這一分歧造成了團隊之間的摩擦。Mike Fleming 站在 Danger 一邊:“我對 Binder 持懷疑態(tài)度。我認為它沒有經(jīng)過深思熟慮。這確實是他們在 Palm 做的,但并沒有被用在真正的產(chǎn)品中?!?br> “我感覺特別糟糕的是對Binder的阻塞調(diào)用會導致另一邊也阻塞。我覺得這導致了很多不必要的線程開銷,而且沒有為我們帶來任何價值。另外,初始的Binder Linux內(nèi)核驅(qū)動程序也不是很健壯。為了讓它更健壯,我們也是費了很大一番功夫的?!?br> 對Binder持懷疑態(tài)度的人并沒有贏得這場戰(zhàn)斗,Jeff和他的小組奮勇向前,實現(xiàn)了Binder,成為Android框架的一個基礎部分。與此同時,Mike在他的電話功能中跳過Binder:“我在Java進程和本地接口進程之間開了一個UNIX域套接字?!?/p>
binder當初并不成熟,團隊成員對于進程間通訊更傾向于用socket.后面為了做了很多優(yōu)化,才使得binder通訊變得成熟穩(wěn)定.
關于Android操作系統(tǒng),書中推薦閱讀《現(xiàn)代操作系統(tǒng)》,并深入閱讀介紹 Android 的章節(jié)(10.8)。那一章是 Dianne Hackborn 寫的,為 Binder和 Linux 擴展等內(nèi)容提供了詳盡的細節(jié)。另關于handle設計思想的理解,我推薦閱讀《C++沉思錄》.
----------分割線---------
要想了解這個問題,首先需要對Linux進程間通訊機制有一定的了解。
1.Linux進程間通訊機制
https://www.zhihu.com/question/39440766/answer/89210950
Linux現(xiàn)有的所有進程間IPC方式:
1.管道:在創(chuàng)建時分配一個page大小的內(nèi)存,緩存區(qū)大小比較有限;
2.消息隊列:信息復制兩次,額外的CPU消耗;不合適頻繁或信息量大的通信;
3.共享內(nèi)存:無須復制,共享緩沖區(qū)直接付附加到進程虛擬地址空間,速度快;但進程間的同步問題操作系統(tǒng)無法實現(xiàn),必須各進程利用同步工具解決;
4.套接字:作為更通用的接口,傳輸效率低,主要用于不通機器或跨網(wǎng)絡的通信;
5.信號量:常作為一種鎖機制,防止某進程正在訪問共享資源時,其他進程也訪問該資源。因此,主要作為進程間以及同一進程內(nèi)不同線程之間的同步手段
6.信號: 不適用于信息交換,更適用于進程中斷控制,比如非法內(nèi)存訪問,殺死某個進程等;
Binder機制基于開源的OpenBinder。http://www.angryredplanet.com/~hackbod/openbinder/docs/html/BinderIPCMechanism.html
2. socket 與 binder 對比
先來看看 socket與binder 兩種進程間通訊機制 對比。


接下來回顧下 Zygote啟動和Android啟動。
Zygote啟動過程的函數(shù)調(diào)用類大致流程:

http://gityuan.com/2016/02/13/android-zygote/#jnistartreg
Zygote啟動過程:
1.解析init.zygote.rc中的參數(shù),創(chuàng)建AppRuntime并調(diào)用AppRuntime.start()方法;
2.調(diào)用AndroidRuntime的startVM()方法創(chuàng)建虛擬機,再調(diào)用startReg()注冊JNI函數(shù);
3.通過JNI方式調(diào)用ZygoteInit.main(),第一次進入Java世界;
4.registerZygoteSocket()建立socket通道,zygote作為通信的服務端,用于響應客戶端請求;
5.preload()預加載通用類、drawable和color資源、openGL以及共享庫以及WebView,用于提高app啟動效率;
6.zygote完畢大部分工作,接下來再通過startSystemServer(),fork得力幫手system_server進程,也是上層framework的運行載體。
7.zygote功成身退,調(diào)用runSelectLoop(),隨時待命,當接收到請求創(chuàng)建新進程請求時立即喚醒并執(zhí)行相應工作。
下面來看一張圖,標示了調(diào)用startService之后的通訊流程。

圖中涉及3種IPC通信方式:
Binder、Socket以及Handler,在圖中分別用3種不同的顏色來代表這3種通信方式。一般來說,同一進程內(nèi)的線程間通信采用的是 Handler消息隊列機制,不同進程間的通信采用的是binder機制,另外與Zygote進程通信采用的Socket。
Android系統(tǒng)啟動流程如下:

現(xiàn)在回到問題,為什么Zygote通信為什么用Socket,而不是Binder?
具體可看這篇:
android中AMS通知Zygote去fork進程為什么使用socket而不使用binder?
可從以下五個方面分析:
1.先后時序問題:
binder驅(qū)動是早于init進程加載的。而init進程是安卓系統(tǒng)啟動的第一個進程。
安卓中一般使用的binder引用,都是保存在ServiceManager進程中的,而如果想從ServiceManager中獲取到對應的binder引用,前提是需要注冊。雖然Init進程是先創(chuàng)建ServiceManager,后創(chuàng)建Zygote進程的。雖然Zygote更晚創(chuàng)建,但是也不能保證Zygote進程去注冊binder的時候,ServiceManager已經(jīng)初始化好了。注冊時間點無法保證,AMS無法獲取到Zygote的binder引用,這是原因之一。

2.多線程問題
Linux中,fork進程是不推薦fork一個多線程的進程的,因為如果存在鎖的情況下,會導致鎖異常。
而如果自身作為binder機制的接收者,就會創(chuàng)建一個額外的線程來進行處理(發(fā)送者進程是無影響的)。
所以,如果使用binder機制,就會導致去fork一個多線程的進程,這是原因之二。
3.效率問題
AMS和Zygote之間使用的LocalSocket,相對于網(wǎng)絡Socket,減少了數(shù)據(jù)驗證等環(huán)節(jié),所以其實效率相對于正常的網(wǎng)絡Socket會大幅的提升。雖然還是要經(jīng)過兩次拷貝,但是由于數(shù)據(jù)量并不大,所以其實影響并不明顯。
所以,LocalSocket效率其實也不低,這是原因之三。
4.安全問題
LocalSocket其實也有權(quán)限校驗,并不意味著可以被所有進程隨意調(diào)用,這是原因之四。
5.Binder拷貝問題
如果使用binder通訊機制的話,從Zygote中fork出子進程會拷貝Zygote中binder對象。所以就憑白多占用了一塊無用的內(nèi)存區(qū)域。而Binder對象不能釋放。Binder的特殊性在于其是成對存在的,其分為Client端對象和Server端對象。假設我們使用binder,如果要釋放掉APP的Server端binder引用對象,就必須釋放掉AMS中的Client端binder對象,那這樣就會導致AMS失去binder從而無法正常向Zygote發(fā)送消息。
而使用socket通訊機制的話,fork出APP進程之后,APP進程會去主動的關閉掉這個socket,從而釋放這塊區(qū)域。相關代碼在ZygoteConnection的processCommand方法中:
try {
if (pid == 0) {
// in child
zygoteServer.setForkChild();
zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
return handleChildProc(parsedArgs, childPipeFd,
parsedArgs.mStartChildZygote);
} else {
// In the parent. A pid < 0 indicates a failure and will be handled in
// handleParentProc.
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
handleParentProc(pid, serverPipeFd);
return null;
}
}
所以,使用binder會造成額外的內(nèi)存占用,這是原因之五。
另外,binder調(diào)用一般是同步阻塞的。如果使用oneway,是非阻塞(像一些系統(tǒng)服務調(diào)用應用進程的時候就會使用 oneway,比如 AMS 調(diào)用應用進程啟動 Activity,這樣就算應用進程中做了耗時的任務,也不會阻塞系統(tǒng)服務的運行。)。但是,binder驅(qū)動對于oneway的調(diào)用是類似于handler sendmessage那樣的,挨個處理,所以如果服務端的oneway接口處理太慢而客戶端調(diào)用太多的話,來不及處理的調(diào)用會占滿binder驅(qū)動的緩存,導致其他調(diào)用拋出上面的transaction failed。
oneway 方法的隱患具體參考這篇。
AIDL oneway 方法的隱患
socket也不是單獨使用的,I/O模型中的epoll是一種高效的管理socket的模型,epoll機制相對成熟,是同步非阻塞。
socket(套接字)是對 TCP/IP 或者UDP/IP協(xié)議的封裝,Socket本身并不是協(xié)議,而是一個調(diào)用接口(API)。
而Binder很負復雜。
簡單的設計,減少出問題的幾率,會讓系統(tǒng)更加穩(wěn)定。
Zygote通信為什么用Socket,而不是Binder?
說了這么多,其實是通過對比加深對Android進程間通訊Socket和Binder兩種機制的理解。
3.Zygote 處理 socket消息代碼分析
具體代碼流程分析可看這篇:
app_process: zygote處理socket消息請求(5)
參考鏈接:
為什么 Android 要采用 Binder 作為 IPC 機制?
為什么Android的Zygote與SystemServer通信采用Socket,而不是Binder?
[026]Zygote中Socket通信能否替換成Binder通信?
Android系統(tǒng)啟動-zygote篇
Android10.0系統(tǒng)啟動之Zygote進程-[Android取經(jīng)之路]
app_process: zygote處理socket消息請求(5)
Android Framework層學習——為什么SystemServer進程與Zygote進程通訊采用Socket而不是Binder
android中AMS通知Zygote去fork進程為什么使用socket而不使用binder