一個APP從啟動到主頁面顯示經歷了哪些過程?

蝸牛改變自己發表於2019-02-25
轉載自:

https://www.jianshu.com/p/a72c5ccbd150?utm_campaign=haruki&utm_content=note&utm_medium=reader_share&utm_source=qq

本文以圖文並茂的形式簡單介紹一個APP從啟動到主頁面顯示經歷了哪些流程,以及實現的原理。不介紹具體原始碼,僅僅構建一個大體框架。

一個APP從啟動到主頁面顯示經歷了哪些過程?

啟動流程:

①點選桌面App圖示,Launcher程式採用Binder IPC向system_server程式發起startActivity請求;

②system_server程式接收到請求後,向zygote程式傳送建立程式的請求;

③Zygote程式fork出新的子程式,即App程式;

④App程式,通過Binder IPC向sytem_server程式發起attachApplication請求;

⑤system_server程式在收到請求後,進行一系列準備工作後,再通過binder IPC向App程式傳送scheduleLaunchActivity請求;

⑥App程式的binder執行緒(ApplicationThread)在收到請求後,通過handler向主執行緒傳送LAUNCH_ACTIVITY訊息;

⑦主執行緒在收到Message後,通過發射機制建立目標Activity,並回撥Activity.onCreate()等方法。

⑧到此,App便正式啟動,開始進入Activity生命週期,執行完onCreate/onStart/onResume方法,UI渲染結束後便可以看到App的主介面。

上面的一些列步驟簡單介紹了一個APP啟動到主頁面顯示的過程,可能這些流程中的一些術語看的有些懵,什麼是Launcher,什麼是zygote,什麼是applicationThread.....

下面我們一一介紹。

二、理論基礎

1.zygote

zygote意為“受精卵“。Android是基於Linux系統的,而在Linux中,所有的程式都是由init程式直接或者是間接fork出來的,zygote程式也不例外。

在Android系統裡面,zygote是一個程式的名字。Android是基於Linux System的,當你的手機開機的時候,Linux的核心載入完成之後就會啟動一個叫“init“的程式。在Linux System裡面,所有的程式都是由init程式fork出來的,我們的zygote程式也不例外。

我們都知道,每一個App其實都是

● 一個單獨的dalvik虛擬機器
● 一個單獨的程式

所以當系統裡面的第一個zygote程式執行之後,在這之後再開啟App,就相當於開啟一個新的程式。而為了實現資源共用和更快的啟動速度,Android系統開啟新程式的方式,是通過fork第一個zygote程式實現的。所以說,除了第一個zygote程式,其他應用所在的程式都是zygote的子程式,這下你明白為什麼這個程式叫“受精卵”了吧?因為就像是一個受精卵一樣,它能快速的分裂,並且產生遺傳物質一樣的細胞!

2.system_server

SystemServer也是一個程式,而且是由zygote程式fork出來的。

知道了SystemServer的本質,我們對它就不算太陌生了,這個程式是Android Framework裡面兩大非常重要的程式之一——另外一個程式就是上面的zygote程式。

為什麼說SystemServer非常重要呢?因為系統裡面重要的服務都是在這個程式裡面開啟的,比如
ActivityManagerService、PackageManagerService、WindowManagerService等等。

3.ActivityManagerService

ActivityManagerService,簡稱AMS,服務端物件,負責系統中所有Activity的生命週期。

ActivityManagerService進行初始化的時機很明確,就是在SystemServer程式開啟的時候,就會初始化ActivityManagerService。

下面介紹下Android系統裡面的伺服器和客戶端的概念。

其實伺服器客戶端的概念不僅僅存在於Web開發中,在Android的框架設計中,使用的也是這一種模式。伺服器端指的就是所有App共用的系統服務,比如我們這裡提到的ActivityManagerService,和前面提到的PackageManagerService、WindowManagerService等等,這些基礎的系統服務是被所有的App公用的,當某個App想實現某個操作的時候,要告訴這些系統服務,比如你想開啟一個App,那麼我們知道了包名和MainActivity類名之後就可以開啟

Intent intent = new Intent(Intent.ACTION_MAIN);  
intent.addCategory(Intent.CATEGORY_LAUNCHER);              
ComponentName cn = new ComponentName(packageName, className);              
intent.setComponent(cn);  
startActivity(intent);複製程式碼

