安卓應(yīng)用啟動(dòng)流程(從點(diǎn)擊Launcher圖標(biāo)開始)

閱讀這篇文章,需要對Binder有一定了解。我們通過從桌面啟動(dòng)一個(gè)應(yīng)用講解啟動(dòng)一個(gè)安卓應(yīng)用的流程贪惹。

遠(yuǎn)程調(diào)用

這里要先明確一個(gè)概念,就是所謂的遠(yuǎn)程調(diào)用即跨進(jìn)程調(diào)用寂嘉,安卓大部分情況下通過Binder來實(shí)現(xiàn)奏瞬,其實(shí)現(xiàn)的大致原理,每個(gè)支持Binder的進(jìn)程都有一個(gè)Binder線程池垫释,當(dāng)我們通過Binder遠(yuǎn)程調(diào)用另一個(gè)進(jìn)程的方法時(shí)丝格,例如A進(jìn)程遠(yuǎn)程調(diào)用B進(jìn)程的print方法,其過程是A進(jìn)程把要調(diào)用的方法的方法描述(方法名棵譬,參數(shù)显蝌,身份確認(rèn)信息等)裝進(jìn)一個(gè)Parcel對象發(fā)送到Binder驅(qū)動(dòng),B進(jìn)程中空閑的Binder線程會(huì)去取消息,當(dāng)它取到消息后開始在B進(jìn)程里運(yùn)行曼尊,根據(jù)傳遞過來的方法描述去調(diào)用對應(yīng)的方法酬诀,這樣兩個(gè)進(jìn)程間就完成了一次跨進(jìn)程的調(diào)用,屏蔽掉細(xì)節(jié)就變成了A進(jìn)程調(diào)用了B進(jìn)程的print方法骆撇,這里要注意的是瞒御,A進(jìn)程往Binder驅(qū)動(dòng)寫值后,可以選擇阻塞或不阻塞神郊,也就是Binder的雙向還是單向模式肴裙,若調(diào)用模式為單向模式,A進(jìn)程往Binder驅(qū)動(dòng)寫入值后會(huì)立即返回涌乳,開始執(zhí)行下一條指令蜻懦,不在乎B進(jìn)程是否正確處理了這個(gè)消息,而如果是雙向夕晓,則在A進(jìn)程寫值后會(huì)一直等待宛乃,等待B進(jìn)程處理完成print方法,再往Binder驅(qū)動(dòng)回一條消息蒸辆,A進(jìn)程接收到這個(gè)消息后調(diào)用返回征炼,開始執(zhí)行下一條指令,這個(gè)過程就很像在同一個(gè)進(jìn)程中調(diào)用方法了躬贡,想象若我們在A進(jìn)程中也有同名方法print谆奥,這個(gè)方法的作用是往Binder驅(qū)動(dòng)寫值并等待調(diào)用返回,而B進(jìn)程收到消息并執(zhí)行了B進(jìn)程的print并在Binder驅(qū)動(dòng)中寫回值逗宜,現(xiàn)在A進(jìn)程收到寫回的消息雄右,print返回,執(zhí)行下一條指令纺讲,其過程就像是在A進(jìn)程里執(zhí)行了B進(jìn)程的print方法一樣擂仍,足以讓使用者忽略掉這其實(shí)經(jīng)過了跨進(jìn)程的通信,而只是調(diào)用了一次普通方法熬甚。

幾個(gè)重要的類:

  • ActivityManagerService (簡稱AMS)逢渔,運(yùn)行在system_server 進(jìn)程,其實(shí)質(zhì)為一個(gè)Binder服務(wù)端乡括,與之對應(yīng)的是 ActivityManagerProxy(簡稱AMP)肃廓,運(yùn)行在各個(gè)應(yīng)用即客戶端,封裝了Binder操作诲泌,應(yīng)用使用這個(gè)類遠(yuǎn)程調(diào)用AMS
  • ActivityThread盲赊,應(yīng)用進(jìn)程java層的根節(jié)點(diǎn),其main方法為應(yīng)用進(jìn)程java層的起點(diǎn)敷扫,完成應(yīng)用啟動(dòng)初始化工作哀蘑,并通過Binder和Handler負(fù)責(zé)應(yīng)用與system_server進(jìn)程間通信的消息轉(zhuǎn)發(fā)工作
  • ApplicationThread,工作在應(yīng)用進(jìn)程,ActivityThread的成員變量绘迁,負(fù)責(zé)應(yīng)用與system_server間的通信合溺,與AMS功能對應(yīng),其作為Binder服務(wù)端缀台,system_server通過ApplicationThreadProxy遠(yuǎn)程調(diào)用ApplicationThread棠赛,從而調(diào)用ActivityThread的各個(gè)方法,經(jīng)過ActivityThread的轉(zhuǎn)發(fā)膛腐,從而控制整個(gè)應(yīng)用
  • Instrumentation睛约,ActivityThread對Activity生命周期的調(diào)用具體通過這個(gè)類實(shí)現(xiàn)

