天天看點

Android應用程式啟動(根Activity)過程

感謝:

《Android進階解密 - 第四章》

今天開始學習四大元件的啟動工作。從Activity開始。之前有寫過,但是那是基于Andorid7.0的源碼,7.0和8.0的最大的差別就是7.0沒有使用AIDL,其通信類用 ActivityManagerNative,而8.0用了AIDL後,将AMN封裝了起來。

Activity的啟動分為兩種:

  1. 根Activity的啟動

    按下桌面的程式快捷圖示,啟動應用程式的第一個Activity的過程,是以根Activity的啟動過程也可以了解為應用程式的啟動過程。

  2. 普通Activity的啟動

    程式内從一個Activity打開另外一個Activity的過程的啟動。

一般情況下我們說的Activity的啟動就是指第一種:根Activity的啟動。是以我們就來分析根Activity的啟動流程。

根Activity啟動的過程很複雜,總體可以分為三個部分:

  1. Launcher請求AMS的過程
  2. AMS到ApplicationThread的調用過程
  3. ActivityThread啟動Activity

注意,該篇學習之前,要弄懂的知識:

  1. 系統的啟動流程

    按下電源鍵後,一個Android系統是怎麼啟動的。

    主要涉及到Init程序、Zygote、SystemServer、Launcher的知識概念

  2. 應用程式程序的啟動過程

    一個應用程式所在程序是怎麼建立出來的。就是 Zygote的Socket啟動一個死循環來等待AMS發來啟動一個應用程式程序的請求

    主要涉及到ActivityManagerService(即AMS)、建立Binder線程池、建立消息循環的概念

網上有很多介紹上面東西的資料,最好跟着重點的源碼過一遍,不然下面的内容也不知道在說什麼。

下面的源碼基于 Android8.0

1.Lanuncher請求AMS的過程

我們知道Launcher是Android系統的第一個應用程式,它會讀取 ​

​PakgesManagerService​

​​來擷取目前系統裝了哪些應用,并把這些應用程式的快捷圖示展示在桌面上。

我們通過點選應用的快捷圖示,就會通過Launcher請求AMS來啟動該應用。我們來看看第一個大步驟的時序圖:

Android應用程式啟動(根Activity)過程

閱讀源碼的正确方式就是先看一遍時序圖,再讀一遍重點源碼,再回來看一遍時序圖。

在我們點選應用程式的快捷圖示時,就會調用Launcher的 ​

​startActivitySafely()​

​,我們來看看這個方法的代碼:

// launcher3/Launcher.java
public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
        ...
        // 1
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        if (v != null) {
            intent.setSourceBounds(getViewBounds(v));
        }
        try {
            if (Utilities.ATLEAST_MARSHMALLOW
                    && (item instanceof ShortcutInfo)
                    && (item.itemType == Favorites.ITEM_TYPE_SHORTCUT
                     || item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT)
                    && !((ShortcutInfo) item).isPromise()) {
                // Shortcuts need some special checks due to legacy reasons.
                startShortcutIntentSafely(intent, optsBundle, item);
            } else if (user == null || user.equals(Process.myUserHandle())) {
                // 2
                startActivity(intent, optsBundle);
            } 
            ...
        } catch (ActivityNotFoundException|SecurityException e) {
          ...
        }
        return false;
    }      

注釋1:建立一個intent後把intent的Flag置為 ​

​FLAG_ACTIVITY_NEW_TASK​

​​,這個flag表示這個Activity會在新的任務棧中啟動(像singleTask模式那樣)。

一般來說,往下走,代碼一般都會走到注釋2的分支去。

注釋2:傳入intent,執行​​

​startAcivity()​

​​。這個方法在​

​Activity.java​

​類中實作,我們來看看其代碼:

// Activity.java
    @Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
        if (options != null) {
            startActivityForResult(intent, -1, options);
        } else {
            startActivityForResult(intent, -1);
        }
    }      

都是走到 ​

​startActivityForResult()​

​​中去,其中第一個參數為在Launcher中建立的Intent,第二個參數-1表示Launcher不需要知道Activity啟動的結果。也就是說Lancher隻管發請求,之後怎麼樣就再也不處理了。我們來看看 ​

​startActivityForResult()​

​的代碼:

// Acitvity.java
 public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
            @Nullable Bundle options) {
        // 1
        if (mParent == null) { 
            options = transferSpringboardActivityOptions(options);
            Instrumentation.ActivityResult ar =
                mInstrumentation.execStartActivity(
                    this, mMainThread.getApplicationThread(), mToken, this,
                    intent, requestCode, options);
             ...
        } else {
           ...
        }
    }      

注釋1:如果mParent==null 則往下走​

​execStartActivity()​

​​ mParent是目前Activity的父類,因為根Activity還沒有建立出來,是以mParent就是null。

接着調用 ​

​Instrumentation​

​類的 ​

​execStartActivity()​

​,傳入參數:this(上下文)、但前應用主線程、token、this(上下文)、Launcher來的intent、requstCode(-1,表示無需知道後面的結果)、攜帶參數bundle。

接着我們來看看 ​

​Instrumentation​

​這個類的啟動Activity的方法:

public ActivityResult execStartActivity(
        Context who, IBinder contextThread, IBinder token, String target,
        Intent intent, int requestCode, Bundle options) {
        ...
        try {
            intent.migrateExtraStreamToClipData();
            intent.prepareToLeaveProcess(who);
            int result = ActivityManager.getService()
                .startActivity(whoThread, who.getBasePackageName(), intent,
                        intent.resolveTypeIfNeeded(who.getContentResolver()), //1
                        token, target, requestCode, 0, null, options);  
            checkStartActivityResult(result, intent);         //2
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
        return null;
    }      

在 ​

​try{}​

​​中,先修改一下intent的内容。

其次在注釋1中:調用 ​​

​ActivityManager.getService().startActivity()​

​​一套組合拳。

這條代碼先從 ​​

​ActivityManager.getService()​

​​擷取AMS在Client端的代理對象。也就是說,它會傳回個可以看做是 ​

​AMS​

​​的對象。

然後調用其 ​​

​startActivity()​

​​,也就是調用 ​

​ASM.startActivity()​

​。

我們先不進入到AMS的startActivity去,而是看看這個 AMS是怎麼來的。

在Android8.0之前,是通過 ​

​ActivityManagerNative.getDefaul()​

​​來擷取AMS的代理對象的,現在這個邏輯放到了 ​

​ActivityManager​

​​中而不是 ​

​ActivityManagerNative​

​中,在我之前做的筆記《Android藝術探索》這本書裡面,用的是7.0的代碼,可以看下面:

Android應用程式啟動(根Activity)過程

我們來看看getServcie的代碼:

// AcitvityManager.java
public static IActivityManager getService() {
      return IActivityManagerSingleton.get();
}      

這個方法傳回一個​

​IActivityManager​

​​的對選哪個,有了解AIDL或代理模式的應該就能立馬知道 ​

​IActivityManager​

​是​

​ActivityManagerService​

​在用戶端的代理類!

我們來看看 ​​

​IActivityManagerSingleton​

​​的​

​get()​

​:

// ActivityManager.java
  private static final Singleton<IActivityManager> IActivityManagerSingleton =
            new Singleton<IActivityManager>() {
                @Override
                protected IActivityManager create() {
                    //1
                    final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                    //2
                    final IActivityManager am = IActivityManager.Stub.asInterface(b);
                    return am;
                }
            };      

注釋1:從 ServiceManager得到一個IBinder,也就是 “IBinder類型的AMS”

注釋2:将IBinder通過 ​​

​asInterface()​

​​轉換成一個 IActivityManager對象,通過​

​get()​

​可以得到這個對象。

上面是 ​

​AIDL​

​的做法,用 程序間通信完成的從 用戶端層到 服務端層的實作。8.0之前并不是AIDL的做法。至于AIDL的用法、原理網上已經有n多的blog去學習了。這裡不再贅述。

至此,第一階段結束,​

​execStartActivity​

​​方法最終會調用到 ​

​ActivityManagerService.startActivity()​

​​。

這部分其實特别好了解。

2.AMS到ApplicationThread的調用過程

Android應用程式啟動(根Activity)過程

可以看到,從AMS到ApplicaitonThread的過程就有些複雜了,圖中會經過 ​

​ActivityStarter​

​​、​

​ActivityStackSupervisor​

​​、​

​ActivityStack​

​這樣的類。

我們先來看看最初始的 ActivityMangerService的startAcitivty方法:

// ActivityManagerService.java
    @Override
    public final int startActivity(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {
        return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,
                resultWho, requestCode, startFlags, profilerInfo, bOptions,
                UserHandle.getCallingUserId());
    }      

調用自己的 ​

​startActivityAsUser()​

​​,可以看到在參數的對比上,後者多了一個 ​

​getCallingUserId()​

​,顧名思義,這個方法可以擷取到調用者的UserId,AMS就是根據這個UserId來确定調用者的權限的:

@Override
    public final int startActivityAsUser(IApplicationThread caller, String callingPackage,
            Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,
            int startFlags, ProfilerInfo profilerInfo, Bundle bOptions, int userId) {
        //1
        enforceNotIsolatedCaller("startActivity");
        //2
        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
                userId, false, ALLOW_FULL_ONLY, "startActivity", null);
        //3
        return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                profilerInfo, null, null, bOptions, false, userId, null, null,
                "startActivityAsUser");
    }      