但是,我們的App通過呼叫startActivity()並不能直接開啟另外一個App,這個方法會通過一系列的呼叫,最後還是告訴AMS說:“我要開啟這個App,我知道他的住址和名字,你幫我開啟吧!”所以是AMS來通知zygote程式來fork一個新程式,來開啟我們的目標App的。這就像是瀏覽器想要開啟一個超連結一樣,瀏覽器把網頁地址傳送給伺服器,然後還是伺服器把需要的資原始檔傳送給客戶端的。

知道了Android Framework的客戶端伺服器架構之後,我們還需要了解一件事情,那就是我們的App和AMS(SystemServer程式)還有zygote程式分屬於三個獨立的程式,他們之間如何通訊呢?

App與AMS通過Binder進行IPC通訊,AMS(SystemServer程式)與zygote通過Socket進行IPC通訊。後面具體介紹。

那麼AMS有什麼用呢?在前面我們知道了,如果想開啟一個App的話,需要AMS去通知zygote程式,除此之外,其實所有的Activity的開啟、暫停、關閉都需要AMS來控制,所以我們說,AMS負責系統中所有Activity的生命週期。

在Android系統中,任何一個Activity的啟動都是由AMS和應用程式程式(主要是ActivityThread)相互配合來完成的。AMS服務統一排程系統中所有程式的Activity啟動,而每個Activity的啟動過程則由其所屬的程式具體來完成。

4.Launcher

當我們點選手機桌面上的圖示的時候,App就由Launcher開始啟動了。但是,你有沒有思考過Launcher到底是一個什麼東西?

Launcher本質上也是一個應用程式,和我們的App一樣,也是繼承自Activity

packages/apps/Launcher2/src/com/android/launcher2/Launcher.java


public final class Launcher extends Activity
        implements View.OnClickListener, OnLongClickListener, LauncherModel.Callbacks,
                   View.OnTouchListener {
                   }複製程式碼

Launcher實現了點選、長按等回撥介面,來接收使用者的輸入。既然是普通的App,那麼我們的開發經驗在這裡就仍然適用,比如,我們點選圖示的時候,是怎麼開啟的應用呢?捕捉圖示點選事件,然後startActivity()傳送對應的Intent請求唄!是的,Launcher也是這麼做的,就是這麼easy!

5.Instrumentation和ActivityThread

每個Activity都持有Instrumentation物件的一個引用,但是整個程式只會存在一個Instrumentation物件。
Instrumentation這個類裡面的方法大多數和Application和Activity有關,這個類就是完成對Application和Activity初始化和生命週期的工具類。Instrumentation這個類很重要,對Activity生命週期方法的呼叫根本就離不開他,他可以說是一個大管家。

ActivityThread,依賴於UI執行緒。App和AMS是通過Binder傳遞資訊的,那麼ActivityThread就是專門與AMS的外交工作的。

6.ApplicationThread

前面我們已經知道了App的啟動以及Activity的顯示都需要AMS的控制,那麼我們便需要和服務端的溝通,而這個溝通是雙向的。

客戶端-->服務端


一個APP從啟動到主頁面顯示經歷了哪些過程?

而且由於繼承了同樣的公共介面類,ActivityManagerProxy提供了與ActivityManagerService一樣的函式原型,使使用者感覺不出Server是執行在本地還是遠端,從而可以更加方便的呼叫這些重要的系統服務。

服務端-->客戶端

還是通過Binder通訊,不過是換了另外一對,換成了ApplicationThread和ApplicationThreadProxy。

一個APP從啟動到主頁面顯示經歷了哪些過程?

他們也都實現了相同的介面IApplicationThread

  private class ApplicationThread extends ApplicationThreadNative {}

  public abstract class ApplicationThreadNative extends Binder implements IApplicationThread{}

  class ApplicationThreadProxy implements IApplicationThread {}複製程式碼

關於Binder通訊,可以參考這兩篇文章理解一下:簡單理解Binder機制的原理,關於AIDL使用和Binder機制詳解,你只需要看這一篇即可

好了,前面羅裡吧嗦的一大堆,介紹了一堆名詞,可能不太清楚,沒關係,下面結合流程圖介紹。

三、啟動流程

1.建立程式

①先從Launcher的startActivity()方法,通過Binder通訊,呼叫ActivityManagerService的startActivity方法。

