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

相關文章
Android深刻四大組件系列
Android系統啓動系列html

Android應用程序進程系列
Android深刻解析AMS系列java

前言

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

1. ActivityThread啓動Activity的過程

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

4.4.png

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

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

@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.javapost

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.javathis

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.javaspa

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
相關文章
相關標籤/搜索