每行代碼都很重要:

注釋1:判斷調用者程序是否被隔離(是否可用),如果被隔離則抛出異常。

注釋2:檢查調用者是否有權限,是根據傳進來的 userId進行判斷的。如果沒有權限也會抛出異常

注釋3:調用 ​​

​ActivityStarter.startActivityMayWait()​

​​。

這裡需要注意的是倒數第二個參數 TaskRecord,代表啟動Activity所在的棧,最後一個參數reason,代表啟動Activity的理由,我們來看看以下 ​​

​startActivityMayWait()​

​:

// ActivityStarter.java
 final int startActivityMayWait(IApplicationThread caller, int callingUid,
            String callingPackage, Intent intent, ... int userId,
            IActivityContainer iContainer, TaskRecord inTask, String reason) {
            ...
            int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,
                    aInfo, rInfo, voiceSession, voiceInteractor..., container,
                    inTask, reason);
                    ...
            return res;
        }
    }      

​ActivityStarter​

​ 是Android7.0中新加入的類,它是加載Activity的控制類。

這個類的作用是根據傳入的資料來吧Intent轉換成Activity的。在這個方法裡面,調用到了 ​​

​startActivityLocked()​

​,這個方法是通向後面啟動Activity的方法,我們來看一下其源碼:

// ActivityStarter.java
int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
            String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
            String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
            ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
            ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,
            TaskRecord inTask, String reason) {

        if (TextUtils.isEmpty(reason)) {
            throw new IllegalArgumentException("Need to specify a reason.");
        }
        mLastStartReason = reason;
        mLastStartActivityTimeMs = System.currentTimeMillis();
        mLastStartActivityRecord[0] = null;

        mLastStartActivityResult = startActivity(caller, intent, ephemeralIntent, resolvedType,
                aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
                callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
                options, ignoreTargetSecurity, componentSpecified, mLastStartActivityRecord,
                container, inTask);
                ...
        return mLastStartActivityResult;
    }      

這個方法就是處理了一下為什麼要建立Activity的Reason這個String。然後調用了 ​

​startActivity()​

​,我們往下看:

private int startActivity(IApplicationThread caller...) {
        int err = ActivityManager.START_SUCCESS;
        final Bundle verificationBundle
                = options != null ? options.popAppVerificationBundle() : null;
        ProcessRecord callerApp = null;
        //1
         if (caller != null) {
            //2
            callerApp = mService.getRecordForAppLocked(caller);
            if (callerApp != null) {
                callingPid = callerApp.pid;
                callingUid = callerApp.info.uid;
            } else {
                Slog.w(TAG, "Unable to find app for caller " + caller
                        + " (pid=" + callingPid + ") when starting: "
                        + intent.toString());
                err = ActivityManager.START_PERMISSION_DENIED;
            }
        }
        ...
        //3 這裡建立即将要啟動的Activity的描述類ActivityRecord。
        ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
                callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
                resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
                mSupervisor, container, options, sourceRecord);
        if (outActivity != null) {
            outActivity[0] = r;
        }
        ...
        //4   
        return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
                options, inTask, outActivity);
}      

注釋1:判斷IApplicationThread類型的caller是否為null,這個caller是方法調用一路傳過來的,指向 Launcher所在應用程式程序的 ​

​ApplicationThread​

​​對象。

注釋2:調用AMS的 ​​

​getRecordForAppLocked()​

​​方得到一個 代表Launcher程序的 ​

​ProcessRecord​

​​類的執行個體callerApp。​

​ProcessRecord​

​​用來描述一個應用程式程序。

注釋3:同樣的 ​​

​ActivityRecord​

