Android Activity啟動過程-從桌面點擊圖標(biāo)到調(diào)用Activity的OnCreate

1、概述

當(dāng)用戶從桌面點擊一個應(yīng)用圖標(biāo)時,該應(yīng)用就會啟動并顯示主Activity,即在AndroidManifest中標(biāo)注如下過濾器的Activity:

image

里面的category中涉及到LAUNCHER。這個其實和Laucher進程有關(guān),這是一個桌面進程。所以從桌面點擊圖標(biāo)到應(yīng)用啟動顯示的頁面的過程,其實就是從一個應(yīng)用啟動到另一個應(yīng)用的過程。

總體流程大致如下圖所示:

image

① 點擊桌面App圖標(biāo),Launcher進程采用Binder IPC向system_server進程發(fā)起startActivity請求。

② system_server進程接收到請求后,向zygote進程發(fā)送創(chuàng)建進程的請求。

③ Zygote進程fork出新的子進程,即App進程。

④ App進程,通過Binder IPC向sytem_server進程發(fā)起attachApplication請求。

⑤ system_server進程在收到請求后,進行一系列準(zhǔn)備工作后,再通過binder IPC向App進程發(fā)送scheduleLaunchActivity請求。

⑥ App進程的binder線程(ApplicationThread)在收到請求后,通過handler向主線程發(fā)送LAUNCH_ACTIVITY消息。

⑦ 主線程在收到Message后,通過發(fā)射機制創(chuàng)建目標(biāo)Activity,并回調(diào)Activity.onCreate()等方法。

⑧ 到此,App便正式啟動,開始進入Activity生命周期,執(zhí)行完onCreate/onStart/onResume方法,UI渲染結(jié)束后便可以看到App的主界面。

2、概念介紹

2.1 Launcher

如開頭所說Launcher本質(zhì)上也是一個應(yīng)用程序,和我們的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這個Activity實現(xiàn)了點擊、長按等回調(diào)接口,來接收用戶的輸入。既然是Activity,那么從Launcher的Activity跳轉(zhuǎn)到我們應(yīng)用的主Activity,和我們平時從一個Activity跳轉(zhuǎn)到另一個Activity的其實從代碼角度一樣。即捕捉圖標(biāo)點擊事件,然后startActivity()發(fā)送對應(yīng)的Intent請求。

2.2 system_server

startActivity()發(fā)送過來的請求其實是發(fā)送給system_server。而SystemServer也是一個進程。所以這一過程其實涉及到了進程間的通信,這邊的這一過程是采用Binder的方式來進行的。system_server這個進程是Android Framework層里面非常重要的一個進程。系統(tǒng)里面重要的服務(wù)都是在這個進程里面開啟的,比如 ActivityManagerService、PackageManagerService、WindowManagerService等等。

而今天重點要涉及到ActivityManagerService這個服務(wù),其簡稱AMS。ActivityManagerService進行初始化的時機很明確,就是在SystemServer進程開啟的時候,就會初始化ActivityManagerService。

我們的App通過調(diào)用startActivity()并不能直接打開另外一個App,這個方法會通過一系列的調(diào)用,最后告訴AMS說:“我要打開這個App,我知道他的住址和名字,你幫我打開吧!”所以是AMS來通知zygote進程來fork一個新進程,來開啟我們的目標(biāo)App。

除此之外,其實所有的Activity的開啟、暫停、關(guān)閉都需要AMS來控制,所以我們說,AMS負(fù)責(zé)系統(tǒng)中所有Activity的生命周期。

在Android系統(tǒng)中,任何一個Activity的啟動都是由AMS和應(yīng)用程序進程相互配合來完成的。AMS服務(wù)統(tǒng)一調(diào)度系統(tǒng)中所有進程的Activity啟動,而每個Activity的啟動過程則由其所屬的進程具體來完成。

2.3 zygote

如上所說,ActivityManagerService收到一個打開一個應(yīng)用程序的通知后會發(fā)送創(chuàng)建進程的請求給到zygote來創(chuàng)建一個app進程。

