安卓應用啟動流程(從點擊Launcher圖標開始)

閱讀這篇文章,需要對Binder有一定了解。我們通過從桌面啟動一個應用講解啟動一個安卓應用的流程。

遠程調用

這里要先明確一個概念,就是所謂的遠程調用即跨進程調用,安卓大部分情況下通過Binder來實現,其實現的大致原理,每個支持Binder的進程都有一個Binder線程池,當我們通過Binder遠程調用另一個進程的方法時,例如A進程遠程調用B進程的print方法,其過程是A進程把要調用的方法的方法描述(方法名,參數,身份確認信息等)裝進一個Parcel對象發送到Binder驅動,B進程中空閑的Binder線程會去取消息,當它取到消息后開始在B進程里運行,根據傳遞過來的方法描述去調用對應的方法,這樣兩個進程間就完成了一次跨進程的調用,屏蔽掉細節就變成了A進程調用了B進程的print方法,這里要注意的是,A進程往Binder驅動寫值后,可以選擇阻塞或不阻塞,也就是Binder的雙向還是單向模式,若調用模式為單向模式,A進程往Binder驅動寫入值后會立即返回,開始執行下一條指令,不在乎B進程是否正確處理了這個消息,而如果是雙向,則在A進程寫值后會一直等待,等待B進程處理完成print方法,再往Binder驅動回一條消息,A進程接收到這個消息后調用返回,開始執行下一條指令,這個過程就很像在同一個進程中調用方法了,想象若我們在A進程中也有同名方法print,這個方法的作用是往Binder驅動寫值并等待調用返回,而B進程收到消息并執行了B進程的print并在Binder驅動中寫回值,現在A進程收到寫回的消息,print返回,執行下一條指令,其過程就像是在A進程里執行了B進程的print方法一樣,足以讓使用者忽略掉這其實經過了跨進程的通信,而只是調用了一次普通方法。

幾個重要的類:

  • ActivityManagerService (簡稱AMS),運行在system_server 進程,其實質為一個Binder服務端,與之對應的是 ActivityManagerProxy(簡稱AMP),運行在各個應用即客戶端,封裝了Binder操作,應用使用這個類遠程調用AMS
  • ActivityThread,應用進程java層的根節點,其main方法為應用進程java層的起點,完成應用啟動初始化工作,并通過Binder和Handler負責應用與system_server進程間通信的消息轉發工作
  • ApplicationThread,工作在應用進程,ActivityThread的成員變量,負責應用與system_server間的通信,與AMS功能對應,其作為Binder服務端,system_server通過ApplicationThreadProxy遠程調用ApplicationThread,從而調用ActivityThread的各個方法,經過ActivityThread的轉發,從而控制整個應用
  • Instrumentation,ActivityThread對Activity生命周期的調用具體通過這個類實現

以下我們通過Launcher啟動一個應用來演示一個應用的啟動過程:

startActivity

通過Launcher啟動一個帶視圖的應用,即啟動一個Activity,此時這個Activity所需要依附的進程還未啟動:

首先我們在Launcher的main線程(即所謂UI線程)里調用startActivity,這個方法最終通過Instrumentation調用ActivityManagerProxy的同名方法,通過AMP遠程調用AMS(ActivityManagerService的同名方法),

打印main 線程的調用棧,調用從下到上,Activity的startActivity方法最終調到了AMP的startActivity,作為Binder客戶端這個startActivity的實現就是打包各種參數并傳到Binder驅動

main:


image

showStartingWindow

調到這里,因為AMS和AMP是實現了同一個接口的,所以在AMS作為服務端也有同名方法,下面是在system_server進程中,一個被啟動來處理這個消息的Binder線程的調用棧:


image

可以看到Binder在倒數第四行,調用了startActivity,下面三個函數啟動的作用就是取出并解析傳過來的數據,然后交給對應的方法處理,這里根據傳過來的方法id調用到了ActivityManagerService的startActivity方法,再經過層層調用,通知WMS顯示startingWindow,所謂startingWindow,就是系統為了應用之間的過渡平滑,應用在啟動之前,預先啟動起來的預覽視圖,這是應用的MainActivity的theme里面配置的,這個視圖的顯示速度很快,因為其不屬于應用進程,不需要等待應用初始化,往往在點擊應用圖標的瞬間就能顯示。

schedulePauseActivity

再看這次調用中另一個方法的調用棧:


image

調到了ApplicationThreadProxy(ATP)的schedulePauseActivity方法,看名字,就知道這又是一個Binder客戶端,這個Binder客戶端對應的Binder服務端在Launcher的進程里,名字叫ApplicationThread,system_server進程通過這個ATP可以跨進程調用Launcher的方法(每個應用進程都有一個ApplicationThread,可見system_server進程存有所有由它管理的進程的ATP,因為它需要通過這些ATP去管理所有應用進程,如控制應用組件的生命周期),到這里,整個調用鏈從Launcher進程的main線程,到system_server進程,現在又要回到Launcher,但是要注意,通過Binder再調回去之后,ApplicationThread的schedulepauseActivity方法就是在一個另起的Binder線程里了,main線程會繼續執行它后續的指令不受影響,我們現在查看Launcher里面這個另起的Binder線程的調用棧:

image

這里可以看到,在ApplicationThread的schedulepauseActivity方法里的處理,Binder線程往Handler里發送了一條消息,這個消息將由main線程來處理

activityPaused

此時我們查看主線程收到這個這個message之后的處理:

image

可以看到收到在handleMessage里,主線程調用了ActivityThread的handlePauseActivity,我們來看一下handlePauseActivity的實現,下面是幾行關鍵代碼:

            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最終會調用到Activity的onPause方法(在這之前還會先調用Fragment的onPause),然后調用到ActivityManagerNative.getDefault().activityPaused(token) 也就是我們上圖調用棧所示的AMP的activityPaused方法。

到這里,整個流程還沒有走到一個新的Activity的創建甚至連新的應用進程都還沒有創建,Launcher與system_server兩個進程之間已經經過了來回各一次跨進程的調用。而到現在對應用開發者能實際感知的到的很重要的一點,就是當前Activity和Fragment走到到了生命周期onPause。應用開發者該在這里做狀態保存工作了。

Process.start

回到AMP的activityPaused方法,現在Launcher的主線程又要遠程調用AMS,system_server端會把這個調用交個一個空閑Binder線程去處理,我們查看其調用棧:


image

注意 ActivityStackSupervisor中的startSpecificActivityLocked方法,這個方法在這里會進入分水嶺,這里會檢查這個Activity需要依附的進程有沒有被創建,如果已經創建,則會進入realStartActivityLocked方法,遠程調會Launcher進程,實例化要啟動的Activity,并依次調用其onCreate,onStart,onResume生命周期方法(當然其中各個方法的調用都是經過各個類層層調用,但如果從應用開發的角度來說就是這個調用順序,期間不需要再由AMS干預),但對應進程如果不存在,則還需要調用AMS的startProcess創建這個進程,如上調用棧棧頂走到Process類的start方法,注意調用這個方法時傳遞的一個參數,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!");

傳遞這個參數,新進程在啟動之后就會調用這個類的main方法作為java層的起點(java層第一個方法應該是ZygoInit的main,但在調用棧中根據傳過來的參數分成別反射調用了SystemServer和ActiviThread的main,我們習慣上把這兩個函數當成起點),至于Process.start的實現,這里先不深究,大致過程,zygote進程與system_server之間通過socket通信,要創建進程時,system_server 進程里通過往socket寫入消息,zygote接收到消息后fork出一個進程,最終會調用ActivityThread的main函數,下面看一下創建進程需要的參數:

     * 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
     */