​​用來描述一個 Activity的所有資訊。建立一個新的賦給r,然後r作為 outActivity第一個資料。

outActivity是 ​​

​ActivityRecord[]​

​​類型的資料。

注釋4:把這個方法裡面得出的所有參數,傳到重載方法 ​​

​startActivity()​

​中:

// ActivityStarter.java
   private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
            ActivityRecord[] outActivity) {
        int result = START_CANCELED;
        try {
            mService.mWindowManager.deferSurfaceLayout();
            //調用startActivityUnchecked
            result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
                    startFlags, doResume, options, inTask, outActivity);
        } 
        ...
        return result;
    }      

這裡傳回 ​

​startActivityUnchecked()​

​這個函數:

// ActivityStarter
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
            ActivityRecord[] outActivity) {
        ...    
        //1
        if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
                && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
            newTask = true;
            //2 建立新的TaskRecord
            result = setTaskFromReuseOrCreateNewTask(
                    taskToAffiliate, preferredLaunchStackId, topStack);
        } else if (mSourceRecord != null) {
            result = setTaskFromSourceRecord();
        } else if (mInTask != null) {
            result = setTaskFromInTask();
        } else {
            setTaskToCurrentTopOrCreateNewTask();
        }
        ...
        if (mDoResume) {
            final ActivityRecord topTaskActivity =
                    mStartActivity.getTask().topRunningActivityLocked();
            if (!mTargetStack.isFocusable()
                    || (topTaskActivity != null && topTaskActivity.mTaskOverlay
                    && mStartActivity != topTaskActivity)) {
                ...
            } else {
                if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) {
                    mTargetStack.moveToFront("startActivityUnchecked");
                }
                //3
                mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                        mOptions);
            }
        }
        ...      

​startActivityUnchecked()​

​​ 它的作用主要是處理與 棧管理相關的邏輯。是以這個方法就是我們新的Activity所處的棧的管理方法了。

注釋1:由于我們傳入進來的Intent的FLAG是有 ​​

​FLAG_ACTIVITY_NEW_TASK​

​​這個屬性的,是以能通過if

注釋2:通過 ​​

​setTaskFromReuseOrCreateNewTask​

​​,它會建立出一個 ​

​TaskRecord​

​,前面說過,它用來描述一個任務棧,也是Activity最直覺的表現類,之是以這麼說,是因為任務棧是一個假象的模型,他實際并不存在,是以這個方法相當于建立了一個任務棧出來。

注釋3:調用​​

​ActivityStackSupervisor.resumeFocusedStackTopActivityLocked()​

​​,這個方法從ActivityStarter深入到了​

​ActivityStackSupervisor​

​​,是往下走的一個方法。

我們來看看這個方法:

// ActivityStackSupervisor
boolean resumeFocusedStackTopActivityLocked(
            ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
        if (targetStack != null && isFocusedStack(targetStack)) {
            return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
        }
        //1
        final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
        //2
        if (r == null || r.state != RESUMED) {
            //3
            mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
        } else if (r.state == RESUMED) {
            mFocusedStack.executeAppTransition(targetOptions);
        }
        return false;
    }      

注釋1:調用​

​ActivityStack.topRunningActivityLocked()​

​​擷取要啟動的Activity所在棧的棧頂的不是處于停止狀态的ActivityRecord

注釋2:判斷這個 ActivityRecord 是否為空或者要啟動的Activity是不是 RESUMED狀态,由于我們是建立根Activity,是以這個 r 是空的。是以它會調用注釋3的代碼

注釋3:調用 ​​

​ActivityStack.resumeTopActivityUncheckedLocked​

​,這個方法名雖然長,但是我們可以知道它大概的意思就是 啟動一個棧頂Activity。我們來看看這個方法:

// ActivityStack
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
        ...
        boolean result = false;
        try {
            mStackSupervisor.inResumeTopActivity = true;
            //1
            result = resumeTopActivityInnerLocked(prev, options);
        } finally {
            mStackSupervisor.inResumeTopActivity = false;
        }
        mStackSupervisor.checkReadyForSleepLocked();
        return result;
    }      

注釋1:上面的代碼在 try-catch裡面,調用了 ​

​resumeTopActivityInnerLocked()​

​​去置result。

我們來看看這個方法:

// ActivityStack
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
     ...
         mStackSupervisor.startSpecificActivityLocked(next, true, true);
     }
     ..
}      