在Android系統(tǒng)里面,zygote是一個進程的名字。Android是基于Linux System的,當(dāng)你的手機開機的時候,Linux的內(nèi)核加載完成之后就會啟動一個叫“init“的進程。在Linux System里面,所有的進程都是由init進程fork出來的,我們的zygote進程也不例外。

我們都知道,每一個App其實都是一個單獨的dalvik虛擬機并對應(yīng)一個單獨的進程。所以當(dāng)系統(tǒng)里面的第一個zygote進程運行之后,在這之后再開啟App,就相當(dāng)于開啟一個新的進程。而為了實現(xiàn)資源共用和更快的啟動速度,Android系統(tǒng)開啟新進程的方式,是通過fork第一個zygote進程實現(xiàn)的。所以說,除了第一個zygote進程,其他應(yīng)用所在的進程都是zygote的子進程。而zygote的直白翻譯為“受精卵”,也是很形象生動了。

而創(chuàng)建的新進程的入口就是ActivityThread.main()方法,之后的部分將著重介紹。

3、應(yīng)用創(chuàng)建到顯示

3.1 啟動應(yīng)用程序

Android中,一個應(yīng)用程序的開始可以說就是從ActivityThread.java中的main()方法開始的。下面是main()比較關(guān)鍵的代碼:


public static void main(String[] args){

    ...

    Looper.prepareMainLooper();

    //初始化Looper

    ...

    ActivityThread thread = new ActivityThread();

    //實例化一個ActivityThread

    thread.attach(false);

    //這個方法最后就是為了發(fā)送出創(chuàng)建Application的消息

    ...

    Looper.loop();

    //主線程進入無限循環(huán)狀態(tài),等待接收消息

}

從源碼中可以看到,main()方法中主要做的事情是,初始化主線程的Looper、主Handler。并使主線程進入等待接收Message消息的無限循環(huán)狀態(tài)。并在進入等待接收消息前實例化一個實例化一個ActivityThread,并調(diào)用其attach()方法。從這也可以想象到為什么說Android的設(shè)計是一個事件驅(qū)動的模型了。

3.2 應(yīng)用程序和AMS關(guān)聯(lián)

我們在看一下thread.attach(false)中的關(guān)鍵代碼:


public void attach(boolean system){

    ...

    final IActivityManager mgr = ActivityManagerNative.getDefault(); 

    //獲得IActivityManager實例

    try {

        mgr.attachApplication(mAppThread);

    } catch (RemoteException ex) {

        throw ex.rethrowFromSystemServer();

    }

    ...

}

里面的IActivityManager 是一個接口,當(dāng)我們調(diào)用ActivityManagerNative.getDefault()獲得的實際是一個代理類的實例——ActivityManagerProxy,這個東西實現(xiàn)了IActivityManager接口。打開源碼你會發(fā)現(xiàn),ActivityManagerProxy是ActivityManagerNative的一個內(nèi)部類。既然是一個代理類它必定有代理的對象。查看一下ActivityManagerProxy的構(gòu)造函數(shù):


public ActivityManagerProxy(IBinder remote) {

        mRemote = remote;

}

這個構(gòu)造函數(shù)非常的簡單。首先它需要一個IBinder參數(shù),然后賦值給mRemote變量。這個mRemote顯然是ActivityManagerNative的成員變量。但對它的操作是由ActivityManagerProxy來代理間接進行的。這樣設(shè)計的好處是保護了mRemote,并且能夠在操作mRemote前執(zhí)行一些別的事務(wù),并且我們是以IActivityManager的身份來進行這些操作。

該構(gòu)造函數(shù)的調(diào)用地點:


static public IActivityManager asInterface(IBinder obj) {

    if (obj == null) {

        return null;

    }

    IActivityManager in =

        (IActivityManager)obj.queryLocalInterface(descriptor);

    //先檢查一下有沒有

    if (in != null) {

        return in;

    }

    ...

    return new ActivityManagerProxy(obj);

    //這個地方調(diào)用了構(gòu)造函數(shù)

}

