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

劉望舒發表於2017-11-27

相關文章
Android深入四大元件系列
Android系統啟動系列
Android應用程式程式系列
Android深入解析AMS系列

前言

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

1.概述

Activity的啟動過程分為兩種,一種是根Activity的啟動過程,另一種是普通Activity的啟動過程,根Activity指的是應用程式啟動的第一個Activity,因此根Activity的啟動過程一般情況下也可以理解為應用程式的啟動過程。普通Activity指的是除了應用程式啟動的第一個Activity之外的其他的Activity。這裡介紹的是根Activity的啟動過程,它和普通Activity的啟動過程是有重疊部分的,只不過根Activity的啟動過程一般情況下指的就是應用程式的啟動過程,更具有指導性意義。想要了解普通Activity的啟動過程的的同學可以參考根Activity的啟動過程去自行閱讀原始碼。

根Activity的啟動過程比較複雜,因此這裡分為三個部分來講,分別是Launcher請求AMS過程、 AMS到ApplicationThread的呼叫過程和ActivityThread啟動Activity,本篇文章會介紹前兩個部分。

2.Launcher請求AMS過程

Launcher啟動後會將已安裝應用程式的快捷圖示顯示到桌面上,這些應用程式的快捷圖示就是啟動根Activity的入口,當我們點選某個應用程式的快捷圖示時就會通過Launcher請求AMS來啟動該應用程式。時序圖如下圖所示。

當我們點選應用程式的快捷圖示時,就會呼叫Launcher的startActivitySafely方法,如下所示。
packages/apps/Launcher3/src/com/android/launcher3/Launcher.java

   public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
        ...
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//1
        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()) {
                startShortcutIntentSafely(intent, optsBundle, item);
            } else if (user == null || user.equals(Process.myUserHandle())) {
                startActivity(intent, optsBundle);//2
            } else {
                LauncherAppsCompat.getInstance(this).startActivityForProfile(
                        intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
            }
            return true;
        } catch (ActivityNotFoundException|SecurityException e) {
            Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
            Log.e(TAG, "Unable to launch. tag=" + item + " intent=" + intent, e);
        }
        return false;
    }複製程式碼

在註釋1處設定Flag為Intent.FLAG_ACTIVITY_NEW_TASK①,這樣根Activity會在新的任務棧中啟動。在註釋2處會呼叫startActivity方法,這個startActivity方法的實現在Activity中,如下所示。
frameworks/base/core/java/android/app/Activity.java

  @Override
    public void startActivity(Intent intent, @Nullable Bundle options) {
        if (options != null) {
            startActivityForResult(intent, -1, options);
        } else {
            startActivityForResult(intent, -1);
        }
    }複製程式碼

startActivity方法中會呼叫startActivityForResult方法,它的第二個引數為-1,表示Launcher不需要知道Activity啟動的結果,startActivityForResult方法的程式碼如下所示。
frameworks/base/core/java/android/app/Activity.java

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

註釋1處的mParent是Activity型別的,表示當前Activity的父類。因為目前根Activity還沒有建立出來,因此,mParent == null成立。接著呼叫Instrumentation的execStartActivity方法,Instrumentation主要用來監控應用程式和系統的互動,execStartActivity方法的程式碼如下所示。
frameworks/base/core/java/android/app/Instrumentation.java

  public ActivityResult execStartActivity(
            Context who, IBinder contextThread, IBinder token, Activity 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()),
                        token, target != null ? target.mEmbeddedID : null,
                        requestCode, 0, null, options);
            checkStartActivityResult(result, intent);
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
        return null;
    }複製程式碼

首先會呼叫ActivityManager的getService方法來獲取AMS的代理物件,接著呼叫它的startActivity方法。這裡與Android 7.0程式碼的邏輯有些不同,Android 7.0是通過ActivityManagerNative的getDefault來獲取AMS的代理物件,現在這個邏輯封裝到了ActivityManager中而不是ActivityManagerNative中。首先我們先來檢視ActivityManager的getService方法做了什麼:

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

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

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

getService方法呼叫了IActivityManagerSingleton的get方法,我們接著往下看,IActivityManagerSingleton 是一個Singleton類。
註釋1處得到名為”activity”的Service引用,也就是IBinder型別的AMS的引用。接著在註釋2處將它轉換成IActivityManager型別的物件,這段程式碼採用的是AIDL,IActivityManager.java類是由AIDL工具在編譯時自動生成的,IActivityManager.aidl的檔案路徑為:frameworks/base/core/java/android/app/IActivityManager.aidl 。要實現程式間通訊,服務端也就是AMS只需要繼承IActivityManager.Stub類並實現相應的方法就可以了。
注意Android 8.0 之前並沒有採用AIDL,而是採用了類似AIDL的形式,用AMS的代理物件ActivityManagerProxy來與AMS進行程式間通訊,Android 8.0 去除了ActivityManagerNative的內部類ActivityManagerProxy,代替它的則是IActivityManager,它是AMS在本地的代理。不理解AIDL可以檢視Android IPC機制(三)在Android Studio中使用AIDL實現跨程式方法呼叫這篇文章。
回到Instrumentation類的execStartActivity方法中,從上面得知execStartActivity方法最終呼叫的是AMS的startActivity方法。

