前言
平日開發(fā),Activity.startActivity()算是熟面孔,功能無須贅言。但它又像是最熟悉的陌生人,因為僅僅API,是不知道在啟動一個Activity時,發(fā)生了什么。這也是本文的目的———說清Activity的啟動發(fā)生的事情。
但開篇并不是從Activity.startActivity()。因為更常見的場景是,點擊桌面APP圖標(biāo),啟動了APP。實際上,這是啟動了某一APP的“Launcher Activity”,也稱根Activity啟動。而在同一APP下的其它Activity啟動,稱為子Activity的啟動。
NOTE: 正文處源碼版本8.0,源碼存有差異,但核心不變。
從AMS角度看Activity
在分析Activity的啟動前,先從AMS(ActivityManagerService)的視角看在Activity的存在。AMS是Android最核心的服務(wù)之一,主要作用可以理解為管理四大組件、處理應(yīng)用進程、記錄系統(tǒng)運行時狀態(tài)。Activity作為四大組件之一,自然服從于AMS的管理。在AMS的眼里,并不直接與Activity打交道,而是通過ActivityRecord作為媒介記錄了有關(guān)于Activity運行數(shù)據(jù)與狀態(tài)信息。
僅僅知道ActivityRecord卻不夠,Activity需要運行在某一進程里。而ProcessRecord則記錄了進程的所有信息。通過規(guī)整ActivityRecord和ProcessRecord的信息,AMS就可以知道如何運行一個Activity。
從使用一個APP的過程中,自然地認為使用此APP的所有Activity運行應(yīng)以APP為維度進行關(guān)聯(lián)。在AMS的描述中,和上文的想法是有差異的。AMS更愿意用Task來描述一系列ActivityRecord的聚合關(guān)系。

ActivityRecord顏色代表所在進程。
Task聚合的ActivityRecord所描述的Activity可以來自不同的進程,因此Task可由不同的APP組成來完成一系列的工作。
示例如下
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".FActivity"
android:launchMode="singleInstance"></activity>
<activity android:name=".TActivity" />
<activity
android:name=".SActivity"
android:process=":remote" />
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