上面這個方法是ActivityManagerNative中的一個靜態(tài)方法,它會調(diào)用到ActivityManagerProxy的構(gòu)造方法。這個靜態(tài)方法也需要一個IBinder作為參數(shù)。

查找這個函數(shù)的調(diào)用地點以及傳入的參數(shù)到底是什么:


private static final SingletongDefault = new Singleton() {

    protected IActivityManager create() {

      IBinder b = ServiceManager.getService("activity");

      //重點啊!IBinder實例就是在這里獲得的。

        ...

        IActivityManager am = asInterface(b);

        //調(diào)用了上面的方法。

        ...

        return am;

    }

};

這是ActivityManagerNative的靜態(tài)常量,它是一個單例。在其中終于獲得了前面一直在用的IBinder實例。


IBinder b = ServiceManager.getService("activity");

到這里應(yīng)該已經(jīng)非常清晰了,IActivityManager 獲取到的就是一個ActivityManagerService的代理。有了這個代理之后就可以作為客戶端通過Binder機制將app作為客戶端,ActivityManagerService作為服務(wù)端來進行通信了。具體Binder進程間通信機制請看我之前一篇文章:Binder進程間通信機制。

我們回到前面的thread.attach(false)方法中,接著往下看在獲得IActivityManager實例之后,將會執(zhí)行它的attachApplication(mAppThread)方法。該方法會傳入一個mAppThread參數(shù)。在ActivityThread這個類的成員變量中,有這么一行代碼:


final ApplicationThread mAppThread = new ApplicationThread();

ApplicationThread是作為ActivityThread中的一個常量出現(xiàn)的。這表明系統(tǒng)不希望這個變量中途被修改,也說明其的重要性。ApplicationThread類繼承自ApplicationThreadNative。并且ApplicationThread是ActivityThread的一個內(nèi)部類。從設(shè)計角度可以看出,該類是專門讓ActivityThread來使用的一個類。

看一下ApplicationThread的父類ApplicationThreadNative:


public abstract class ApplicationThreadNative extends Binder

    implements IApplicationThread{

...

}

我們從ApplicationThreadNative看到它也是一個Binder,同時實現(xiàn)了IApplicationThread接口。這個Binder并不是Binder代理,這個Binder說明了應(yīng)用程序在作為客戶端的同時,也作為了服務(wù)端。而作為服務(wù)端的Binder就是ApplicationThread。而 mgr.attachApplication(mAppThread) 這行代碼就是通過mgr將ApplicationThread的信息作為數(shù)據(jù)發(fā)送給AMS,方便日后AMS通過ApplicationThread的代理發(fā)送數(shù)據(jù)給ApplicationThread來達(dá)到控制app的Activity生命周期等一系列操作。

幾經(jīng)輾轉(zhuǎn),ApplicationThread的信息終于傳遞到了AMS中,我們可以從AMS的源碼中找到這個函數(shù):


private final boolean attachApplicationLocked(IApplicationThread thread

, int pid) {

    ...

    thread.bindApplication();

    ...

}

3.3 創(chuàng)建Application

ApplicationThread以IApplicationThread的身份到了ActivityManagerService中(其實在ActivityManagerService中的是ApplicationThread的代理),經(jīng)過一系列的操作,最終被調(diào)用了自己的bindApplication()方法,發(fā)出初始化Applicationd的消息:


public final void bindApplication(String processName, ApplicationInfo appInfo, Listproviders, ComponentName instrumentationName, ProfilerInfo profilerInfo, Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher, IUiAutomationConnection instrumentationUiConnection, int debugMode, boolean enableBinderTracking, boolean trackAllocation, boolean isRestrictedBackupMode, boolean persistent, Configuration config, CompatibilityInfo compatInfo, Map services,

    Bundle coreSettings){

    ...

    sendMessage(H.BIND_APPLICATION, data);

}

bindApplication()函數(shù)就是AMS的ApplicationThread的代理,通過Binder進程間通信調(diào)用app進程的ApplicationThread的bindApplication()方法。該方法里面有一句關(guān)鍵代碼