3.AMS到ApplicationThread的呼叫過程

Launcher請求AMS後,程式碼邏輯已經走到了AMS中,接著是AMS到ApplicationThread的呼叫流程,時序圖如圖4-2所示。

AMS的startActivity方法如下所示。
frameworks/base/services/core/java/com/android/server/am/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());
    }複製程式碼

AMS的startActivity方法中return了startActivityAsUser方法,可以發現startActivityAsUser方法比startActivity方法多了一個引數UserHandle.getCallingUserId(),這個方法會獲得呼叫者的UserId,AMS會根據這個UserId來確定呼叫者的許可權。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

    @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) {
        //判斷呼叫者程式是否被隔離    
        enforceNotIsolatedCaller("startActivity");//1
        //檢查呼叫者許可權
        userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
                userId, false, ALLOW_FULL_ONLY, "startActivity", null);//2
        return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
                resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
                profilerInfo, null, null, bOptions, false, userId, null, null,
                "startActivityAsUser");
    }複製程式碼

註釋1處判斷呼叫者程式是否被隔離,如果被隔離則丟擲SecurityException異常,註釋2處用於檢查呼叫者是否有許可權,如果沒有許可權也會丟擲SecurityException異常。最後呼叫了ActivityStarter的startActivityLocked方法,startActivityLocked方法的引數要比startActivityAsUser多幾個,需要注意的是倒數第二個引數型別為TaskRecord,代表啟動的Activity所在的棧。最後一個引數"startActivityAsUser"代表啟動的理由。 程式碼如下所示。

frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java

final int startActivityMayWait(IApplicationThread caller, int callingUid,
            String callingPackage, Intent intent, String resolvedType,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            IBinder resultTo, String resultWho, int requestCode, int startFlags,
            ProfilerInfo profilerInfo, WaitResult outResult,
            Configuration globalConfig, Bundle bOptions, boolean ignoreTargetSecurity, int userId,
            IActivityContainer iContainer, TaskRecord inTask, String reason) {
         ...
        int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,
                    aInfo, rInfo, voiceSession, voiceInteractor,
                    resultTo, resultWho, requestCode, callingPid,
                    callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
                    options, ignoreTargetSecurity, componentSpecified, outRecord, container,
                    inTask, reason);
         ...
         return res;
     }
 }複製程式碼

ActivityStarter是Android 7.0新加入的類,它是載入Activity的控制類,會收集所有的邏輯來決定如何將Intent和Flags轉換為Activity,並將Activity和Task以及Stack相關聯。ActivityStarter的startActivityMayWait方法呼叫了startActivityLocked方法,如下所示。
frameworks/base/services/core/java/com/android/server/am/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)) {//1
            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);
        if (outActivity != null) {
            outActivity[0] = mLastStartActivityRecord[0];
        }
        return mLastStartActivityResult;
    }複製程式碼

註釋1處判斷啟動的理由不為空,如果為空則丟擲IllegalArgumentException異常。緊接著又呼叫了startActivity方法,如下所示。
frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java

  private int startActivity(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) {
        int err = ActivityManager.START_SUCCESS;
        final Bundle verificationBundle
                = options != null ? options.popAppVerificationBundle() : null;
        ProcessRecord callerApp = null;
        if (caller != null) {//1
            //獲取Launcher程式
            callerApp = mService.getRecordForAppLocked(caller);//2
            if (callerApp != null) {
              //獲取Launcher程式的pid和uid並賦值
                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;
            }
        }
        ...
        //建立即將要啟動的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); //2  
        if (outActivity != null) {
            outActivity[0] = r;//3
        }
        ...
            doPendingActivityLaunchesLocked(false);
            return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
                options, inTask, outActivity);//4
    }複製程式碼

ActivityStarter的startActivity方法邏輯比較多,這裡列出部分我們需要關心的程式碼。註釋1處判斷IApplicationThread型別的caller是否為null,這個caller是方法呼叫一路傳過來的,指向的是Launche程式的ApplicationThread物件,在註釋2處呼叫AMS的getRecordForAppLocked方法得到的是代表Launcher程式的callerApp物件,它是ProcessRecord型別的,ProcessRecord用於描述一個應用程式程式。同樣的,ActivityRecord用於描述一個Activity,用來記錄一個Activity的所有資訊。在註釋2處建立ActivityRecord,這個ActivityRecord用於描述即將要啟動的Activity,並在註釋3處將建立的ActivityRecord賦值給ActivityRecord[]型別的outActivity,這個outActivity會作為註釋4處的startActivity方法的引數傳遞下去。
frameworks/base/services/core/java/com/android/server/am/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();
            result = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor,
                    startFlags, doResume, options, inTask, outActivity);
        }
        ...
        return result;
    }複製程式碼

