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

劉望舒發表於2017-12-25

相關文章
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

相關文章