以下我們通過Launcher啟動(dòng)一個(gè)應(yīng)用來演示一個(gè)應(yīng)用的啟動(dòng)過程:

startActivity

通過Launcher啟動(dòng)一個(gè)帶視圖的應(yīng)用,即啟動(dòng)一個(gè)Activity,此時(shí)這個(gè)Activity所需要依附的進(jìn)程還未啟動(dòng):

首先我們在Launcher的main線程(即所謂UI線程)里調(diào)用startActivity,這個(gè)方法最終通過Instrumentation調(diào)用ActivityManagerProxy的同名方法碟狞,通過AMP遠(yuǎn)程調(diào)用AMS(ActivityManagerService的同名方法)耕姊,

打印main 線程的調(diào)用棧,調(diào)用從下到上棍丐,Activity的startActivity方法最終調(diào)到了AMP的startActivity误辑,作為Binder客戶端這個(gè)startActivity的實(shí)現(xiàn)就是打包各種參數(shù)并傳到Binder驅(qū)動(dòng)

main:


image

showStartingWindow

調(diào)到這里,因?yàn)锳MS和AMP是實(shí)現(xiàn)了同一個(gè)接口的歌逢,所以在AMS作為服務(wù)端也有同名方法巾钉,下面是在system_server進(jìn)程中,一個(gè)被啟動(dòng)來處理這個(gè)消息的Binder線程的調(diào)用棧:


image

可以看到Binder在倒數(shù)第四行秘案,調(diào)用了startActivity砰苍,下面三個(gè)函數(shù)啟動(dòng)的作用就是取出并解析傳過來的數(shù)據(jù),然后交給對應(yīng)的方法處理阱高,這里根據(jù)傳過來的方法id調(diào)用到了ActivityManagerService的startActivity方法赚导,再經(jīng)過層層調(diào)用,通知WMS顯示startingWindow赤惊,所謂startingWindow吼旧,就是系統(tǒng)為了應(yīng)用之間的過渡平滑,應(yīng)用在啟動(dòng)之前未舟,預(yù)先啟動(dòng)起來的預(yù)覽視圖圈暗,這是應(yīng)用的MainActivity的theme里面配置的,這個(gè)視圖的顯示速度很快裕膀,因?yàn)槠洳粚儆趹?yīng)用進(jìn)程员串,不需要等待應(yīng)用初始化,往往在點(diǎn)擊應(yīng)用圖標(biāo)的瞬間就能顯示昼扛。

schedulePauseActivity

再看這次調(diào)用中另一個(gè)方法的調(diào)用棧:


image

調(diào)到了ApplicationThreadProxy(ATP)的schedulePauseActivity方法寸齐,看名字,就知道這又是一個(gè)Binder客戶端,這個(gè)Binder客戶端對應(yīng)的Binder服務(wù)端在Launcher的進(jìn)程里访忿,名字叫ApplicationThread瞧栗,system_server進(jìn)程通過這個(gè)ATP可以跨進(jìn)程調(diào)用Launcher的方法(每個(gè)應(yīng)用進(jìn)程都有一個(gè)ApplicationThread,可見system_server進(jìn)程存有所有由它管理的進(jìn)程的ATP海铆,因?yàn)樗枰ㄟ^這些ATP去管理所有應(yīng)用進(jìn)程迹恐,如控制應(yīng)用組件的生命周期),到這里卧斟,整個(gè)調(diào)用鏈從Launcher進(jìn)程的main線程殴边,到system_server進(jìn)程,現(xiàn)在又要回到Launcher珍语,但是要注意锤岸,通過Binder再調(diào)回去之后,ApplicationThread的schedulepauseActivity方法就是在一個(gè)另起的Binder線程里了板乙,main線程會(huì)繼續(xù)執(zhí)行它后續(xù)的指令不受影響是偷,我們現(xiàn)在查看Launcher里面這個(gè)另起的Binder線程的調(diào)用棧:

image

這里可以看到,在ApplicationThread的schedulepauseActivity方法里的處理募逞,Binder線程往Handler里發(fā)送了一條消息蛋铆,這個(gè)消息將由main線程來處理

activityPaused

此時(shí)我們查看主線程收到這個(gè)這個(gè)message之后的處理:

image

可以看到收到在handleMessage里,主線程調(diào)用了ActivityThread的handlePauseActivity放接,我們來看一下handlePauseActivity的實(shí)現(xiàn)刺啦,下面是幾行關(guān)鍵代碼:

            performPauseActivity(token, finished, r.isPreHoneycomb(), "handlePauseActivity");
                ...
                ...
            // Tell the activity manager we have paused.
            if (!dontReport) {
                try {
                    ActivityManagerNative.getDefault().activityPaused(token);
                } catch (RemoteException ex) {
                    throw ex.rethrowFromSystemServer();
                }
            }