sendMessage(H.BIND_APPLICATION, data);

還記不記得最開始main函數(shù)創(chuàng)建的Looper。而ActivityThread中還存在一個該Looper的處理對象Hander H。從傳送的參數(shù)H.BIND_APPLICATION可以看到,這個消息就是發(fā)送給這個H來處理的。

一旦H接收到這個消息就開始創(chuàng)建Application了。這個過程是在handleBindApplication()中完成的:


private void handleBindApplication(AppBindData data) {

    ...

    mInstrumentation = (Instrumentation)

        cl.loadClass(data.instrumentationName.getClassName())

        .newInstance();

    //通過反射初始化一個Instrumentation儀表。后面會介紹。

    ...

    Application app = data.info.makeApplication(data.restrictedBackupMode, null);

    //通過LoadedApp命令創(chuàng)建Application實例

    mInitialApplication = app;

    ...

    mInstrumentation.callApplicationOnCreate(app);

    //讓儀器調(diào)用Application的onCreate()方法

    ...

}

handleBindApplication()中比較關(guān)鍵的是上面幾句代碼。其中有個類Instrumentation,它在創(chuàng)建Application類之前進行實例化。它能夠允許你監(jiān)視應(yīng)用程序和系統(tǒng)的所有交互。打開這個類你可以發(fā)現(xiàn),最終Apllication的創(chuàng)建,Activity的創(chuàng)建,以及生命周期都會經(jīng)過這個對象去執(zhí)行。簡單點說,就是把這些操作包裝了一層。通過操作Instrumentation進而實現(xiàn)上述的功能。這里實例化Instrumentation的方法是反射!而反射的ClassName是來自于從ActivityManagerService中通過ApplicationThread的代理傳過來的。

接我們著看mInstrumentation調(diào)用的方法callApplicationOnCreate(app):


public void callApplicationOnCreate(Application app) {

    app.onCreate();

}

該方法只是回調(diào)了一下Application 的onCreate()。這就是為什么它能夠起到監(jiān)控的作用。我們最熟悉的Activity的一些聲明周期的方法onCreate(),onStart()等等也是通過這樣來進行回調(diào)的。

再回到


Application app = data.info.makeApplication(data.restrictedBackupMode, null);

看下調(diào)用的方法makeApplication(data.restrictedBackupMode, null):


public Application makeApplication(boolean forceDefaultAppClass,

    Instrumentation instrumentation) {

    ...

    String appClass = mApplicationInfo.className;

    //Application的類名。明顯是要用反射了。

    ...

    ContextImpl appContext = ContextImpl.createAppContext(mActivityThread

        , this);

    //留意下Context

    app = mActivityThread.mInstrumentation

        .newApplication( cl, appClass, appContext);

    //通過儀表創(chuàng)建Application

    ...

}

這里首先通過反射找到了Application的類名。其次創(chuàng)建了Application的ContextImpl ,ContextImpl 其實Application的Context具體執(zhí)行的類,我們平時調(diào)用的Context有關(guān)的方法最后其實都是調(diào)用了ContextImpl 的對應(yīng)方法,這里不展開講了。之后就是通過剛才說的mInstrumentation來調(diào)用newApplication( cl, appClass, appContext)創(chuàng)建Application。具體該方法如下:


static public Application newApplication(Class clazz

    , Context context) throws InstantiationException

    , IllegalAccessException

    , ClassNotFoundException {

        Application app = (Application)clazz.newInstance();

        //反射創(chuàng)建,簡單粗暴

        app.attach(context);

        //關(guān)注下這里,Application被創(chuàng)建后第一個調(diào)用的方法。

        //目的是為了綁定ContextImpl 。

        return app;

    }

至此終于將Application創(chuàng)建出來了。

3.4 創(chuàng)建及啟動Activity

