我覺得馋评,chatgpt的答案好像更適合答題。
為什么zygote使用socket而不是binder
Zygote是Android中的一個重要進(jìn)程刺啦,它是啟動應(yīng)用程序進(jìn)程的父進(jìn)程留特。Zygote使用Socket來與應(yīng)用程序進(jìn)程進(jìn)行通信,而不是使用Android中的IPC機(jī)制Binder玛瘸,這是因為Socket和Binder有不同的優(yōu)缺點(diǎn)蜕青,而在Zygote進(jìn)程中使用Socket可以更好地滿足Zygote進(jìn)程的需求。
首先糊渊,Socket具有良好的跨平臺性右核,能夠在不同的操作系統(tǒng)和語言之間進(jìn)行通信。這對于Zygote進(jìn)程來說非常重要渺绒,因為它需要在不同的設(shè)備和架構(gòu)上運(yùn)行贺喝,并且需要與不同的應(yīng)用程序進(jìn)程進(jìn)行通信。使用Socket可以讓Zygote進(jìn)程更加靈活和可擴(kuò)展宗兼,因為它不需要考慮Binder所帶來的特定限制和要求躏鱼。
其次,Socket具有簡單的API和易于使用的特點(diǎn)针炉。Zygote進(jìn)程需要快速啟動并與應(yīng)用程序進(jìn)程建立通信挠他,Socket提供了快速、可靠的通信方式篡帕,并且使用Socket API也很容易實(shí)現(xiàn)殖侵。相比之下,Binder需要更多的配置和維護(hù)工作镰烧,這對于Zygote進(jìn)程來說可能會增加不必要的復(fù)雜性和開銷拢军。
最后,Socket在數(shù)據(jù)傳輸時具有更低的延遲和更高的吞吐量怔鳖,這對于Zygote進(jìn)程來說非常重要茉唉。Zygote進(jìn)程需要在較短的時間內(nèi)啟動應(yīng)用程序進(jìn)程,并且需要傳輸大量的數(shù)據(jù)和代碼,Socket的高性能和低延遲使其成為更好的選擇度陆。
總之艾凯,Zygote進(jìn)程使用Socket而不是Binder是基于其優(yōu)點(diǎn)和需求而做出的選擇。雖然Binder在Android中扮演著重要的角色懂傀,但在某些情況下罩息,使用Socket可以提供更好的性能和更大的靈活性枣察。
——分割線——
看完《安卓傳奇:Android締造團(tuán)隊回憶錄》后,我覺得這個問題的答案書中給出了.這段歷史是這樣的...
先來看看書中關(guān)于Zygote的靈感來源,Emacs.
是Dalvik小組為Android 1.0 開發(fā)的另一個東西笛粘。Zygote就像你做三明治時用的面包片外臂。當(dāng)然,你也可以在每次做三明治時從頭開始烤面包犀斋,但如果是這樣的話贝乎,每次你想吃三明治都要花大量的時間和精力。很明顯叽粹,如果有現(xiàn)成的面包览效,你只需要把它切成片,并更快更容易地做出三明治球榆。Zygote就像做三明治用的面包朽肥。
Dan的這個想法來自Emacs(UNIX系統(tǒng)上的一個非常流行的文本編輯器)的一個特性,我們可以隨時轉(zhuǎn)儲編輯器的狀態(tài)持钉,稍后可以從這個保存點(diǎn)啟動Emacs(這個過程被巧妙地稱為反轉(zhuǎn)儲(undump))衡招。這意味著Emacs可以更快地啟動,因為它只需要從磁盤上恢復(fù)狀態(tài)每强,
不需要在啟動時重新執(zhí)行一大堆代碼邏輯始腾。“我的想法是我們實(shí)現(xiàn)一個具有反轉(zhuǎn)儲功能的系統(tǒng)空执,就像Emacs最‘著名’(至少對我來說)的那個特性浪箭。Mike Fleming說:‘我們跳過轉(zhuǎn)儲和重新加載這些步驟,怎么樣辨绊?’說完他就開干了奶栖。”
Mike 讓系統(tǒng)跑了起來门坷,從根本上改變了應(yīng)用程序的啟動方式宣鄙。原先的每個應(yīng)用程序在啟動時都需要加載必要的代碼,并進(jìn)行初始化默蚌。Zygote 創(chuàng)建了一個包含大部分核心平臺代碼的進(jìn)程冻晤,并幾乎預(yù)加載和初始化了所有這些代碼。每當(dāng)有應(yīng)用程序啟動時绸吸,都會通過分叉
(將其復(fù)制到一個新進(jìn)程中)Zygote 進(jìn)程鼻弧,讓應(yīng)用程序立即進(jìn)入即將就緒的狀態(tài)设江。
而binder的來源.
Binder 的概念可以追溯到 Be 公司。George Hoffman 是 Be 公司圖形和框架團(tuán)隊的負(fù)責(zé)人攘轩,他需要一種機(jī)制讓 Be 的互聯(lián)網(wǎng)設(shè)備的 JavaScript UI 層與底層系統(tǒng)服務(wù)發(fā)生交互叉存,于是就有了 Binder。隨著 Be 公司的工程師后來加入 PalmSource 開發(fā) Palm OS度帮,再到后來加入 Android鹉胖,Binder 也都一直在演化。George 最終沒有參與開發(fā) Android够傍,但他與 Be 和 PalmSource 的未來 Android 工程師一起設(shè)計了許多概念,這些概念最終都出現(xiàn)在 Android 上挠铲,比如 Activity 和 Intent冕屯。
Android 設(shè)備上始終運(yùn)行著許多進(jìn)程,負(fù)責(zé)處理系統(tǒng)的各種任務(wù)拂苹。系統(tǒng)進(jìn)程負(fù)責(zé)進(jìn)程的管理安聘、應(yīng)用的啟動、窗口的管理和其他底層的操作系統(tǒng)功能瓢棒。電話進(jìn)程負(fù)責(zé)保持通話正常連接浴韭。運(yùn)行中的前臺應(yīng)用進(jìn)程為用戶提供交互功能。系統(tǒng) UI 進(jìn)程負(fù)責(zé)處理導(dǎo)航按鈕脯宿、狀態(tài)欄和通知念颈。還有很多其他進(jìn)程,它們都需要在某個時刻與其他流程通信连霉。
通常來說榴芳,IPC 機(jī)制是一種簡單而底層的東西,而這也正是 Danger 前工程師們想要的跺撼。
黃威說:“Danger 做事喜歡速戰(zhàn)速決窟感,但主要還是要簡單∏妇”但來自 Be 公司的工程師柿祈,包括 Jeff、Joe 和 Dianne哩至,更喜歡他們在 PalmSource 實(shí)現(xiàn)的功能更全面(也更復(fù)雜)的 Binder躏嚎。
況且,Binder 是開源的憨募,可以直接用在這個新平臺上紧索。
這一分歧造成了團(tuán)隊之間的摩擦。Mike Fleming 站在 Danger 一邊:“我對 Binder 持懷疑態(tài)度菜谣。我認(rèn)為它沒有經(jīng)過深思熟慮珠漂。這確實(shí)是他們在 Palm 做的晚缩,但并沒有被用在真正的產(chǎn)品中∠蔽#”
“我感覺特別糟糕的是對Binder的阻塞調(diào)用會導(dǎo)致另一邊也阻塞荞彼。我覺得這導(dǎo)致了很多不必要的線程開銷,而且沒有為我們帶來任何價值待笑。另外鸣皂,初始的Binder Linux內(nèi)核驅(qū)動程序也不是很健壯。為了讓它更健壯暮蹂,我們也是費(fèi)了很大一番功夫的寞缝。”
對Binder持懷疑態(tài)度的人并沒有贏得這場戰(zhàn)斗仰泻,Jeff和他的小組奮勇向前荆陆,實(shí)現(xiàn)了Binder,成為Android框架的一個基礎(chǔ)部分集侯。與此同時被啼,Mike在他的電話功能中跳過Binder:“我在Java進(jìn)程和本地接口進(jìn)程之間開了一個UNIX域套接字√耐鳎”
binder當(dāng)初并不成熟,團(tuán)隊成員對于進(jìn)程間通訊更傾向于用socket.后面為了做了很多優(yōu)化,才使得binder通訊變得成熟穩(wěn)定.
關(guān)于Android操作系統(tǒng),書中推薦閱讀《現(xiàn)代操作系統(tǒng)》浓体,并深入閱讀介紹 Android 的章節(jié)(10.8)。那一章是 Dianne Hackborn 寫的辈讶,為 Binder和 Linux 擴(kuò)展等內(nèi)容提供了詳盡的細(xì)節(jié)命浴。另關(guān)于handle設(shè)計思想的理解,我推薦閱讀《C++沉思錄》.
----------分割線---------
要想了解這個問題,首先需要對Linux進(jìn)程間通訊機(jī)制有一定的了解荞估。
1.Linux進(jìn)程間通訊機(jī)制
https://www.zhihu.com/question/39440766/answer/89210950
Linux現(xiàn)有的所有進(jìn)程間IPC方式:
1.管道:在創(chuàng)建時分配一個page大小的內(nèi)存咳促,緩存區(qū)大小比較有限;
2.消息隊列:信息復(fù)制兩次勘伺,額外的CPU消耗跪腹;不合適頻繁或信息量大的通信;
3.共享內(nèi)存:無須復(fù)制飞醉,共享緩沖區(qū)直接付附加到進(jìn)程虛擬地址空間冲茸,速度快;但進(jìn)程間的同步問題操作系統(tǒng)無法實(shí)現(xiàn)缅帘,必須各進(jìn)程利用同步工具解決轴术;
4.套接字:作為更通用的接口,傳輸效率低钦无,主要用于不通機(jī)器或跨網(wǎng)絡(luò)的通信逗栽;
5.信號量:常作為一種鎖機(jī)制,防止某進(jìn)程正在訪問共享資源時失暂,其他進(jìn)程也訪問該資源彼宠。因此鳄虱,主要作為進(jìn)程間以及同一進(jìn)程內(nèi)不同線程之間的同步手段
6.信號: 不適用于信息交換,更適用于進(jìn)程中斷控制凭峡,比如非法內(nèi)存訪問拙已,殺死某個進(jìn)程等;
Binder機(jī)制基于開源的OpenBinder摧冀。http://www.angryredplanet.com/~hackbod/openbinder/docs/html/BinderIPCMechanism.html
2. socket 與 binder 對比
先來看看 socket與binder 兩種進(jìn)程間通訊機(jī)制 對比倍踪。
接下來回顧下 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)建虛擬機(jī),再調(diào)用startReg()注冊JNI函數(shù)椒惨;
3.通過JNI方式調(diào)用ZygoteInit.main()癞志,第一次進(jìn)入Java世界;
4.registerZygoteSocket()建立socket通道框产,zygote作為通信的服務(wù)端,用于響應(yīng)客戶端請求错洁;
5.preload()預(yù)加載通用類秉宿、drawable和color資源、openGL以及共享庫以及WebView屯碴,用于提高app啟動效率描睦;
6.zygote完畢大部分工作,接下來再通過startSystemServer()导而,fork得力幫手system_server進(jìn)程忱叭,也是上層framework的運(yùn)行載體。
7.zygote功成身退今艺,調(diào)用runSelectLoop()韵丑,隨時待命,當(dāng)接收到請求創(chuàng)建新進(jìn)程請求時立即喚醒并執(zhí)行相應(yīng)工作虚缎。
下面來看一張圖撵彻,標(biāo)示了調(diào)用startService之后的通訊流程。
圖中涉及3種IPC通信方式:
Binder
实牡、Socket
以及Handler
陌僵,在圖中分別用3種不同的顏色來代表這3種通信方式。一般來說创坞,同一進(jìn)程內(nèi)的線程間通信采用的是 Handler消息隊列機(jī)制碗短,不同進(jìn)程間的通信采用的是binder機(jī)制,另外與Zygote
進(jìn)程通信采用的Socket
题涨。
Android系統(tǒng)啟動流程如下:
現(xiàn)在回到問題偎谁,為什么Zygote通信為什么用Socket总滩,而不是Binder?
具體可看這篇:
android中AMS通知Zygote去fork進(jìn)程為什么使用socket而不使用binder?
可從以下五個方面分析:
1.先后時序問題:
binder驅(qū)動是早于init進(jìn)程加載的搭盾。而init進(jìn)程是安卓系統(tǒng)啟動的第一個進(jìn)程咳秉。
安卓中一般使用的binder引用,都是保存在ServiceManager進(jìn)程中的鸯隅,而如果想從ServiceManager中獲取到對應(yīng)的binder引用澜建,前提是需要注冊。雖然Init進(jìn)程是先創(chuàng)建ServiceManager蝌以,后創(chuàng)建Zygote進(jìn)程的炕舵。雖然Zygote更晚創(chuàng)建,但是也不能保證Zygote進(jìn)程去注冊binder的時候跟畅,ServiceManager已經(jīng)初始化好了咽筋。注冊時間點(diǎn)無法保證,AMS無法獲取到Zygote的binder引用徊件,這是原因之一奸攻。
2.多線程問題
Linux中,fork進(jìn)程是不推薦fork一個多線程的進(jìn)程的虱痕,因為如果存在鎖的情況下睹耐,會導(dǎo)致鎖異常。
而如果自身作為binder機(jī)制的接收者部翘,就會創(chuàng)建一個額外的線程來進(jìn)行處理(發(fā)送者進(jìn)程是無影響的)硝训。
所以,如果使用binder機(jī)制新思,就會導(dǎo)致去fork一個多線程的進(jìn)程窖梁,這是原因之二。
3.效率問題
AMS和Zygote之間使用的LocalSocket夹囚,相對于網(wǎng)絡(luò)Socket纵刘,減少了數(shù)據(jù)驗證等環(huán)節(jié),所以其實(shí)效率相對于正常的網(wǎng)絡(luò)Socket會大幅的提升荸哟。雖然還是要經(jīng)過兩次拷貝彰导,但是由于數(shù)據(jù)量并不大,所以其實(shí)影響并不明顯敲茄。
所以位谋,LocalSocket效率其實(shí)也不低,這是原因之三堰燎。
4.安全問題
LocalSocket其實(shí)也有權(quán)限校驗掏父,并不意味著可以被所有進(jìn)程隨意調(diào)用,這是原因之四秆剪。
5.Binder拷貝問題
如果使用binder通訊機(jī)制的話赊淑,從Zygote中fork出子進(jìn)程會拷貝Zygote中binder對象爵政。所以就憑白多占用了一塊無用的內(nèi)存區(qū)域。而Binder對象不能釋放陶缺。Binder的特殊性在于其是成對存在的钾挟,其分為Client端對象和Server端對象。假設(shè)我們使用binder饱岸,如果要釋放掉APP的Server端binder引用對象掺出,就必須釋放掉AMS中的Client端binder對象,那這樣就會導(dǎo)致AMS失去binder從而無法正常向Zygote發(fā)送消息苫费。
而使用socket通訊機(jī)制的話汤锨,fork出APP進(jìn)程之后,APP進(jìn)程會去主動的關(guān)閉掉這個socket百框,從而釋放這塊區(qū)域闲礼。相關(guān)代碼在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)服務(wù)調(diào)用應(yīng)用進(jìn)程的時候就會使用 oneway,比如 AMS 調(diào)用應(yīng)用進(jìn)程啟動 Activity棠众,這樣就算應(yīng)用進(jìn)程中做了耗時的任務(wù),也不會阻塞系統(tǒng)服務(wù)的運(yùn)行有决。)闸拿。但是,binder驅(qū)動對于oneway的調(diào)用是類似于handler sendmessage那樣的书幕,挨個處理新荤,所以如果服務(wù)端的oneway接口處理太慢而客戶端調(diào)用太多的話,來不及處理的調(diào)用會占滿binder驅(qū)動的緩存台汇,導(dǎo)致其他調(diào)用拋出上面的transaction failed苛骨。
oneway 方法的隱患具體參考這篇。
AIDL oneway 方法的隱患
socket也不是單獨(dú)使用的苟呐,I/O模型中的epoll是一種高效的管理socket的模型痒芝,epoll機(jī)制相對成熟,是同步非阻塞牵素。
socket(套接字)是對 TCP/IP 或者UDP/IP協(xié)議的封裝,Socket本身并不是協(xié)議,而是一個調(diào)用接口(API)严衬。
而Binder很負(fù)復(fù)雜。
簡單的設(shè)計笆呆,減少出問題的幾率请琳,會讓系統(tǒng)更加穩(wěn)定粱挡。
Zygote通信為什么用Socket,而不是Binder?
說了這么多俄精,其實(shí)是通過對比加深對Android進(jìn)程間通訊Socket和Binder兩種機(jī)制的理解询筏。
3.Zygote 處理 socket消息代碼分析
具體代碼流程分析可看這篇:
app_process: zygote處理socket消息請求(5)
參考鏈接:
為什么 Android 要采用 Binder 作為 IPC 機(jī)制?
為什么Android的Zygote與SystemServer通信采用Socket竖慧,而不是Binder?
[026]Zygote中Socket通信能否替換成Binder通信嫌套?
Android系統(tǒng)啟動-zygote篇
Android10.0系統(tǒng)啟動之Zygote進(jìn)程-[Android取經(jīng)之路]
app_process: zygote處理socket消息請求(5)
Android Framework層學(xué)習(xí)——為什么SystemServer進(jìn)程與Zygote進(jìn)程通訊采用Socket而不是Binder
android中AMS通知Zygote去fork進(jìn)程為什么使用socket而不使用binder