performPauseActivity最終會(huì)調(diào)用到Activity的onPause方法(在這之前還會(huì)先調(diào)用Fragment的onPause),然后調(diào)用到ActivityManagerNative.getDefault().activityPaused(token) 也就是我們上圖調(diào)用棧所示的AMP的activityPaused方法纠脾。

到這里玛瘸,整個(gè)流程還沒有走到一個(gè)新的Activity的創(chuàng)建甚至連新的應(yīng)用進(jìn)程都還沒有創(chuàng)建,Launcher與system_server兩個(gè)進(jìn)程之間已經(jīng)經(jīng)過了來回各一次跨進(jìn)程的調(diào)用苟蹈。而到現(xiàn)在對應(yīng)用開發(fā)者能實(shí)際感知的到的很重要的一點(diǎn)糊渊,就是當(dāng)前Activity和Fragment走到到了生命周期onPause。應(yīng)用開發(fā)者該在這里做狀態(tài)保存工作了慧脱。

Process.start

回到AMP的activityPaused方法再来,現(xiàn)在Launcher的主線程又要遠(yuǎn)程調(diào)用AMS,system_server端會(huì)把這個(gè)調(diào)用交個(gè)一個(gè)空閑Binder線程去處理磷瘤,我們查看其調(diào)用棧:


image

注意 ActivityStackSupervisor中的startSpecificActivityLocked方法芒篷,這個(gè)方法在這里會(huì)進(jìn)入分水嶺,這里會(huì)檢查這個(gè)Activity需要依附的進(jìn)程有沒有被創(chuàng)建采缚,如果已經(jīng)創(chuàng)建针炉,則會(huì)進(jìn)入realStartActivityLocked方法,遠(yuǎn)程調(diào)會(huì)Launcher進(jìn)程扳抽,實(shí)例化要啟動(dòng)的Activity篡帕,并依次調(diào)用其onCreate殖侵,onStart,onResume生命周期方法(當(dāng)然其中各個(gè)方法的調(diào)用都是經(jīng)過各個(gè)類層層調(diào)用镰烧,但如果從應(yīng)用開發(fā)的角度來說就是這個(gè)調(diào)用順序拢军,期間不需要再由AMS干預(yù)),但對應(yīng)進(jìn)程如果不存在怔鳖,則還需要調(diào)用AMS的startProcess創(chuàng)建這個(gè)進(jìn)程茉唉,如上調(diào)用棧棧頂走到Process類的start方法,注意調(diào)用這個(gè)方法時(shí)傳遞的一個(gè)參數(shù)结执,entryPoint度陆,這里是android.app.ActivityThread

            // Start the process.  It will either succeed and return a result containing
            // the PID of the new process, or else throw a RuntimeException.
            boolean isActivityProcess = (entryPoint == null);
            if (entryPoint == null) entryPoint = "android.app.ActivityThread";
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
                    app.processName);
            checkTime(startTime, "startProcess: asking zygote to start proc");
            Process.ProcessStartResult startResult = Process.start(entryPoint,
                    app.processName, uid, uid, gids, debugFlags, mountExternal,
                    app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
                    app.info.dataDir, entryPointArgs);
            checkTime(startTime, "startProcess: returned from zygote!");

傳遞這個(gè)參數(shù),新進(jìn)程在啟動(dòng)之后就會(huì)調(diào)用這個(gè)類的main方法作為java層的起點(diǎn)(java層第一個(gè)方法應(yīng)該是ZygoInit的main,但在調(diào)用棧中根據(jù)傳過來的參數(shù)分成別反射調(diào)用了SystemServer和ActiviThread的main献幔,我們習(xí)慣上把這兩個(gè)函數(shù)當(dāng)成起點(diǎn))懂傀,至于Process.start的實(shí)現(xiàn),這里先不深究蜡感,大致過程蹬蚁,zygote進(jìn)程與system_server之間通過socket通信,要?jiǎng)?chuàng)建進(jìn)程時(shí)郑兴,system_server 進(jìn)程里通過往socket寫入消息缚忧,zygote接收到消息后fork出一個(gè)進(jìn)程,最終會(huì)調(diào)用ActivityThread的main函數(shù)杈笔,下面看一下創(chuàng)建進(jìn)程需要的參數(shù):

     * Starts a new process via the zygote mechanism.
     *
     * @param processClass Class name whose static main() to run
     * @param niceName 'nice' process name to appear in ps
     * @param uid a POSIX uid that the new process should setuid() to
     * @param gid a POSIX gid that the new process shuold setgid() to
     * @param gids null-ok; a list of supplementary group IDs that the
     * new process should setgroup() to.
     * @param debugFlags Additional flags.
     * @param targetSdkVersion The target SDK version for the app.
     * @param seInfo null-ok SELinux information for the new process.
     * @param abi the ABI the process should use.
     * @param instructionSet null-ok the instruction set to use.
     * @param appDataDir null-ok the data directory of the app.
     * @param extraArgs Additional arguments to supply to the zygote process.
     * @return An object that describes the result of the attempt to start the process.
     * @throws ZygoteStartFailedEx if process start failed for any reason
     */

