Android 創世紀 第三天
第三天,google說,伊甸園(linux世界)要被隔離,于是便創造了亞當(Adm)與夏娃(Eve),稱它為zygote和system_server
--xxx
第二天,init跑完了,它對于android系統,最重要的,就是啟動了zygote和system-server,誰是Adam誰是Eve?
從分析init.rc來看
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
--start-system-server只是個參數。
分析源碼
啊,原來夏娃(zygote)用自己的肋骨(fork)創造了亞當(system_server)!什么?為什么不是亞當創造夏娃??? android的世界,是無性繁殖的世界,zygote(夏娃)一開始就是個受精卵。。。。。。。
Eve誕生記(zygote啟動過程)
第一步,受精(改名)
從init.rc可以看出,啟動的是app_process程序,啟動后,再把自己的進程名改為zygote,就算是受精了。。
第二步,著床(交由AppRuntime啟動javaVM)
這時,會創建一個vm,算是android java世界的祖師爺,并且在這個vm啟動時賦予各種參數,比如我們都知道默認的情況下,一個應用程序加載的內存不能超過16mb,這個參數就是在這里設置的,heapsize為16mb。這之后vm就啟動了,哦,應該叫dalvik。
在啟動后,還會為java的類注冊JNI函數,android世界是c與java互相交織的。
第三步,生長臍帶(初涉java世界)
注冊好各種JNI函數后,zygote的C層面就可以調用Java代碼了。
這里第一次進入了java世界。它調用了 com.android.internal.os.ZygoteInit 的main方法。
java世界并不孤立
1、它首先注冊socket,使自己成為一個服務端,也就是IPC通信服務端。這就是android的偉大之處,巧妙利用了linux的所有特性。以后會講到zygote的真諦。
2、然后預加載類以及一些android資源。洋洋灑灑1k多個java類要加載,并且還都是加載時間大于1250微妙的類,android框架加載耗時的類都到這里來加載了,這也正是android開機慢得原因,不過苦盡甘來嗎,開始累點能干的都干了,以后用起來就方便了,不是么?當然,android的系統就像是量產車,各種性能不求最好只求最穩定,廣大發燒友改rom就像改裝汽車一樣,需要精通從齒輪組到ECU的各種知識,方能達到硬件與軟件完美的結合以便發揮出最大功效,扯多了。。要想定制rom,減少開機時間,還得靠nb的水平與良好的洞察力。
3、啟動SystemServer。也就是system_server進程。
剛才說了,這個system_server就是Adm,夏娃的第一塊肉就這么掉下來了,同樣利用linux的fork機制,從zygote進程分裂出了一個system_server進程。男女搭配干活不累,亞當與夏娃共同勞動,為我們搭建美好的android世界。
后面會分析system_server都干些什么事。
4、建一個線程,轉入socket偵聽模式。每個apk在android中運行起來都是一個單獨的linux進程,這些進程,就是zygote分裂出來的。現在zygote偵聽的就是ActivityService通過system_server使用socket傳入的請求,用以分裂進程。線程之外的最后,關閉之前打開的socket偵聽。
現在夏娃該干的事,基本上干完了,就等著亞當再次讓她受精了。。。。。 -_-!!!!
這里就順便描述下每個Activity分娩出來的過程吧!(Activity大致啟動過程)
step 1 凡人向神求仔:
啟動一個activity,也就是startActivity。這個activity依附于一個未啟動的進程,好比剛開機,打開一個android程序。
step 2 大神收到祈愿:
ActvityManagerService收到startActvity,梳理一番各種參數,比如apk的報名,再將這個祈愿通過送到伊甸園交由夏娃實施。
step3 伊甸園接到生仔請求:
亞當愿意別人直接找夏娃么?呵呵,各種service都是SystemServer啟動起來的,而SystemServer又掌管著Binder,自己肯定會首先處理這個通知的。SystemServer通過socket這個IPC機制,向zygote發送一個fork請求,這時從java世界回到了native世界,亞當(system_server)讓夏娃(zygote)受精了。。。。 -_-!!! android的繁榮離不開這種造仔活動
step4 夏娃生仔:
又要分裂了,fork出了一個新進程,并把這個進程返還給Java世界,并且由ActivityManagerService管理它。這里,就是讓這個進程調用ActivityThread,ActvityThread就是main,apk程序的main。
linuix中fork出來的子進程會繼承父進程的所有信息,就相當于一個拷貝,只不過變成了另一個進程。既然繼承了所有信息,那么dalvik也就繼承下來了,這就解釋了為什么一個android程序都有一個vm進程。
Adam誕生記(SystemServer啟動過程)
上面提到zygote在java層啟動并fork了SystemServer,也就是夏娃身上掉下來的第一塊肉。
SystemServer首先會關閉因fork而從父進程繼承而來的socket。
第一步,Native層初始化
這里會通過JNI調用native方法,又回到了Native世界。
首先,初始化Skia引擎,就是一個圖像引擎,封裝了畫圖的各種操作,這樣屏幕就能讓顯示東西了。
然后,啟動Binder,也就是android IPC的核心。
第二步,換名,并進行JAVA層初始化
換名了,這個vm進程就被正式命名為system_server了。
java層初始化,也就是調用 com.android.server.SystemServer 的main。有趣的是,這里通過反射,獲得SystemServer類的main方法后,不直接調用,而是拋出一個異常,這個異常包含了main這個Method。
再回頭看看zygote的java世界,啟動了system_server的代碼是在try中,catch中就是截獲上面所說的異常,并執行main的這個Method。
為什么這么做?
先來看個示例程序:
public class Method_test { public static void main(String[] args) { ClassA ca=new ClassA(); ca.start(); } } class ClassA{ public ClassA() { } public void start(){ System.out.println("開始調用方法"); Method_A(); } public void Method_A(){ System.out.println("方法A被調用"); Method_B(); } public void Method_B(){ System.out.println("方法B被調用"); Method_C(); } public void Method_C(){ System.out.println("方法C被調用"); Method_final(); } public void Method_final(){ System.out.println("最終方法被調用"); } }
上面這段代碼模擬一個一個場景,方法A調用B,B又調用了C。。。 A()->B()->C()->final(),final里面可能又有更復雜的內容,而且final之后基本上不做什么了。真實情況下,A()與final()之間還有更多的調用層次。
上面的調用棧情況是這樣的:
這樣的話,在一些資源稀缺的平臺上,,,,的確不怎么好,我們希望執行final的時候,前面調用的層次能消失,以前用過的變量什么也消失,還我們一個清凈的世界,而且執行完了也不用再層層跳出了。
這時,try catch就有大作用了,看代碼:
public class Method_test { public static void main(String[] args) { ClassA ca=new ClassA(); ca.start(); } } class ClassA{ public ClassA() { } public void start(){ System.out.println("開始調用方法"); try{ Method_A(); }catch (RuntimeException e) { //捕獲異常后再執行目標方法 Method_final(); } } public void Method_A(){ System.out.println("方法A被調用"); Method_B(); } public void Method_B(){ System.out.println("方法B被調用"); Method_C(); } public void Method_C(){ System.out.println("方法C被調用"); //這里拋出一個異常 throw new RuntimeException(); } public void Method_final(){ System.out.println("最終方法被調用"); } }與之前相比,把final()的調用換到了start()里,直接讓c()拋出個異常,catch中執行final()。
調用棧如下:
Android的設計思想真猛啊,通過這么分析,又學到一個技巧。。。。
SystemService->main
1、加載native庫并調用init1()
這里創建了幾個native服務, ServiceManger、SurfaceFlinger等,并把當前線程加入到Binder的通信大軍中。
2、通過JNI調用JAVA世界的init2()
在上面的init1()中,最后會調用java世界的init2()。
這里就是啟動各種服務了,什么EntropyService、PowerManagerService、BatteryService、WindowManager等等。
還會把地獄犬召喚出來,也就是WatchDog(看門狗),來時刻盯著一些重要的Service,防止他們墮落。看門狗的職責就是盯著一些重要的service,萬一他們掛了,就把亞當殺死,然后讓init把它再原地滿血復活。
最后,就進入了消息循環,負責android世界中跨線程訪問的調度,google常曰 子線程要通過handler來更新UI線程,那么handler中發送的消息就是靠這里來分發的。
這里嚴重推薦 鄧凡平 前輩所著的《深入理解Anroid 卷I》,我自己感覺這是我見過的涉及框架的最好的一本書,主要就是通俗易懂?。ㄆ鋵嵾€是自己的水平有限)
水平有限,錯誤之處請指正,多謝!
創世紀:第一天連接:http://www.rzrgm.cn/hangxin1940/archive/2011/10/01/2196964.html
創世紀:第二天連接:http://www.rzrgm.cn/hangxin1940/archive/2011/10/14/2196964.html
##第四天鏈接,占位##
原創文章,轉載請說明出處:
http://www.rzrgm.cn/hangxin1940/archive/2011/10/01/2196964.html


浙公網安備 33010602011771號