其實現:

            /**
             * 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();

往流里寫入值各種參數,再從流里讀回返回信息,具體的實現就是zygote進程的事了。

至此,一個應用進程就已經啟動,我們進入android.app.ActivityThread的main方法,我們可以當這里是應用的起點。

ActivityThread.main

從 ActivityThread 的main方法開始,應用進入 java 層,應用在main里面的關鍵代碼:

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

主要的三件事:

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

  2. 創建ActivityThread實例,并調用attach,這兩步很關鍵,首先,ActivityThread對象創建時,會創建ResourcesManager的單例對象,還會創建 ApplicationThread 對象作為匿名Binder服務端用以跟system_server進程通信,在thread.attach(false) 中通過AMP把 這個對象注冊到AMS:

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

    AMS 對各應用組件的生命周期管理就是通過這個對象實現的,AMS會通過這個ApplicationThread 對象遠程調用應用進程的方法從而實現管理。

    ?

    另外在attach 方法里ActivityThread對象會把自己賦值給靜態變量sCurrentActivityThread,在應用開發中可以通過反射ActivityThread 直接拿到這個靜態變量對象或反射后調用靜態方法 currentActivityThread()拿到應用的ActivityThread 對象,從而可以拿到其成員變量mAppThread,mInstrumentation,插件化方案可能需要hook這兩個對象。

    ?

  3. 主線程啟動loop,進入循環,等待其他線程往消息隊列里發消息

attachApplication

遠程調用AMS的attachApplication方法后,會輾轉到系統進場中AMS的attachApplicationLocked,通過ProcessRecord.makeActive將這個IApplicationThread 傳入與進程相關的ProcessRecord,這個對象與每個用戶進程相對應, 這樣system_server進程就持有了應用的一個Binder,之后就可以通過這個Binder給應用發消息,從而管理應用了。

bindApplication

之后system_server進程通過thread.bindApplication遠程調用應用進程的ApplicationThread的同名方法,同之前的其他調用,應用進程里bindApplication這個方法是運行在某個binder線程的,這里這個Binder線程調用這個方法通過handler即成員變量mH把消息丟給了主線程,主線程收到消息轉到ActivityThread的handleBindApplication方法,查看調用棧

system_server:

image

從attachApplication 調用到 bindApplication,整個調用過程由應用發起,將ApplicationThread傳遞給AMS(attachApplication這個方法最主要的功能就是把ApplicatioThread傳遞給了system_server進程,從此應用進程和system_server進程可以互相通信),然后AMS拿到這個ApplicationThread的客戶端ATP,調用其bindApplication,這樣調用又走回了應用,應用會在bindApplication里面做一些初始化工作,如實例化Instrumentation,實例化Application,并賦值給mInitialApplication = app;這個變量的賦值是唯一的,只會有這一次,也就是一個進程應用進程只會有一個mInitialApplication,但是,這并不意味著一個進程只有一個Application實例,一個進程里是有可能創建多個Application實例的,比如下面要講的handleLaunchActivity方法,每啟動一個Activity,都會去判斷這個Activity對應的Application有沒有被實例化,若沒有,則會創建,并添加到mAllApplications列表,這種情況會在兩個應用共用進程時出現。mInitialApplication賦值后,會作為參數啟動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.
          //這里只會實例化Application,而不會調用其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 {
              //調用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());
            }
          //這個context就是mInitialApplication,這里會實例化provider
          //installProvider方法里會為每個provider賦值一個context,這個Context有可能是                   //mInitialApplication本身,也可能是根據不同包名重新創建的
          //這個方法里還會調用ContentProvider的onCreate生命周期方法
          //要注意,直到這里,我們還在ActivityThread的bindApplication方法里,這是AMS對應用進程的第          //一個遠程調用,我們雖然已經創建了Application實例,但我們還沒有調用其onCreate,還沒有任何          //Activity和Service組件被實例化,而在這里,所有ContentProvider已經完成創建,調用                //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完成后,到這里應用進程已經先后完成了Application的實例化,ContentProvider的實例化和onCreate生命周期,Application的onCreate生命周期。

scheduleLaunchActivity

注意AMS里面 attachApplicationLocked方法,除了遠程調用ActivityThread的bindApplication外,還調用了其scheduleLaunchActivity方法,這個方法最終會實例化一個Activity,調用其生命周期方法。先來看system_server端的調用棧:

image

下面是上面兩次遠程調用,轉到應用進程后對應的兩次處理,都是Binder線程收到消息后重新丟到主線程里后主線程的調用棧。

image
image

handleLaunchActivity是應用進程收到的第二個system_server的遠程調用(通過handler中轉過的),我們來看一下主線程在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得到了一個Activity,之后調用了handleResumeActivity,這里方法里就會調用Activity的onResume生命周期方法。再看在這之前performLaunchActivity的邏輯:

        Activity activity = null;
        try {
          //反射實例化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,這個Application是之前已經創建的,若對應的Application之前沒有創建
          //則會先實例化,這種情況出現在一個應用進程承載多個應用時,啟動第一個之外的其他應用時應用進程
          //已經創建并與AMS綁定,所以不會走bindApplication方法,所以新應用對應的Application是還沒有
          //創建的,需要先創建。
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);
            ... ...
            if (activity != null) {
              //這里實際是一個ContextImpl實例
                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的很多功能會委托給ContextImpl實例實現
                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;
              
              //調用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反射創建Activity,然后r.packageInfo.makeApplication(false, mInstrumentation),這個方法會判斷當前應用(注意是應用而不是進程)有沒有Application實例,若沒有,則創建,創建其ContextImpl,調用其生命周期方法onCreate,注意Application app = r.packageInfo.makeApplication(false, mInstrumentation); 這個方法,其實現末尾處有一段判斷

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

若傳遞的instrumentation不為空,則調用其onCreate,之前在bindAppliction里面調用傳遞參數是空,所以只是實例化了Application,這里在參數不為空,如果這個Application不是應用進程的第一個Application,那么會在這里實例化并調用onCreate 。

Activity.attach

可以看出,如果同一個進程運行多個應用的話,除了一個應用外,一個應用的第一個Activity會比Application先實例化,只是生命周期的調用時機在Application后面。Activity的創建過程是先反射創建其實例,然后作為參數創建其委托對象ContextImpl,然后attach這個對象,將ContextImpl作為自己的成員變量,很多功能會委托給這個對象實現,除此之外Activity.attach方法還會為創建PhoneWindow作為成員變量。

callActivityOnCreate

attach之后,來到mInstrumentation.callActivityOnCreate,這里會調用Activity的onCreate,activity.performStart,調用activity.onStart,mInstrumentation.callActivityOnRestoreInstanceState,調用Activity.onRestoreInstanceState,performLaunchActivity 方法返回之后,handleLaunchActivity繼續走到ActivityThread.handleResumeActivity,調用Activity.onResume 。這些方法里面還夾雜Fragment的管理,這里先忽略。

scheduleStopActivity

至此,完成這個應用啟動需要走的所有生命周期,而Launcher我們只分析到OnPause,一個完整的過程它是需要走到onStop才對的,我們看下在Launcher的ActivityThread調用ams的activityPaused里面,AMS除了通知Zygote孵化新進程外還做了什么,我們先回顧下創建應用進程的調用棧,:

image

Launcher在走完onPause生命周期后,就會通知AMS去啟動新的Activity,而啟動時發現對應的進程還沒創建,所以這里先創建進程,這之后AMS就等著新啟動的進程走到java層的attach方法來注冊自己。

我們看上面這個調用里,在completePausedLocked方法里,還有另一個調用,看下面的調用棧:

image

往Handler里面發了一條消息,這個handler攜帶的消息會在system_server的一個Looper子線程里被處理,我們看其處理的調用棧:

image

這里就會去調用經過Binder和Handler中轉,就會走到Launcher的的onStop生命周期了。

回顧

到這里大家可以回顧一下兩個應用的的Activity生命周期是怎么走的,首先Launcher向AMS發消息要啟動一個Activity,AMS發消息回來,讓Launcher走到onPause,然后Launcher告訴AMS onPause已經調用,這個“告訴”的過程中往system_server的一個Looper線程中發了條消息,這個消息收到后就會再回過來調用到Launcher的onStop,同時,還通過Process.start通知Zygote孵化出要啟動的應用進程,應用進程啟動后通過AMP.attachApplication注冊自己的ApplicationThread到AMS,AMS回過來通過ApplicationThread調用了應用的bindApplication和scheduleLaunchActivity,前者完成Application對象實例化,Instrumentation初始化,ContentProvider的實例化和onCreate調用,Application的onCreate的調用,后者完成Activity的實例化,以及onCreate,onStart,onResume 連續三個生命周期的調用。這里可以看出兩點:

  1. Application的實例化是在ContentProvider之前的,但是Application的onCreate調用時機其實是在ContentProvider的onCreate之后的。
  2. Launcher的onStop的調用其實和被啟動的應用的Activity的生命周期是沒有絕對的順序的,但它的onPause肯定是要先被調用的(而在這之前還會通知WMS顯示應用的startingWindow),其調用時機甚至比新應用進程的創建還早,AMS會等它被調用后才通知Zygote孵化新進程(其實也不絕對,想象如果onPause耗時太久,必然會影響新進程的啟動了,這里AMS會有超時機制,超過500毫秒還沒有通知AMS activityPaused,AMS就會不再等待,直接創建新進程)
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,461評論 6 532
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,538評論 3 417
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,423評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,991評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,761評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,207評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,268評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,419評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,959評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,653評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,901評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,678評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,978評論 2 374

推薦閱讀更多精彩內容