其實(shí)現(xiàn):

            /**
             * See com.android.internal.os.ZygoteInit.readArgumentList()
             * Presently the wire format to the zygote process is:
             * a) a count of arguments (argc, in essence)
             * b) a number of newline-separated argument strings equal to count
             *
             * After the zygote process reads these it will write the pid of
             * the child or -1 on failure, followed by boolean to
             * indicate whether a wrapper process was used.
             */
            final BufferedWriter writer = zygoteState.writer;
            final DataInputStream inputStream = zygoteState.inputStream;
            writer.write(Integer.toString(args.size()));
            writer.newLine();
            for (int i = 0; i < sz; i++) {
                String arg = args.get(i);
                writer.write(arg);
                writer.newLine();
            }
            writer.flush();
            ---
            ---
            // Always read the entire result from the input stream to avoid leaving
            // bytes in the stream for future process starts to accidentally stumble
            // upon.
            result.pid = inputStream.readInt();
            result.usingWrapper = inputStream.readBoolean();

往流里寫入值各種參數(shù),再從流里讀回返回信息糕非,具體的實(shí)現(xiàn)就是zygote進(jìn)程的事了蒙具。

至此,一個(gè)應(yīng)用進(jìn)程就已經(jīng)啟動(dòng)朽肥,我們進(jìn)入android.app.ActivityThread的main方法禁筏,我們可以當(dāng)這里是應(yīng)用的起點(diǎn)。

ActivityThread.main

從 ActivityThread 的main方法開始衡招,應(yīng)用進(jìn)入 java 層篱昔,應(yīng)用在main里面的關(guān)鍵代碼:

    public static void main(String[] args) {
        ... ...
        Looper.prepareMainLooper();
        ActivityThread thread = new ActivityThread();
        thread.attach(false);
        ... ...
        Looper.loop();
    }