startActivity方法緊接著呼叫了startActivityUnchecked方法:
frameworks/base/services/core/java/com/android/server/am/ActivityStarter.java

  private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
            ActivityRecord[] outActivity) {
...
 if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
                && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {//1
            newTask = true;
            //建立新的TaskRecord
            result = setTaskFromReuseOrCreateNewTask(
                    taskToAffiliate, preferredLaunchStackId, topStack);//2
        } 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");
                }
                mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
                        mOptions);//3
            }
        } else {
            mTargetStack.addRecentActivityLocked(mStartActivity);
        }
        ...

}複製程式碼

startActivityUnchecked方法主要處理棧管理相關的邏輯。在標註①處我們得知,啟動根Activity時會將Intent的Flag設定為FLAG_ACTIVITY_NEW_TASK,這樣註釋1處的條件判斷就會滿足,接著執行註釋2處的setTaskFromReuseOrCreateNewTask方法,其內部會建立一個新的TaskRecord,TaskRecord用來描述一個Activity任務棧,也就是說setTaskFromReuseOrCreateNewTask方法內部會建立一個新的Activity任務棧。Activity任務棧其實是一個假想的模型,並不真實的存在,關於Activity任務棧可以閱讀Android解析ActivityManagerService(二)ActivityTask和Activity棧管理這篇文章。在註釋3處會呼叫ActivityStackSupervisor的resumeFocusedStackTopActivityLocked方法,如下所示。
frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

boolean resumeFocusedStackTopActivityLocked(
        ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
    if (targetStack != null && isFocusedStack(targetStack)) {
        return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
    }
    //獲取要啟動的Activity所在棧的棧頂的不是處於停止狀態的ActivityRecord
    final ActivityRecord r = mFocusedStack.topRunningActivityLocked();//1
    if (r == null || r.state != RESUMED) {//2
        mFocusedStack.resumeTopActivityUncheckedLocked(null, null);//3
    } else if (r.state == RESUMED) {
        mFocusedStack.executeAppTransition(targetOptions);
    }
    return false;
}複製程式碼

註釋1處呼叫ActivityStack的topRunningActivityLocked方法獲取要啟動的Activity所在棧的棧頂的不是處於停止狀態的ActivityRecord。註釋2處如果ActivityRecord不為null,或者要啟動的Activity的狀態不是RESUMED狀態,就會呼叫註釋3處的ActivityStack的resumeTopActivityUncheckedLocked方法,對於即將要啟動的Activity,註釋2的條件判斷是肯定滿足,因此我們來檢視ActivityStack的resumeTopActivityUncheckedLocked方法,如下所示。
frameworks/base/services/core/java/com/android/server/am/ActivityStack.java

  boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
        if (mStackSupervisor.inResumeTopActivity) {
            return false;
        }
        boolean result = false;
        try {
            mStackSupervisor.inResumeTopActivity = true;
            result = resumeTopActivityInnerLocked(prev, options);//1
        } finally {
            mStackSupervisor.inResumeTopActivity = false;
        }
        mStackSupervisor.checkReadyForSleepLocked();
        return result;
    }複製程式碼

緊接著檢視註釋1處ActivityStack的resumeTopActivityInnerLocked方法:
frameworks/base/services/core/java/com/android/server/am/ActivityStack.java

private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
      ...
           mStackSupervisor.startSpecificActivityLocked(next, true, true);
       }
        if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
       return true;
}複製程式碼

resumeTopActivityInnerLocked方法程式碼非常多,我們只需要關注呼叫了ActivityStackSupervisor的startSpecificActivityLocked方法,程式碼如下所示。
frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

 void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
        //獲取即將要啟動的Activity的所在的應用程式程式
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);//1
        r.getStack().setLaunchTime(r);

        if (app != null && app.thread != null) {//2
            try {
                if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
                        || !"android".equals(r.info.packageName)) {
                    app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,
                            mService.mProcessStats);
                }
                realStartActivityLocked(r, app, andResume, checkConfig);//3
                return;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when starting activity "
                        + r.intent.getComponent().flattenToShortString(), e);
            }
        }
        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
    }複製程式碼

註釋1處獲取即將要啟動的Activity的所在的應用程式程式,註釋2處判斷要啟動的Activity的所在應用程式程式已經執行的話,就會呼叫註釋3處的realStartActivityLocked方法,需要注意的是,這個方法的第二個引數是代表要啟動的Activity的所在的應用程式程式的ProcessRecord。
frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

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, new Configuration(mService.mConfiguration),
                  new Configuration(task.mOverrideConfig), 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。app指的是傳入的要啟動的Activity的所在的應用程式程式,因此,註釋1處的程式碼指的就是要在目標應用程式程式啟動Activity。當前程式碼邏輯執行在AMS所在的程式(SyetemServer程式),通過ApplicationThread來與應用程式程式進行Binder通訊,換句話說,ApplicationThread是AMS所在程式(SyetemServer程式)和應用程式程式的通訊橋樑,如下圖所示。

結語

本文我們學習了根Activity的啟動過程的前兩個部分,分別是Launcher請求AMS過程、 AMS到ApplicationThread的呼叫過程,完成第二個部分後程式碼邏輯就執行在了應用程式程式中,後篇會接著介紹ActivityThread啟動Activity的過程以及根Activity啟動過程中涉及的程式。

相關文章