還記得之前的Application啟動信號其實是AMS通過ApplicationThread的代理調(diào)用bindApplication()發(fā)送過來的嗎?了解Binder通信機制可以知道,一旦客戶端調(diào)用遠(yuǎn)程服務(wù)(此時AMS是客戶端,app是服務(wù)端),調(diào)用服務(wù)的線程調(diào)用服務(wù)后是會掛起直到服務(wù)調(diào)用完畢返回結(jié)果的。這邊創(chuàng)建完Application相當(dāng)于服務(wù)調(diào)用完畢了。此時AMS的對應(yīng)線程會接著往下執(zhí)行代碼以同樣的方法通過ApplicationThread的代理向ApplicationThread發(fā)起啟動主Activity的請求,并且在ApplicationThread中向H發(fā)送一條LAUNCH_ACTIVITY的消息。然后H就開始了初始化Activity。

收到LAUNCH_ACTIVITY后H會調(diào)用handleLaunchActivity():


private void handleLaunchActivity(ActivityClientRecord r

    , Intent customIntent

    , String reason) {

    ...

    Activity a = performLaunchActivity(r, customIntent);

    //媽蛋!又封裝到另一個方法中創(chuàng)建了。

    ...

    if (a != null) {

        ...

        handleResumeActivity(r.token

        , false

        , r.isForward

        ,!r.activity.mFinished && !r.startsNotResumed

        , r.lastProcessedSeq, reason);

        //Activity創(chuàng)建成功就往onResume()走了!

        ...

    }

}

繼續(xù)往下看performLaunchActivity(r, customIntent):


private Activity performLaunchActivity(ActivityClientRecord r

    , Intent customIntent) {

    ...

    activity = mInstrumentation.newActivity(

        cl, component.getClassName(), r.intent);

    //通過mInstrumentation來創(chuàng)建Activity

    ...

    Application app = r.packageInfo.makeApplication(false

    , mInstrumentation);

    //獲取Application

    ...

    activity.attach(appContext

        , this

        , getInstrumentation()

        , r.token

        ,.ident

        , app

        , r.intent

        , r.activityInfo

        , title

        , r.parent

        , r.embeddedID

        , r.lastNonConfigurationInstances

        , config

        ,r.referrer

        , r.voiceInteractor

        , window);

    ...

    if (r.isPersistable()) {

        mInstrumentation.callActivityOnCreate(

          activity, r.state, r.persistentState);

    } else {

        mInstrumentation.callActivityOnCreate(activity, r.state);

    }

    //根據(jù)是否可持久化選擇onCreate()方法。

    ...

}

注意這句代碼:


activity = mInstrumentation.newActivity(

        cl, component.getClassName(), r.intent);

正如前面所說,Activity、Application的創(chuàng)建及生命周期都被承包給Instrumentation。所以由它來負(fù)責(zé)??纯磏ewActivity():


public Activity newActivity(ClassLoader cl, String className,

            Intent intent)

            throws InstantiationException

            , IllegalAccessException,

            ClassNotFoundException {

        return (Activity)cl.loadClass(className).newInstance();

        //反射實例化Activity而已

    }

其實就是通過反射實例化了Activity。

回到performLaunchActivity() 創(chuàng)建了Activity后 將之前創(chuàng)建出來的Application和Activity關(guān)聯(lián)。

接著我們看performLaunchActivity() 中的這段代碼:


if (r.isPersistable()) {

        mInstrumentation.callActivityOnCreate(

          activity, r.state, r.persistentState);

    } else {

        mInstrumentation.callActivityOnCreate(activity, r.state);

    }

根據(jù)是否可持久化選擇Activity的onCreate()方法。同樣是通過Instrumentation儀表來執(zhí)行onCreate()的。它兩分別對應(yīng)的onCreate()方法為:


onCreate(icicle, persistentState);

//可獲得持久化數(shù)據(jù)

onCreate(icicle);

//平時重寫的最多的。

至此,成功調(diào)用了Activity的onCreate()方法。其實之后的onStart(),onResume()等生命周期的方法也時類似這樣調(diào)用的。

4、總結(jié)

從桌面點擊圖標(biāo)到創(chuàng)建應(yīng)用進程,再到創(chuàng)建Application,在到創(chuàng)建主Activity到最后調(diào)用onCreate()的流程大致如上文所述。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容