主要的三件事:

  1. 調(diào)用Looper.prepareMainLooper 創(chuàng)建mainLooper并賦值給Loop (這個(gè)looper的MessageQueue不能quit)靜態(tài)變量 sMainLooper ,這樣應(yīng)用可以在任何地方拿到主線程的Looper

  2. 創(chuàng)建ActivityThread實(shí)例始腾,并調(diào)用attach州刽,這兩步很關(guān)鍵,首先浪箭,ActivityThread對象創(chuàng)建時(shí)穗椅,會(huì)創(chuàng)建ResourcesManager的單例對象,還會(huì)創(chuàng)建 ApplicationThread 對象作為匿名Binder服務(wù)端用以跟system_server進(jìn)程通信奶栖,在thread.attach(false) 中通過AMP把 這個(gè)對象注冊到AMS:

        final IActivityManager mgr = ActivityManagerNative.getDefault();
        try {
            mgr.attachApplication(mAppThread);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    

    AMS 對各應(yīng)用組件的生命周期管理就是通過這個(gè)對象實(shí)現(xiàn)的匹表,AMS會(huì)通過這個(gè)ApplicationThread 對象遠(yuǎn)程調(diào)用應(yīng)用進(jìn)程的方法從而實(shí)現(xiàn)管理门坷。

    ?

    另外在attach 方法里ActivityThread對象會(huì)把自己賦值給靜態(tài)變量sCurrentActivityThread,在應(yīng)用開發(fā)中可以通過反射ActivityThread 直接拿到這個(gè)靜態(tài)變量對象或反射后調(diào)用靜態(tài)方法 currentActivityThread()拿到應(yīng)用的ActivityThread 對象袍镀,從而可以拿到其成員變量mAppThread默蚌,mInstrumentation,插件化方案可能需要hook這兩個(gè)對象苇羡。

    ?

  3. 主線程啟動(dòng)loop绸吸,進(jìn)入循環(huán),等待其他線程往消息隊(duì)列里發(fā)消息

attachApplication

遠(yuǎn)程調(diào)用AMS的attachApplication方法后宣虾,會(huì)輾轉(zhuǎn)到系統(tǒng)進(jìn)場中AMS的attachApplicationLocked惯裕,通過ProcessRecord.makeActive將這個(gè)IApplicationThread 傳入與進(jìn)程相關(guān)的ProcessRecord,這個(gè)對象與每個(gè)用戶進(jìn)程相對應(yīng)绣硝, 這樣system_server進(jìn)程就持有了應(yīng)用的一個(gè)Binder蜻势,之后就可以通過這個(gè)Binder給應(yīng)用發(fā)消息,從而管理應(yīng)用了鹉胖。

bindApplication

之后system_server進(jìn)程通過thread.bindApplication遠(yuǎn)程調(diào)用應(yīng)用進(jìn)程的ApplicationThread的同名方法握玛,同之前的其他調(diào)用,應(yīng)用進(jìn)程里bindApplication這個(gè)方法是運(yùn)行在某個(gè)binder線程的甫菠,這里這個(gè)Binder線程調(diào)用這個(gè)方法通過handler即成員變量mH把消息丟給了主線程挠铲,主線程收到消息轉(zhuǎn)到ActivityThread的handleBindApplication方法,查看調(diào)用棧

system_server:

image

從attachApplication 調(diào)用到 bindApplication寂诱,整個(gè)調(diào)用過程由應(yīng)用發(fā)起拂苹,將ApplicationThread傳遞給AMS(attachApplication這個(gè)方法最主要的功能就是把ApplicatioThread傳遞給了system_server進(jìn)程,從此應(yīng)用進(jìn)程和system_server進(jìn)程可以互相通信)痰洒,然后AMS拿到這個(gè)ApplicationThread的客戶端ATP瓢棒,調(diào)用其bindApplication,這樣調(diào)用又走回了應(yīng)用丘喻,應(yīng)用會(huì)在bindApplication里面做一些初始化工作脯宿,如實(shí)例化Instrumentation,實(shí)例化Application泉粉,并賦值給mInitialApplication = app;這個(gè)變量的賦值是唯一的连霉,只會(huì)有這一次,也就是一個(gè)進(jìn)程應(yīng)用進(jìn)程只會(huì)有一個(gè)mInitialApplication嗡靡,但是跺撼,這并不意味著一個(gè)進(jìn)程只有一個(gè)Application實(shí)例,一個(gè)進(jìn)程里是有可能創(chuàng)建多個(gè)Application實(shí)例的讨彼,比如下面要講的handleLaunchActivity方法财边,每啟動(dòng)一個(gè)Activity,都會(huì)去判斷這個(gè)Activity對應(yīng)的Application有沒有被實(shí)例化点骑,若沒有酣难,則會(huì)創(chuàng)建谍夭,并添加到mAllApplications列表,這種情況會(huì)在兩個(gè)應(yīng)用共用進(jìn)程時(shí)出現(xiàn)憨募。mInitialApplication賦值后紧索,會(huì)作為參數(shù)啟動(dòng)provider。

bindApplication:

        // Allow disk access during application and provider setup. This could
        // block processing ordered broadcasts, but later processing would
        // probably end up doing the same disk access.
        final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
        try {
            // If the app is being launched for full backup or restore, bring it up in
            // a restricted environment with the base application class.
          //這里只會(huì)實(shí)例化Application菜谣,而不會(huì)調(diào)用其onCreate
            Application app = data.info.makeApplication(data.restrictedBackupMode, null);
            mInitialApplication = app;

            // don't bring up providers in restricted mode; they may depend on the
            // app's custom Application class
            if (!data.restrictedBackupMode) {
                if (!ArrayUtils.isEmpty(data.providers)) {
                    //初始化ContentProvider
                    installContentProviders(app, data.providers);
                    // For process that contains content providers, we want to
                    // ensure that the JIT is enabled "at some point".
                    mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
                }
            }

            // Do this after providers, since instrumentation tests generally start their
            // test thread at this point, and we don't want that racing.
            try {
                mInstrumentation.onCreate(data.instrumentationArgs);
            }
            catch (Exception e) {
                throw new RuntimeException(
                    "Exception thrown in onCreate() of "
                    + data.instrumentationName + ": " + e.toString(), e);
            }

            try {
              //調(diào)用Application.onCreate
                mInstrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
                if (!mInstrumentation.onException(app, e)) {
                    throw new RuntimeException(
                        "Unable to create application " + app.getClass().getName()
                        + ": " + e.toString(), e);
                }
            }
        } finally {
            StrictMode.setThreadPolicy(savedPolicy);
        }
    private void installContentProviders(
            Context context, List<ProviderInfo> providers) {
        final ArrayList<IActivityManager.ContentProviderHolder> results =
            new ArrayList<IActivityManager.ContentProviderHolder>();

        for (ProviderInfo cpi : providers) {
            if (DEBUG_PROVIDER) {
                StringBuilder buf = new StringBuilder(128);
                buf.append("Pub ");
                buf.append(cpi.authority);
                buf.append(": ");
                buf.append(cpi.name);
                Log.i(TAG, buf.toString());
            }
          //這個(gè)context就是mInitialApplication珠漂,這里會(huì)實(shí)例化provider
          //installProvider方法里會(huì)為每個(gè)provider賦值一個(gè)context,這個(gè)Context有可能是                   //mInitialApplication本身尾膊,也可能是根據(jù)不同包名重新創(chuàng)建的
          //這個(gè)方法里還會(huì)調(diào)用ContentProvider的onCreate生命周期方法
          //要注意媳危,直到這里,我們還在ActivityThread的bindApplication方法里冈敛,這是AMS對應(yīng)用進(jìn)程的第          //一個(gè)遠(yuǎn)程調(diào)用待笑,我們雖然已經(jīng)創(chuàng)建了Application實(shí)例,但我們還沒有調(diào)用其onCreate抓谴,還沒有任何          //Activity和Service組件被實(shí)例化暮蹂,而在這里,所有ContentProvider已經(jīng)完成創(chuàng)建癌压,調(diào)用                //onCreate并注冊到AMS了
            IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
                    false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
            if (cph != null) {
                cph.noReleaseNeeded = true;
                results.add(cph);
            }
        }
        //注冊到AMS
        try {
            ActivityManagerNative.getDefault().publishContentProviders(
                getApplicationThread(), results);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }

bindApplication完成后仰泻,到這里應(yīng)用進(jìn)程已經(jīng)先后完成了Application的實(shí)例化,ContentProvider的實(shí)例化和onCreate生命周期滩届,Application的onCreate生命周期集侯。

scheduleLaunchActivity

注意AMS里面 attachApplicationLocked方法,除了遠(yuǎn)程調(diào)用ActivityThread的bindApplication外帜消,還調(diào)用了其scheduleLaunchActivity方法棠枉,這個(gè)方法最終會(huì)實(shí)例化一個(gè)Activity,調(diào)用其生命周期方法券犁。先來看system_server端的調(diào)用棧:

image

下面是上面兩次遠(yuǎn)程調(diào)用,轉(zhuǎn)到應(yīng)用進(jìn)程后對應(yīng)的兩次處理汹碱,都是Binder線程收到消息后重新丟到主線程里后主線程的調(diào)用棧粘衬。

image
image

handleLaunchActivity是應(yīng)用進(jìn)程收到的第二個(gè)system_server的遠(yuǎn)程調(diào)用(通過handler中轉(zhuǎn)過的),我們來看一下主線程在handleLaunchActivity里做了什么:

        // Make sure we are running with the most recent config.
        handleConfigurationChanged(null, null);
        ... ...
        // Initialize before creating the activity
        WindowManagerGlobal.initialize();

        Activity a = performLaunchActivity(r, customIntent);
        if (a != null) {
            r.createdConfig = new Configuration(mConfiguration);
            reportSizeConfigurations(r);
            Bundle oldState = r.state;
            handleResumeActivity(r.token, false, r.isForward,
                    !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
            ... ...
        }

performLaunchActivity得到了一個(gè)Activity咳促,之后調(diào)用了handleResumeActivity稚新,這里方法里就會(huì)調(diào)用Activity的onResume生命周期方法。再看在這之前performLaunchActivity的邏輯:

        Activity activity = null;
        try {
          //反射實(shí)例化Activity
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to instantiate activity " + component
                    + ": " + e.toString(), e);
            }
        }

        try {
          //拿到Application跪腹,這個(gè)Application是之前已經(jīng)創(chuàng)建的褂删,若對應(yīng)的Application之前沒有創(chuàng)建
          //則會(huì)先實(shí)例化,這種情況出現(xiàn)在一個(gè)應(yīng)用進(jìn)程承載多個(gè)應(yīng)用時(shí)冲茸,啟動(dòng)第一個(gè)之外的其他應(yīng)用時(shí)應(yīng)用進(jìn)程
          //已經(jīng)創(chuàng)建并與AMS綁定屯阀,所以不會(huì)走bindApplication方法缅帘,所以新應(yīng)用對應(yīng)的Application是還沒有
          //創(chuàng)建的,需要先創(chuàng)建难衰。
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);
            ... ...
            if (activity != null) {
              //這里實(shí)際是一個(gè)ContextImpl實(shí)例
                Context appContext = createBaseContextForActivity(r, activity);
                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                Configuration config = new Configuration(mCompatConfiguration);
                if (r.overrideConfig != null) {
                    config.updateFrom(r.overrideConfig);
                }
                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                        + r.activityInfo.name + " with config " + config);
                Window window = null;
                if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
                    window = r.mPendingRemoveWindow;
                    r.mPendingRemoveWindow = null;
                    r.mPendingRemoveWindowManager = null;
                }
                //典型裝飾者模式钦无,Activity的很多功能會(huì)委托給ContextImpl實(shí)例實(shí)現(xiàn)
                activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window);

                if (customIntent != null) {
                    activity.mIntent = customIntent;
                }
                r.lastNonConfigurationInstances = null;
                activity.mStartedActivity = false;
                int theme = r.activityInfo.getThemeResource();
                if (theme != 0) {
                    activity.setTheme(theme);
                }

                activity.mCalled = false;
              
              //調(diào)用Activity.onCreate
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
              ... ...
                //Activity.onStart
                if (!r.activity.mFinished) {
                    activity.performStart();
                    r.stopped = false;
                }
              ///Activity.onRestoreInstanceState
                if (!r.activity.mFinished) {
                    if (r.isPersistable()) {
                        if (r.state != null || r.persistentState != null) {
                            mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
                                    r.persistentState);
                        }
                    } else if (r.state != null) {
                        mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
                    }
                }


