Android 創世紀 第三天 – Android移動開發技術文章_手機開發 Android移動開發教學課程

 

第三天,google說,伊甸園(linux世界)要被隔離,於是便創造瞭亞當(Adm)與夏娃(Eve),稱它為zygote和system_server

 

               –xxx

 

 

 

     第二天,init跑完瞭,它對於android系統,最重要的,就是啟動瞭zygote和system-server,誰是Adam誰是Eve?

 

     從分析init.rc來看

 

1 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的frok機制,從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發送一個frok請求,這時從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中,catach中就是截獲上面所說的異常,並執行main的這個Method。

 

 

 

為什麼這麼做?

 

先來看個示例程序:

 

01 public class Method_test { 

 

02   

 

03     public static void main(String[] args) { 

 

04         ClassA ca=new ClassA(); 

 

05         ca.start();      

 

06     } 

 

07   

 

08 } 

 

09   

 

10 class ClassA{ 

 

11   

 

12     public ClassA() { 

 

13     } 

 

14     public void start(){ 

 

15         System.out.println("開始調用方法"); 

 

16         Method_A(); 

 

17     } 

 

18       

 

19     public void Method_A(){ 

 

20         System.out.println("方法A被調用"); 

 

21         Method_B(); 

 

22               

 

23     } 

 

24     public void Method_B(){ 

 

25         System.out.println("方法B被調用"); 

 

26         Method_C(); 

 

27     } 

 

28     public void Method_C(){ 

 

29         System.out.println("方法C被調用"); 

 

30         Method_final(); 

 

31     } 

 

32       

 

33     public void Method_final(){ 

 

34         System.out.println("最終方法被調用"); 

 

35           

 

36     } 

 

37 }

 

 

 

上面這段代碼模擬一個一個場景,方法A調用B,B又調用瞭C。。。  A()->B()->C()->final(),final裡面可能又有更復雜的內容,而且final之後基本上不做什麼瞭。真實情況下,A()與final()之間還有更多的調用層次。

 

上面的調用棧情況是這樣的:

 

 

 

 

 

這樣的話,在一些資源稀缺的平臺上,,,,的確不怎麼好,我們希望執行final的時候,前面調用的層次能消失,以前用過的變量什麼也消失,還我們一個清凈的世界,而且執行完瞭也不用再層層跳出瞭。

 

這時,try catch就有大作用瞭,看代碼:

 

01 public class Method_test { 

 

02   

 

03     public static void main(String[] args) { 

 

04         ClassA ca=new ClassA(); 

 

05         ca.start();      

 

06     } 

 

07   

 

08 } 

 

09   

 

10 class ClassA{ 

 

11   

 

12     public ClassA() { 

 

13     } 

 

14     public void start(){ 

 

15         System.out.println("開始調用方法"); 

 

16         try{ 

 

17             Method_A(); 

 

18         }catch (RuntimeException e) { 

 

19             //捕獲異常後再執行目標方法 

 

20             Method_final(); 

 

21         } 

 

22     } 

 

23       

 

24     public void Method_A(){ 

 

25         System.out.println("方法A被調用"); 

 

26         Method_B(); 

 

27               

 

28     } 

 

29     public void Method_B(){ 

 

30         System.out.println("方法B被調用"); 

 

31         Method_C(); 

 

32     } 

 

33     public void Method_C(){ 

 

34         System.out.println("方法C被調用"); 

 

35         //這裡拋出一個異常 

 

36         throw new RuntimeException(); 

 

37     } 

 

38       

 

39     public void Method_final(){ 

 

40         System.out.println("最終方法被調用"); 

 

41           

 

42     } 

 

43 }

 

與之前相比,把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》,我自己感覺這是我見過的涉及框架的最好的一本書,主要就是通俗易懂啊(其實還是自己的水平有限)

 

 

 

水平有限,錯誤之處請指正,多謝!  

 

 

作者 黑暗伯爵

發佈留言