②一系列折騰,最後呼叫startProcessLocked()方法來建立新的程式。

③該方法會通過前面講到的socket通道傳遞引數給Zygote程式。Zygote孵化自身。呼叫ZygoteInit.main()方法來例項化ActivityThread物件並最終返回新程式的pid。

④呼叫ActivityThread.main()方法,ActivityThread隨後依次呼叫Looper.prepareLoop()和Looper.loop()來開啟訊息迴圈。

方法呼叫流程圖如下:


一個APP從啟動到主頁面顯示經歷了哪些過程?

更直白的流程解釋:

一個APP從啟動到主頁面顯示經歷了哪些過程?

①App發起程式:當從桌面啟動應用,則發起程式便是Launcher所在程式;當從某App內啟動遠端程式,則傳送程式便是該App所在程式。發起程式先通過binder傳送訊息給system_server程式;

②system_server程式:呼叫Process.start()方法,通過socket向zygote程式傳送建立新程式的請求;

③zygote程式:在執行ZygoteInit.main()後便進入runSelectLoop()迴圈體內,當有客戶端連線時便會執行ZygoteConnection.runOnce()方法,再經過層層呼叫後fork出新的應用程式;

④新程式:執行handleChildProc方法,最後呼叫ActivityThread.main()方法。

2.繫結Application

上面建立程式後,執行ActivityThread.main()方法,隨後呼叫attach()方法。

將程式和指定的Application繫結起來。這個是通過上節的ActivityThread物件中呼叫bindApplication()方法完成的。該方法傳送一個BIND_APPLICATION的訊息到訊息佇列中, 最終通過handleBindApplication()方法處理該訊息. 然後呼叫makeApplication()方法來載入App的classes到記憶體中。

方法呼叫流程圖如下:

一個APP從啟動到主頁面顯示經歷了哪些過程?

更直白的流程解釋:

一個APP從啟動到主頁面顯示經歷了哪些過程?

如果看不懂AMS,ATP等名詞,後面有解釋)

3.顯示Activity介面

經過前兩個步驟之後, 系統已經擁有了該application的程式。 後面的呼叫順序就是普通的從一個已經存在的程式中啟動一個新程式的activity了。

實際呼叫方法是realStartActivity(), 它會呼叫application執行緒物件中的scheduleLaunchActivity()傳送一個LAUNCH_ACTIVITY訊息到訊息佇列中, 通過 handleLaunchActivity()來處理該訊息。在 handleLaunchActivity()通過performLaunchActiivty()方法回撥Activity的onCreate()方法和onStart()方法,然後通過handleResumeActivity()方法,回撥Activity的onResume()方法,最終顯示Activity介面。

一個APP從啟動到主頁面顯示經歷了哪些過程?

更直白的流程解釋:

一個APP從啟動到主頁面顯示經歷了哪些過程?

四、Binder通訊

一個APP從啟動到主頁面顯示經歷了哪些過程?

簡稱:

ATP: ApplicationThreadProxy

AT: ApplicationThread

AMP: ActivityManagerProxy

**AMS: **ActivityManagerService

圖解:

①system_server程式中呼叫startProcessLocked方法,該方法最終通過socket方式,將需要建立新程式的訊息告知Zygote程式,並阻塞等待Socket返回新建立程式的pid;

②Zygote程式接收到system_server傳送過來的訊息, 則通過fork的方法,將zygote自身程式複製生成新的程式,並將ActivityThread相關的資源載入到新程式app process,這個程式可能是用於承載activity等元件;

③ 在新程式app process向servicemanager查詢system_server程式中binder服務端AMS, 獲取相對應的Client端,也就是AMP. 有了這一對binder c/s對, 那麼app process便可以通過binder向跨程式system_server傳送請求,即attachApplication()

④system_server程式接收到相應binder操作後,經過多次呼叫,利用ATP向app process傳送binder請求, 即bindApplication.
system_server擁有ATP/AMS, 每一個新建立的程式都會有一個相應的AT/AMP,從而可以跨程式 進行相互通訊. 這便是程式建立過程的完整生態鏈。

以上大概介紹了一個APP從啟動到主頁面顯示經歷的流程,主要從巨集觀角度介紹了其過程,具體可結合原始碼理解。



相關文章