利用Instrumentation反射創(chuàng)建Activity,然后r.packageInfo.makeApplication(false, mInstrumentation)盖袭,這個(gè)方法會(huì)判斷當(dāng)前應(yīng)用(注意是應(yīng)用而不是進(jìn)程)有沒有Application實(shí)例失暂,若沒有,則創(chuàng)建鳄虱,創(chuàng)建其ContextImpl弟塞,調(diào)用其生命周期方法onCreate,注意Application app = r.packageInfo.makeApplication(false, mInstrumentation); 這個(gè)方法拙已,其實(shí)現(xiàn)末尾處有一段判斷

        if (mApplication != null) {
            return mApplication;//這里作為應(yīng)用進(jìn)程第一個(gè)被創(chuàng)建的Application决记,在bindApplication里就完成了實(shí)例化和生命周期onCreate,這里直接返回
        }
        //這里省略了反射實(shí)例化Application的代碼
        ... ...
        if (instrumentation != null) {
            try {
                instrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
              ... ...
            }
        }

若傳遞的instrumentation不為空悠栓,則調(diào)用其onCreate霉涨,之前在bindAppliction里面調(diào)用傳遞參數(shù)是空,所以只是實(shí)例化了Application惭适,這里在參數(shù)不為空笙瑟,如果這個(gè)Application不是應(yīng)用進(jìn)程的第一個(gè)Application,那么會(huì)在這里實(shí)例化并調(diào)用onCreate 癞志。

