在幾個月前我寫了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);
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);
} 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.FLAGACTIVITYNEW_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) {
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);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
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在本地的代理。
回到Instrumentation類的execStartActivity方法中,從上面得知execStartActivity方法最終調用的是AMS的startActivity方法。
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");
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, false, ALLOW_FULL_ONLY, "startActivity", null);
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)) {
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) {
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;
}
}
...
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;
}
...
doPendingActivityLaunchesLocked(false);
return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
options, inTask, outActivity);
}
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) {
newTask = true;
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");
}
mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
mOptions);
}
} else {
mTargetStack.addRecentActivityLocked(mStartActivity);
}
...
}
startActivityUnchecked方法主要處理棧管理相關的邏輯。在標註①處我們得知,啟動根Activity時會將Intent的Flag設置為FLAGACTIVITYNEW_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);
}
final ActivityRecord r = mFocusedStack.topRunningActivityLocked();
if (r == null || r.state != RESUMED) {
mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
} 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);
} 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) {
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid, true);
r.getStack().setLaunchTime(r);
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);
}
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);
}
注釋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啟動過程中涉及的進程。