Android深入四大組件(七)Android8.0 根Activity啓動過程(後篇)

相關文章
Android深入四大組件系列
Android系統啓動系列
Android應用程序進程系列
Android深入解析AMS系列

前言

在幾個月前我寫了Android深入四大組件(一)應用程序啓動過程(前篇)Android深入四大組件(一)應用程序啓動過程(後篇)這兩篇文章,它們都是基於Android 7.0,當我開始閱讀Android 8.0源碼時發現應用程序(根Activity)啓動過程照Android 7.0有了一些變化,因此又寫下了本篇文章,本篇文章照此前的文章不僅流程發生變化,而且增加了一些分析,算是升級版本。由於篇幅較長,Android8.0 根Activity啓動過程仍舊分爲前篇和後篇來進行講解。

1. ActivityThread啓動Activity的過程

通過前篇的介紹,我們知道目前的代碼邏輯運行在應用程序進程中。先來查看ActivityThread啓動Activity的過程的時序圖。
4.4.png

我們接着來查看ApplicationThread的scheduleLaunchActivity方法,其中ApplicationThread是ActivityThread的內部類,應用程序進程創建後會運行代表主線程的實例ActivityThread,它管理着當前應用程序進程的線程。ApplicationThread的scheduleLaunchActivity方法如下所示。

frameworks/base/core/java/android/app/ActivityThread.java

        @Override
        public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
                CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
                int procState, Bundle state, PersistableBundle persistentState,
                List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
                boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {
            updateProcessState(procState, false);
            ActivityClientRecord r = new ActivityClientRecord();
            r.token = token;
            r.ident = ident;
            r.intent = intent;
            r.referrer = referrer;
            ...
            updatePendingConfiguration(curConfig);
            sendMessage(H.LAUNCH_ACTIVITY, r);
        }

scheduleLaunchActivity方法會將啓動Activity的參數封裝成ActivityClientRecord ,sendMessage方法向H類發送類型爲LAUNCH_ACTIVITY的消息,並將ActivityClientRecord 傳遞過去,sendMessage方法有多個重載方法,最終調用的sendMessage方法如下所示。
frameworks/base/core/java/android/app/ActivityThread.java

   private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
        if (DEBUG_MESSAGES) Slog.v(
            TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
            + ": " + arg1 + " / " + obj);
        Message msg = Message.obtain();
        msg.what = what;
        msg.obj = obj;
        msg.arg1 = arg1;
        msg.arg2 = arg2;
        if (async) {
            msg.setAsynchronous(true);
        }
        mH.sendMessage(msg);
    }

這裏mH指的是H,它是ActivityThread的內部類並繼承Handler,是應用程序進程中主線程的消息管理類。H的代碼如下所示。

private class H extends Handler {
      public static final int LAUNCH_ACTIVITY         = 100;
      public static final int PAUSE_ACTIVITY          = 101;
...
public void handleMessage(Message msg) {
          if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
          switch (msg.what) {
              case LAUNCH_ACTIVITY: {
                  Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                  final ActivityClientRecord r = (ActivityClientRecord) msg.obj;//1
                  r.packageInfo = getPackageInfoNoCheck(
                          r.activityInfo.applicationInfo, r.compatInfo);//2
                  handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");//3
                  Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
              } break;
              case RELAUNCH_ACTIVITY: {
                  Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");
                  ActivityClientRecord r = (ActivityClientRecord)msg.obj;
                  handleRelaunchActivity(r);
                  Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
              } break;
            ...
}

查看H的handleMessage方法中對LAUNCH_ACTIVITY的處理,在註釋1處將傳過來的msg的成員變量obj轉換爲ActivityClientRecord。
在註釋2處通過getPackageInfoNoCheck方法獲得LoadedApk類型的對象並賦值給ActivityClientRecord 的成員變量packageInfo 。應用程序進程要啓動Activity時需要將該Activity所屬的APK加載進來,而LoadedApk就是用來描述已加載的APK文件。
在註釋3處調用handleLaunchActivity方法,代碼如下所示。
frameworks/base/core/java/android/app/ActivityThread.java

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
    ...
    WindowManagerGlobal.initialize();
    //啓動Activity
    Activity a = performLaunchActivity(r, customIntent);//1
    if (a != null) {
        r.createdConfig = new Configuration(mConfiguration);
        reportSizeConfigurations(r);
        Bundle oldState = r.state;
        //將Activity的狀態置爲Resume
        handleResumeActivity(r.token, false, r.isForward,
                !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);//2
        if (!r.activity.mFinished && r.startsNotResumed) {
            performPauseActivityIfNeeded(r, reason);
            if (r.isPreHoneycomb()) {
                r.state = oldState;
            }
        }
    } else {
        try {
            //停止Activity啓動
            ActivityManager.getService()
                .finishActivity(r.token, Activity.RESULT_CANCELED, null,
                        Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }
}

註釋1處的performLaunchActivity方法用來啓動Activity ,註釋2處的代碼用來將Activity 的狀態置爲Resume。如果該Activity爲null則會通知AMS停止啓動Activity。來查看performLaunchActivity方法做了什麼:
frameworks/base/core/java/android/app/ActivityThread.java

 private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        //獲取ActivityInfo類
        ActivityInfo aInfo = r.activityInfo;//1
        if (r.packageInfo == null) {
        //獲取APK文件的描述類LoadedApk
            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                    Context.CONTEXT_INCLUDE_CODE);//2
        }

        ComponentName component = r.intent.getComponent();//3
        ...
        //創建要啓動Activity的上下文環境
        ContextImpl appContext = createBaseContextForActivity(r);//4
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.getClassLoader();
            //用類加載器來創建該Activity的實例
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);//5
          ...
        } catch (Exception e) {
          ...
        }

        try {
            //創建Application
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);//6
            ...
            if (activity != null) {
               ...
                /**
                *7 初始化Activity
                */
                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, r.configCallback);

               ...
                if (r.isPersistable()) {
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);//8
                } else {
                    mInstrumentation.callActivityOnCreate(activity, r.state);
                }
               ...
            }
            r.paused = true;
            mActivities.put(r.token, r);
        } catch (SuperNotCalledException e) {
            throw e;
        } catch (Exception e) {
          ...
        }

        return activity;
    }