因為這個方法代碼非常多,是以我們來看它調用比較關鍵的代碼就可以了,即調用了 ​

​ActivitySupervisor.startSpecificActivityLocked​

​ 回到了 ActivitySupervisor中,我們來看看這段代碼:

// ActivitySupervisor
 void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
        // 1
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);
        r.getStack().setLaunchTime(r);
        if (app != null && app.thread != null) {
            try {
                ... 
                //2
                realStartActivityLocked(r, app, andResume, checkConfig);
                return;
            } 
            ...
        }

        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
    }      

注釋1:擷取即将啟動的Activity所在應用程式的程序。開篇說過需要知道應用程式程序是怎麼啟動的。因為一個應用程式要啟動,最先要做的就是把這個應用程式的程序給啟動。 ​

​ProcessRecord​

​​就是描述一個應用程序的類。它由 AMS來管理。

注釋2:由于程序已經啟動了是以不為null,就會調用 ​​

​realStartActivityLocked()​

​。

// ActivityStackSupervisor
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
            boolean andResume, boolean checkConfig) throws RemoteException {
            ...
            app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
                    System.identityHashCode(r), r.info,
                    mergedConfiguration.getGlobalConfiguration(),
                    mergedConfiguration.getOverrideConfiguration(), r.compat,
                    r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
                    r.persistentState, results, newIntents, !andResume,
                    mService.isNextTransitionForward(), profilerInfo);
            ...
            return true; 
}      

這個方法也非常的長,比較關鍵的就是這句.

​​

​app.thread​

​​ 指的是 ​

​IApplicationThread​

​​,它的實作是​

​ActivityThread​

​​的内部類 ​

​ApplicationThread​

​​,其中ApplicationThread繼承了 IApplicationThread.Stub。也就是這裡又使用了一次AIDL。

app是ProcessRecord,即應用程式所在的程序。

是以這段代碼就是要在 目标應用程式程序啟動Activity。

目前代碼邏輯運作在 AMS所在的程序(即Server端/SystemServer程序)中,通過ApplicationThread來與應用程式程序進行Binder通信,換句話說,ApplicationThread是AMS和應用程式程序間的橋梁。他們的關系如下:

Android應用程式啟動(根Activity)過程

到這裡,代碼從AMS到了應用程式所在的程序中了。這也到了我們啟動流程最後的一部分。

3. ActivityThread啟動Activity的過程

我們先來看看ActivityThread啟動Activity的時序圖:

Android應用程式啟動(根Activity)過程

我們先從入口 ​

​ApplicationThread.scheduleLaunchActivity()​

​,其中 ApplicaitonThread是ActivityThread的内部類。

在應用程式程序的建立中,程序建立後會運作這個程序的主線程Thread執行個體,即 ActivityThread,它管理目前應用程式的主線程。

// 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;
            ...
            updatePendingConfiguration(curConfig);
            sendMessage(H.LAUNCH_ACTIVITY, r);
        }      

這個方法把要啟動的 Activity封裝成一個 ​

​ActivityClientRecord​

​​,然後通過 ​

​sendMessage()​

​​向H類發送類型為 ​

​H.LAUNCH_ACTIVITY​

​的消息,這個封裝好的對象給帶上。來看看我們非常熟悉的sendMessage()吧:

// AcitivtyThread
final H mH = new H();

private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
        ...
        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​

​ 的執行個體,在應用程式程序的啟動中,這個 H 是随着程序的啟動而建立,它是 ActivityThread的内部類,并且繼承自Handler,是應用程式程序中主線程的消息管理類。

為什麼明明都到了應用程式的程序中了,還要在這個時候使用到Handler呢?是因為 ​

​ApplicationThread​

​​作為一個橋梁Binder,它的邏輯是運作在Binder線程池中的,因為接下來的流程要切到主線程中,是以就要通過Handler來實作一個線程的切換。

我們來看看 ​​

​H​

​類的實作:

//ActivityThread
        private class H extends Handler {
           //1
           public static final int LAUNCH_ACTIVITY         = 100;
           ...
           public void handleMessage(Message msg) {
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                    //2
                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
                    //3
                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo);
                    //4
                    handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;
            ...
          }      

首先 H 繼承了Handler,它實作了 ​

​sendMessage()​

​​ 、 ​

​handleMessage()​

​​等方法

注釋1:定義了 ​​

​LAUNCH_ACTIVITY​