Activity.attach

可以看出往枷,如果同一個(gè)進(jìn)程運(yùn)行多個(gè)應(yīng)用的話,除了一個(gè)應(yīng)用外凄杯,一個(gè)應(yīng)用的第一個(gè)Activity會(huì)比Application先實(shí)例化错洁,只是生命周期的調(diào)用時(shí)機(jī)在Application后面。Activity的創(chuàng)建過程是先反射創(chuàng)建其實(shí)例戒突,然后作為參數(shù)創(chuàng)建其委托對象ContextImpl屯碴,然后attach這個(gè)對象,將ContextImpl作為自己的成員變量膊存,很多功能會(huì)委托給這個(gè)對象實(shí)現(xiàn)导而,除此之外Activity.attach方法還會(huì)為創(chuàng)建PhoneWindow作為成員變量。

callActivityOnCreate

attach之后隔崎,來到mInstrumentation.callActivityOnCreate今艺,這里會(huì)調(diào)用Activity的onCreate,activity.performStart爵卒,調(diào)用activity.onStart虚缎,mInstrumentation.callActivityOnRestoreInstanceState,調(diào)用Activity.onRestoreInstanceState钓株,performLaunchActivity 方法返回之后实牡,handleLaunchActivity繼續(xù)走到ActivityThread.handleResumeActivity陌僵,調(diào)用Activity.onResume 。這些方法里面還夾雜Fragment的管理铲掐,這里先忽略拾弃。

scheduleStopActivity

至此,完成這個(gè)應(yīng)用啟動(dòng)需要走的所有生命周期摆霉,而Launcher我們只分析到OnPause豪椿,一個(gè)完整的過程它是需要走到onStop才對的,我們看下在Launcher的ActivityThread調(diào)用ams的activityPaused里面携栋,AMS除了通知Zygote孵化新進(jìn)程外還做了什么搭盾,我們先回顧下創(chuàng)建應(yīng)用進(jìn)程的調(diào)用棧,:

image

Launcher在走完onPause生命周期后婉支,就會(huì)通知AMS去啟動(dòng)新的Activity鸯隅,而啟動(dòng)時(shí)發(fā)現(xiàn)對應(yīng)的進(jìn)程還沒創(chuàng)建,所以這里先創(chuàng)建進(jìn)程向挖,這之后AMS就等著新啟動(dòng)的進(jìn)程走到j(luò)ava層的attach方法來注冊自己蝌以。