註釋1處用來獲取ActivityInfo,ActivityInfo用於存儲代碼和AndroidManifes設置的Activity和receiver節點信息,比如Activity的theme和launchMode。在註釋2處獲取APK文件的描述類LoadedApk。註釋3處獲取要啓動的Activity的ComponentName類,ComponentName類中保存了該Activity的包名和類名。註釋4處用來創建要啓動Activity的上下文環境。註釋5處根據ComponentName中存儲的Activity類名,用類加載器來創建該Activity的實例。註釋6處用來創建Application,makeApplication方法內部會調用Application的onCreate方法。註釋7處調用Activity的attach方法初始化Activity,attach方法中會創建Window對象(PhoneWindow)並與Activity自身進行關聯。註釋8處會調用Instrumentation的callActivityOnCreate方法來啓動Activity,如下所示。
frameworks/base/core/java/android/app/Instrumentation.java

  public void callActivityOnCreate(Activity activity, Bundle icicle,
            PersistableBundle persistentState) {
        prePerformCreate(activity);
        activity.performCreate(icicle, persistentState);//1
        postPerformCreate(activity);
    }

註釋1處調用了Activity的performCreate方法,代碼如下所示。
frameworks/base/core/java/android/app/Activity.java

  final void performCreate(Bundle icicle, PersistableBundle persistentState) {
        restoreHasCurrentPermissionRequest(icicle);
        onCreate(icicle, persistentState);
        mActivityTransitionState.readState(icicle);
        performCreateCommon();
    }

performCreate方法中會調用Activity的onCreate方法,講到這裏,根Activity就啓動了,即應用程序就啓動了。
根Activity啓動過程就講到這裏,下面我們來學習根Activity啓動過程中涉及到的進程。

2. 根Activity啓動過程中涉及的進程

在應用程序進程沒有創建的情況下,根Activity啓動過程中會涉及到4個進程,分別是Zygote進程、Launcher進程、AMS所在進程(SyetemServer進程)、應用程序進程。它們之間的關係如下圖所示。
4.5.png

首先Launcher進程向AMS請求創建根Activity,AMS會判斷根Activity所需的應用程序進程是否存在並啓動,如果不存在就會請求Zygote進程創建應用程序進程。應用程序進程準備就緒後會通知AMS,AMS會請求應用程序進程創建根Activity。關於上圖中四個步驟的進程間通信方式,其中步驟2和步驟3相關的進程採用的是Socket通信,步驟1和步驟4相關的進程採用的Binder通信。
上圖可能並不是很直觀,爲了更好的理解,下面給出這四個進程調用的時序圖。

4.6.png

如果是普通Activity啓動過程會涉及到幾個進程呢?答案是兩個,AMS所在進程和應用程序進程。實際上理解了根Activity的啓動過程(根Activity的onCreate過程),根Activity和普通Activity其他生命週期狀態比如onStart、onResume等過程也會很輕鬆的掌握,這些知識點都是觸類旁通的,想要具體瞭解這些知識點的同學可以自行閱讀源碼。

公衆號末尾1.1.jpg

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章