​​ 消息字段,然後在 ​

​handleMessage()​

​​中處理。代碼走下來就一定會走到這個case中

注釋2:從消息message中拿出裡面 ​​

​ActivityClientRecord​

​​,即封裝好的 Activity資訊。

注釋3:通過 ​​

​getPackageInfoNoCheck()​

​​來獲得 ​

​LoadedApk​

​​ 類型的對象,并指派給 ​

​ActivityClientRecord​

​​的 ​

​packageInfo​

​​ 屬性。

應用程式程序要啟動Activity時需要将Activity所屬的APK加載進來,而 LoadedApk 就是用來描述已加載的 APK檔案的。

注釋3:調用 ​​

​handleLaunchActivity()​

​,我們來看看其代碼:

// ActivityThread.java
 private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
        ...
        WindowManagerGlobal.initialize();
        //1 
        Activity a = performLaunchActivity(r, customIntent);

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

            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,如果成功啟動則會傳回一個Activity執行個體。

注釋2:​​

​handleResumeActivity()​

​​用來将 Activity的狀态設定成 Resume。

如果該Activity為null,通知AMS終止行動。下面來看看 ​​

​performLaunchActivity()​

// ActivityThread
   private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ...
        //1 擷取 Actiivty的 ActivityInfo類
        ActivityInfo aInfo = r.activityInfo;
        if (r.packageInfo == null) {
            //2 擷取APK檔案描述類 LoadedApk
            r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                    Context.CONTEXT_INCLUDE_CODE);
        }
        //3
        ComponentName component = r.intent.getComponent();
        ....
        //4
        ContextImpl appContext = createBaseContextForActivity(r);
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.getClassLoader();
            //5
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            ...
        } catch (Exception e) {
            ...
        }
        try {
            //6
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);
            ...
            if (activity != null) {
                //7
                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()) {
                    //8
                    mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
                } 
                ...
    }      

這個方法做的事情有點多,它的目标是通給給定的一個 Activity描述類 -> Activity執行個體,我們來分析每個注釋

注釋1:擷取ActivityInfo,它用于存儲代碼以及 AndroidManifest設定的該Acitivty和Receiver等節點資訊,比如我們熟知的 launchMode

注釋2:擷取LoadedApk,前面也做過,這裡如果沒有就再做一次

注釋3:擷取要啟動Activity的 ​​

​ComponentName​

​​類,這個類儲存了 Activity的包名和類名

注釋4:建立要啟動Activity的上下文環境​​

​ContextImpl​

​​ 注釋5:根據ComponentName中存儲的Activity類名,用 類加載器來建立該Activity的執行個體。

注釋6:建立Application,​

​makeApplication()​

​内部會調用Application的 ​

​onCreate()​

​​

注釋7:調用Activity的 ​

​attach()​

​,這個方法用來初始化一個 Activity。在 ​

​attach()​

​ 中會建立 Window(​

​PhoneWindow​

​)對象并與 Activity自身進行關聯。

注釋8:調用 ​

​Instrumentation.callActivityOnCreate()​

​ 我們來看看這個方法:

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

注釋1調用了​

​performCreate()​

​,我們來看下這個方法:

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

這段代碼中,調用了 ​

​Activity.onCreate()​

​​。這個方法就是我們寫的Acitivty的 super.onCreate 方法了。

至此,Activity啟動的流程就結束了。這個方法走完後,就會通過一開始ActivityThread的 ​​

​handleResumeActivity()​

​走Activity的 onResume了。

4. Activity啟動流程總結

應用程式啟動流程的代碼量極大。涉及到的類也很多。這裡我們需要整個流程歸納一下。也就是和上面一樣,根據程序的角度把它分成了三個步驟。

應用程式的啟動涉及了四個主要的程序:

  1. Launcher程序

    即桌面。通過點選桌面上應用程式快捷圖示,通知AMS要打開應用程式

  2. AMS所在的 SystemServer程序

    AMS請求Zygote建立應用程式程序

  3. Zygote程序

    接收到AMS的通知後通過​​

    ​fork()​

    ​​自身來建立應用程式程序。

    接着AMS開始建構Activity的資訊并傳給應用程式程序

  4. 應用程式程序

    在主線程​​

    ​ActivityThread​

    ​來建構一個Activity并調用其 onCreate()

下面copy一份皇叔的圖來便于了解:

Android應用程式啟動(根Activity)過程