我們看上面這個(gè)調(diào)用里,在completePausedLocked方法里何之,還有另一個(gè)調(diào)用跟畅,看下面的調(diào)用棧:

image

往Handler里面發(fā)了一條消息,這個(gè)handler攜帶的消息會(huì)在system_server的一個(gè)Looper子線程里被處理溶推,我們看其處理的調(diào)用棧:

image

這里就會(huì)去調(diào)用經(jīng)過Binder和Handler中轉(zhuǎn)徊件,就會(huì)走到Launcher的的onStop生命周期了。

回顧

到這里大家可以回顧一下兩個(gè)應(yīng)用的的Activity生命周期是怎么走的蒜危,首先Launcher向AMS發(fā)消息要啟動(dòng)一個(gè)Activity虱痕,AMS發(fā)消息回來,讓Launcher走到onPause辐赞,然后Launcher告訴AMS onPause已經(jīng)調(diào)用部翘,這個(gè)“告訴”的過程中往system_server的一個(gè)Looper線程中發(fā)了條消息,這個(gè)消息收到后就會(huì)再回過來調(diào)用到Launcher的onStop响委,同時(shí)新思,還通過Process.start通知Zygote孵化出要啟動(dòng)的應(yīng)用進(jìn)程,應(yīng)用進(jìn)程啟動(dòng)后通過AMP.attachApplication注冊自己的ApplicationThread到AMS晃酒,AMS回過來通過ApplicationThread調(diào)用了應(yīng)用的bindApplication和scheduleLaunchActivity表牢,前者完成Application對象實(shí)例化窄绒,Instrumentation初始化贝次,ContentProvider的實(shí)例化和onCreate調(diào)用,Application的onCreate的調(diào)用彰导,后者完成Activity的實(shí)例化蛔翅,以及onCreate,onStart,onResume 連續(xù)三個(gè)生命周期的調(diào)用敲茄。這里可以看出兩點(diǎn):

  1. Application的實(shí)例化是在ContentProvider之前的,但是Application的onCreate調(diào)用時(shí)機(jī)其實(shí)是在ContentProvider的onCreate之后的山析。
  2. Launcher的onStop的調(diào)用其實(shí)和被啟動(dòng)的應(yīng)用的Activity的生命周期是沒有絕對的順序的堰燎,但它的onPause肯定是要先被調(diào)用的(而在這之前還會(huì)通知WMS顯示應(yīng)用的startingWindow),其調(diào)用時(shí)機(jī)甚至比新應(yīng)用進(jìn)程的創(chuàng)建還早笋轨,AMS會(huì)等它被調(diào)用后才通知Zygote孵化新進(jìn)程(其實(shí)也不絕對秆剪,想象如果onPause耗時(shí)太久,必然會(huì)影響新進(jìn)程的啟動(dòng)了爵政,這里AMS會(huì)有超時(shí)機(jī)制仅讽,超過500毫秒還沒有通知AMS activityPaused,AMS就會(huì)不再等待钾挟,直接創(chuàng)建新進(jìn)程)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末洁灵,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子掺出,更是在濱河造成了極大的恐慌徽千,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件汤锨,死亡現(xiàn)場離奇詭異双抽,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)泥畅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進(jìn)店門荠诬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人位仁,你說我怎么就攤上這事柑贞。” “怎么了聂抢?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵钧嘶,是天一觀的道長。 經(jīng)常有香客問我琳疏,道長有决,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任空盼,我火速辦了婚禮书幕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘揽趾。我一直安慰自己台汇,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著苟呐,像睡著了一般痒芝。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上牵素,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天严衬,我揣著相機(jī)與錄音,去河邊找鬼笆呆。 笑死请琳,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的赠幕。 我是一名探鬼主播单起,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼劣坊!你這毒婦竟也來了嘀倒?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤局冰,失蹤者是張志新(化名)和其女友劉穎测蘑,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體康二,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡碳胳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了沫勿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片挨约。...
    茶點(diǎn)故事閱讀 40,030評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖产雹,靈堂內(nèi)的尸體忽然破棺而出诫惭,到底是詐尸還是另有隱情,我是刑警寧澤蔓挖,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布夕土,位于F島的核電站,受9級特大地震影響瘟判,放射性物質(zhì)發(fā)生泄漏怨绣。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一拷获、第九天 我趴在偏房一處隱蔽的房頂上張望篮撑。 院中可真熱鬧,春花似錦匆瓜、人聲如沸赢笨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽质欲。三九已至,卻和暖如春糠馆,著一層夾襖步出監(jiān)牢的瞬間嘶伟,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工又碌, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留九昧,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓毕匀,卻偏偏與公主長得像铸鹰,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子皂岔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評論 2 355

推薦閱讀更多精彩內(nèi)容