圖中從Main -> S -> T -> F的順序啟動了Activity, 通過命令
adb shell dumpsys activity | grep packageName
可以看到當(dāng)前Activity在AMS中的樣子,符合第一張圖。
- Main、S、T屬于TASK #5791,F(xiàn)屬于另一個TASK #5792
- Main、T、F運行于進程30223,S運行于進程30670
根啟動
回到正題。
根啟動最常進的場景是從桌面點擊了一個APP圖標(biāo)啟動到APP的“Launch Activity”,此中,桌面其實是Launcher,并且Launcher也是一個Activity,內(nèi)聚了其它APP的信息,以方便用戶操作。如果手機不使用Launcher的話,那么當(dāng)你啟動手機后,屏幕所呈現(xiàn)的模樣,與終端無異。
既然Launcher為Activity,則遵循Activity生命周期,見Launcher.onCreate()
@Override
protected void onCreate(Bundle savedInstanceState) {
......
if (!mRestoring) {
if (sPausedFromUserAction) {
mModel.startLoader(true, -1);
} else {
// 開始加載app信息,初始狀態(tài)sPausedFromUserAction為false
mModel.startLoader(true, mWorkspace.getCurrentPage());
}
}
......
}
通過mModel即LauncherModel開啟線程任務(wù)LoaderTask向PMS獲取各個APP的啟動信息,信息保存于LauncherModel.mBgAllAppsList。收集的關(guān)鍵信息如在各Manifest定義的App包名、定義為action為MAIN,category為LAUNCHER的Activity的信息、應(yīng)用圖標(biāo)等。關(guān)聯(lián)信息并生成桌面圖標(biāo)。
如果對上述過程感興趣,可查閱
-> Luancher.startLoader()
-> LoaderTask.run()
-> loadAndBindAllApps()
-> loadAllAppsByBatch()
這里點到為止,不做深入。
當(dāng)Launcher準(zhǔn)備各項啟動信息,桌面生成了對應(yīng)的圖標(biāo)后,點擊某一圖標(biāo),開始了一個APP根Activity的啟動。
Launcher
public void onClick(View v) {
......
Object tag = v.getTag();
if (tag instanceof ShortcutInfo) {
......
boolean success = startActivitySafely(v, intent, tag);
......
}
......
}
APP圖標(biāo)點解由Launcher.onClick()接收,之前關(guān)聯(lián)的關(guān)鍵啟動信息存于View tag中,這里取出并用以啟動。鏈路為Launcher.startActivitySafely() -> Launcher.startActivity() -> Activity.startActivity(),此過程中會為啟動所用的Intent設(shè)置FLAG_ACTIVITY_NEW_TASK的標(biāo)識位。不難理解,當(dāng)前AMS中并沒有關(guān)于此APP的相關(guān)TASK,理所應(yīng)當(dāng)為此次啟動新建TASK進行處理。 Launcher本身為Activity,最終以Activity.startActivity()進行啟動。
而以Activity.startActivity()啟動,不管何種形式,最終到達Activity.startActivityForResult(),如下
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
// 根啟動情況下,是沒有mParent的
if (mParent == null) {
......
options = transferSpringboardActivityOptions(options);
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
......
}
// 子Activity啟動
else {
if (options != null) {
mParent.startActivityFromChild(this, intent, requestCode, options);
}
else {
// Note we want to go through this method for compatibility with
// existing applications that may have overridden it.
mParent.startActivityFromChild(this, intent, requestCode);
}
}
}
mInstrumentation為Instrumentation,用來監(jiān)控應(yīng)用程序和系統(tǒng)之間的交互操作。而mMainThread為ActivityThread,可以看作所說的主線程,但實際上ActivityThread并非線程,只是在ActivityThread.Main()時機,將各類在主線程里使用或于主線程交互的組件做了關(guān)聯(lián),比如創(chuàng)建了主線程Looper,與AMS通信的ApplicationThread等等。通過這類組件,能完成許多在主線程里完成的事而使ActivityThread看起來像是主線線程。
當(dāng)系統(tǒng)啟動一個應(yīng)用程序進程時,會向此進程里加載一個ActivityThread,且由該進程啟動的Activity組件的父Activity持有。
Activity.mToken為ActivityRecord.Token,之前說過ActivityRecord負責(zé)維護Activity的運行狀態(tài)信息。在當(dāng)前場景下,有了Launcher所對應(yīng)的ActivityRecord,AMS自然能知道Launcher的詳細信息,以便后續(xù)操作。
回到Instrumentation.execStarActivity()
public ActivityResult execStartActivity(
Context who, IBinder contextThread, IBinder token, Activity target,
Intent intent, int requestCode, Bundle options) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
Uri referrer = target != null ? target.onProvideReferrer() : null;
if (referrer != null) {
intent.putExtra(Intent.EXTRA_REFERRER, referrer);
}
// 先嘗試通過ActivityMonitor攔截啟動Activity的操作,并處理一些自己的事務(wù),主要是測試用
if (mActivityMonitors != null) {
......
}
// 通過AMS啟動Activity
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;
}
Instrumentation將啟動操作交由AMS啟動。獲取操作AMS的借由ActivityManager.getService()通過android.utils.Singleton和ServiceManager獲取到AMS的代理對象IAcitivityManager。此操作涉及IPC。
通過AMS.startActivity()到達ActivityStarter.startActivityMayWait() , 路徑為
AMS.startActivity() -> AMS.startActivityAsUser() -> ActivityStarter.startActivityMayWait()
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) {
// resultTo 是 Activity.mToken , intent含有即將啟動的Activity信息
......
// 以intent為引子,從PMS收集Manifest的信息
ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);
......
// 收集即將啟動的Activity信息
// Collect information about the target of the Intent.
ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
ActivityOptions options = ActivityOptions.fromBundle(bOptions);
ActivityStackSupervisor.ActivityContainer container =
(ActivityStackSupervisor.ActivityContainer)iContainer;
synchronized (mService) {
......
final ActivityStack stack;
if (container == null || container.mStack.isOnHomeDisplay()) {
// 根Activity啟動會來到這里,之前傳來的container為空
stack = mSupervisor.mFocusedStack;
} else {
stack = container.mStack;
}
if (aInfo != null &&
(aInfo.applicationInfo.privateFlags
& ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
// 防止有相同進程已經(jīng)啟動了
if (aInfo.processName.equals(aInfo.applicationInfo.packageName)) {
......
}
// 這個ActivityRecord將用來記錄新啟用的Activity
final ActivityRecord[] outRecord = new ActivityRecord[1];
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);
......
}
首先,以intent為引子,從PMS收集Manifest聲明的信息存于ResolveInfo,ResolveInfo包含了Service、Activity、Provider等信息。有了ResolveInfo之后,也就有了ActivityInfo———關(guān)于將要啟動的Activity的更多信息,包括theme、launchMode、taskAffinity等。
在擁有這些信息之后,還需要檢驗是否已有相同的進程已經(jīng)在運行。也可以看到,進程名與包名一致。當(dāng)前情況下,還沒有相應(yīng)的進程。而outRecord將在后續(xù)作為記錄要啟動的Activity狀態(tài)信息的ActivityRecord。
鏈路 -> ActivityStarter.startActivityLocked() -> ActivityStarter.startActivity()
/** DO NOT call this method directly. Use {@link #startActivityLocked} instead. */
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;
// Pull the optional Ephemeral Installer-only bundle out of the options early.
final Bundle verificationBundle
= options != null ? options.popAppVerificationBundle() : null;
ProcessRecord callerApp = null;
if (caller != null) {
// 拿到caller所在進程的ProcessRecord
callerApp = mService.getRecordForAppLocked(caller);
if (callerApp != null) {
// 拿到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;
}
}
......
ActivityRecord sourceRecord = null; // 來源Activity
ActivityRecord resultRecord = null;
if (resultTo != null) {
// 從 Activity Stack 獲取已經(jīng)存在的sourceRecord, 根啟動對應(yīng)為launcher的 AR
sourceRecord = mSupervisor.isInAnyStackLocked(resultTo);
......
}
......
// 為新啟動的Activity拿到AR
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;
}
......
return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
options, inTask, outActivity);
ProcessRecord用以描述進程,在AMS內(nèi)部mProcessNames保存了已有進程的信息。當(dāng)前場景下,拿到了Launcher所在進程的ProcessRecord并記錄相關(guān)pid與uid,并從Stack中獲取Launcher所對應(yīng)的ActivityRecord。緊接著,為要新開啟的Activity創(chuàng)建ActivityRecord以作為此后對此Activity的管理維護依據(jù)。
鏈路ActivityStarter.startActivity() -> ActivityStarter.startActivityUnchecked()
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
ActivityRecord[] outActivity) {
/**
* 因為借助ActivityStarter來啟動Activity,這里已有必要的數(shù)據(jù),將數(shù)據(jù)關(guān)聯(lián)到ActivityStarter,方便后續(xù)處理
*/
setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
voiceInteractor);
// 檢查標(biāo)志位 ,以決定是否要新啟Task,即是否新建Stack, 滿足條件mAddingToTask = true
computeLaunchingTaskFlags();
computeSourceStack();
mIntent.setFlags(mLaunchFlags);
/**
* 考慮新啟用的Activity singleTask or singleInstance 的啟動模式的情況,此時可能已經(jīng)有AR了 和相應(yīng) Task
*/
ActivityRecord reusedActivity = getReusableIntentActivity();
......
// 根啟動滿足此條件, 根節(jié)點的話,不需要知道執(zhí)行結(jié)果,自然resultTo為null
if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
&& (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
newTask = true;
// 確保拿到可用的Task
result = setTaskFromReuseOrCreateNewTask(
taskToAffiliate, preferredLaunchStackId, topStack);
}
......
/**
* 這個函數(shù)的意義在于,將Activity放入棧頂,以便之后激活
*/
mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
mOptions);
if (mDoResume) {
mWindowManager.executeAppTransition();
} else {
if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) {
mTargetStack.moveToFront("startActivityUnchecked");
}
// 根啟動進這里
mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
mOptions);
}
}
在真正地去啟動Activity之前,記錄一些關(guān)鍵信息存于ActivityStarter成員變量中,在之后可以直接訪問。并且,需要考慮Activity的啟動模式,通常情況下,一個Activity啟動另一個Activity,兩個Activity會內(nèi)聚于同一個Task來處理。但當(dāng)設(shè)置標(biāo)識為FLAG_ACTIVITY_NEW_TASK時,會為要啟動的Activity尋找合適的Task處理。使用“合適”一詞說明,Task存在復(fù)用的情況,如果沒有找到可復(fù)用的Task,則新建。
如前文所說,從Launcher啟動的根Activity已設(shè)置了FLAG_ACTIVITY_NEW_TASK,因此新建了Task進行處理。然后將要啟動的Activity放置于棧頂,以為之后激活。
在ActivityStack中,mResumeActivity、mLastPausedActivity、mPausingActivity分別用來記錄當(dāng)前要激活的Activity、上一次被paused的Activity和此次要paused的Activity。
鏈路ActivityStackSupervisor.resumeFocusedStackTopActivityLocked() -> ActivityStack.resumeTopActivityUncheckedLocked() -> ActivityStack.resumeTopActivityInnerLocked()
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
......
// 拿到將要激活的Activity的AR
final ActivityRecord next = topRunningActivityLocked(true /* focusableOnly */);
......
// 如果已經(jīng)要激活的Activity為mResumedActivity 且狀態(tài)為RESUMED的話,什么也不做
if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
......
// 是否要通知來源Activity pause
boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, false);
if (mResumedActivity != null) {
if (DEBUG_STATES) Slog.d(TAG_STATES,
"resumeTopActivityLocked: Pausing " + mResumedActivity);
// 通知Launcher,該進入pause狀態(tài)了
pausing |= startPausingLocked(userLeaving, false, next, false);
}
return false;
}
......
// 根啟動時不會進入到這里,因為next.app為空
if (next.app != null && next.app.thread != null) {
......
if (next.newIntents != null) {
// 啟動activity
next.app.thread.scheduleNewIntent(
next.newIntents, next.appToken, false /* andPause */);
}
} else {
......
// 根節(jié)點啟動,為activity啟動進程
mStackSupervisor.startSpecificActivityLocked(next, true, true);
}
......
}
之前已經(jīng)將要激活的Activity的ActivityRecord推至棧頂,直接可以從棧頂獲取。此時,將要委托ActivityThread去啟動Activity,但是,根Activity所需要的進程還沒創(chuàng)建,也就沒有對應(yīng)的ActivityThread,需要先創(chuàng)建進程,隨后激活A(yù)ctivity。在新建進程前,通知Launcher進入pause狀態(tài)。
ActivityThread
ActivityThread會伴隨APP進程的創(chuàng)建而誕生。在前文所說的ActivityRecord里,ActivityRecord知道Activity運行時所知的各種信息,其中就包括運行所在進程的進程信息描述ProcessRecord。ProcessRecord擁有IApplicationThread實例,當(dāng)AMS需要對Activity進行操控時,通過需要ApplicationThread的本地Binder——IApplicationThread便能與APP所在進程進行通信。
在ActivityThread中,類名為H的Handler,則接收各種消息信號處理相應(yīng)的事件。
Launcher進入pause
ActivityStack.startPausingLocked()
final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping,
ActivityRecord resuming, boolean pauseImmediately) {
......
// 指向啟動來源的Activity
ActivityRecord prev = mResumedActivity;
......
// 更新,因為mLastPausedActivity表示上一次暫停的Activity
mLastPausedActivity = prev;
......
if (prev.app != null && prev.app.thread != null) {
if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueueing pending pause: " + prev);
try {
EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
prev.userId, System.identityHashCode(prev),
prev.shortComponentName);
mService.updateUsageStats(prev, false);
// 向AT發(fā)送通知,讓啟動來源Activity pause ,有機會執(zhí)行自己的bussiness
prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,
userLeaving, prev.configChangeFlags, pauseImmediately);
}
......
}
......
if (mPausingActivity != null) {
......
else {
// 發(fā)出PAUSE_TIMEOUT_MSG
schedulePauseTimeout(prev);
return true;
}
}
}
通過IApplicationThread讓ActivityThread處理Launcher的Pause事件,讓Launcher時機處理自己Pause()時的邏輯,同時,在延遲PAUSE_TIMEOUT_MSG時間后,發(fā)出激活新Activity的信息。這樣做的原因是因為,在確保舊Activity的onPause()事件完成后,需要AMS啟動新的Activity,這也符合我們所知的Activity生命周期規(guī)律。由于是進程間異步操作,ActivityStack、AMS不能確切知道舊的Activity完成onPause()的準(zhǔn)確時機,因此,AMS決定等待PAUSE_TIMEOUT_MSG時間,如果舊的Activity沒有在PAUSE_TIMEOUT_MSG時間內(nèi)完成onPause(),則被認為沒有相應(yīng)。
PAUSE_TIMEOUT_MSG事件由ActivityStack內(nèi)部類ActivityStackHandler接收
鏈路
ActivityStack.activityPausedLocked() -> ActivityStack.completePauseLocked() ->
ActivityStackSupervisor.resumeFocusedStackTopActivityLocked() ->
ActivityStackSupervisor.resumeTopActivityUncheckedLocked() ->
ActivityStack.resumeTopActivityInnerLocked()
再此來到ActivityStack.resumeTopActivityInnerLocked()
第一次來到,是給舊的Activity一個Pause時機
第二次來到,是啟動新的Activity
此前的情況是,根Activity的啟動,也是第一次來到時,還需要為APP創(chuàng)建新的進程
private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options) {
......
mStackSupervisor.startSpecificActivityLocked(next, true, true);
......
}
ActivityStackSupervisor.startSpecificActivityLocked()
void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
/**
* 在AMS中,每一個Activity組件都有一個UID和進程名稱,UID在安裝Activity時PMS分配,
* 進程名稱由android:process屬性決定。AMS啟動Activity時,首先會以其UID和進程名來檢查
* 進程是否存在,存在則由那個進程啟動,否則新建進程再啟動
*/
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid, true);
r.getStack().setLaunchTime(r);
// 子Activity與根Activity運行在同一進程里app和app.thread不再為空
if (app != null && app.thread != null) {
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);
}
// 子Activity在同一進程里啟動
realStartActivityLocked(r, app, andResume, checkConfig);
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);
}
因為沒有所需進程,需重新創(chuàng)建進程,也就是常說的冷啟動過程。
鏈路
-> ActivityManagerService.startProcessLocked()
-> ActivityManagerService.startProcessLocked()
-> ActivityManagerService.startProcessLocked()
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
long startTime = SystemClock.elapsedRealtime();
if (app.pid > 0 && app.pid != MY_PID) {
......
synchronized (mPidsSelfLocked) {
mPidsSelfLocked.remove(app.pid);
// 發(fā)送PROC_START_TIMEOUT_MSG
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
}
......
}
......
try{
......
else {
// 啟動新的應(yīng)該進程
// entryPoint 為 "android.app.ActivityThread"
// 剩下交給 Zygote 去孵化
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, entryPointArgs);
}
......
synchronized (mPidsSelfLocked) {
this.mPidsSelfLocked.put(startResult.pid, app);
if (isActivityProcess) {
// 如果進程不能在PROC_START_TIMEOUT_MSG事件啟動,則認為啟動超時
Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
msg.obj = app;
mHandler.sendMessageDelayed(msg, startResult.usingWrapper
? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
}
}
}
......
進程啟動則交給Zygote孵化,創(chuàng)建了進程,也創(chuàng)建了ActivityThread。 進程創(chuàng)建需要在PROC_START_TIMEOUT_MSG時間內(nèi)完成,否則認為創(chuàng)建失敗,也就沒有了后續(xù)的過程。
ActivityThread創(chuàng)建則見ActivityThread.main(),此后也就有了用于處理消息的Looper,用于通信的ApplicationThread。此一筆帶過。
啟動Activity
回到之前的流程,在有了進程,舊Activity已經(jīng)Pause,已可以啟動Activity
ActivityStackSupervisor.resumeTopActivityInnerLocked()
-> ActivityStackSupervisor.startSpecificActivityLocked()
-> ActivityStackSupervisor.realStartActivityLocked()
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,
boolean andResume, boolean checkConfig) throws RemoteException {
......
// 記錄 ProcessRecord
r.app = app;
app.waitingToKill = null;
r.launchCount++;
r.lastLaunchTime = SystemClock.uptimeMillis();
if (DEBUG_ALL) Slog.v(TAG, "Launching: " + r);
int idx = app.activities.indexOf(r);
if (idx < 0) {
// 將 activity 加入 activity 組件列表
app.activities.add(r);
}
......
try {
// 調(diào)用ActivityThread的scheduleLaunchActivity啟動activity
app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,
System.identityHashCode(r), r.info,
// TODO: Have this take the merged configuration instead of separate global and
// override configs.
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
r.launchedFromPackage, task.voiceInteractor, app.repProcState, r.icicle,
r.persistentState, results, newIntents, !andResume,
mService.isNextTransitionForward(), profilerInfo);
}
......
}
為ActivityRecord記錄了相關(guān)的ProcessRecord信息,再讓通過ActivityThread啟動Activity
ActivityThread.H.handlerMessage
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
// 需要加載APK文件,以便訪問資源
r.packageInfo = getPackageInfoNoCheck(
r.activityInfo.applicationInfo, r.compatInfo);
// 加載Activity
handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
鏈路
ActivityThread.handleLaunchActivity()
ActivityThread.performLaunchActivity()
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
// // 獲取Context對象
ContextImpl appContext = createBaseContextForActivity(r);
Activity activity = null;
try {
// 功過類加載器創(chuàng)建Activity
java.lang.ClassLoader cl = appContext.getClassLoader();
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
r.intent.prepareToEnterProcess();
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {
if (!mInstrumentation.onException(activity, e)) {
throw new RuntimeException(
"Unable to instantiate activity " + component
+ ": " + e.toString(), e);
}
}
try {
// 獲取Application,沒有則創(chuàng)建
Application app = r.packageInfo.makeApplication(false, mInstrumentation);
if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
if (localLOGV) Slog.v(
TAG, r + ": app=" + app
+ ", appName=" + app.getPackageName()
+ ", pkg=" + r.packageInfo.getPackageName()
+ ", comp=" + r.intent.getComponent().toShortString()
+ ", dir=" + r.packageInfo.getAppDir());
if (activity != null) {
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
if (r.overrideConfig != null) {
config.updateFrom(r.overrideConfig);
}
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
+ r.activityInfo.name + " with config " + config);
Window window = null;
if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {
window = r.mPendingRemoveWindow;
r.mPendingRemoveWindow = null;
r.mPendingRemoveWindowManager = null;
}
// 創(chuàng)建Activity所需的Context
appContext.setOuterContext(activity);
// Context與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);
......
int theme = r.activityInfo.getThemeResource();
// activity主題設(shè)置
if (theme != 0) {
activity.setTheme(theme);
}
activity.mCalled = false;
// 調(diào)用Activity.onCreate()
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
......
}
Activity.onCreate() 完成,則意味著Activity已啟動。
子Activity的啟動
上文描述了根Activity的啟動過程,而子Activity的啟動大致相同,不同點如下
- 在ActivityStarter.startActivityUnchecked()為Activity尋找Task時,已有Task
而無需創(chuàng)建新的Task,除非子Activity設(shè)置啟動FLAG為FLAG_ACTIVITY_NEW_TASK - 子Activity在不同進程里啟動時,AMS不會為子Activity創(chuàng)建新的Task,但會在ActivityStackSupervisor.startSpecificActivityLocked()為這個子Activity創(chuàng)建新的進程。
總結(jié)
- Task是一個比進程更高級和抽象的概念,每一個Activity都運行在一個Taks中。Task將一系列相關(guān)的Activity組件整合再一起,共同完成一個業(yè)務(wù)功能。如系統(tǒng)中存在A功能應(yīng)用進程,包含實現(xiàn)A功能的Activity,在其它APP使用這個功能時,Task保證A的Activity與其運行在一個Task里,如此用戶感覺不到應(yīng)用進程的不同。
- 啟動Activity需考慮所在Task和所處進程情況
- AMS需保證進程的創(chuàng)建時機可控、Activity的生命周期執(zhí)行時機可控
- Activity的啟動過程,實際上是AMS以ActivityRecord為信息媒介,以IApplicationThread為通信手段的通信管理過程
小思考
為什么不要在onPause()里執(zhí)行耗時任務(wù)?
新舊Activity在交替時生命周期的執(zhí)行,AMS和ActivityThread會保證一定的時序性與約束性,但有局限性。onPause()耗時任務(wù)認為會影響新Activity,也帶來不佳的用戶體驗。但,用戶體驗只能算是一部分原因,更重要的原因在于,onPasuse()方法是數(shù)據(jù)持久化的重要的可靠時機,當(dāng)發(fā)生如內(nèi)存重啟等異常突發(fā)情況致使進程突發(fā)死亡,那么onStop()、onDestroy()并不能保證是一定會被執(zhí)行。
僅僅以用戶體驗為由是不足以說明問題的。可以試驗這樣的場景:A啟動B,B在不同進程,A的onPause()執(zhí)行耗時任務(wù)。在這種場景下,B的onCreate()、onStart()、onResume()遠遠早于A的onPause(),看不到“影響用戶體驗”。那么,在這樣的場景下,就可以在onPause()里執(zhí)行耗時任務(wù)嗎?
參考
UserHandle
Task
Android Launcher 啟動 Activity 的工作過程
onPause()方法的特殊性