ActivityStarter.java services\core\java\com\android\server\wm
依次調(diào)用 execute() ——> executeRequest()——> startActivityUnchecked()——>
啟動后的 ActivityRecord 保存在request.outActivity[0] 中
execute() 會根據(jù)前面提供的請求參數(shù)解析必要的信息壹置,初始化resolveInfo【通過PMS】 和 activityInfo,并執(zhí)行開始activity的請求。
/**
* Resolve necessary information according the request parameters provided earlier, and execute
* the request which begin the journey of starting an activity.
* @return The starter result.
*/
int execute() {
try {
// Refuse possible leaked file descriptors
if (mRequest.intent != null && mRequest.intent.hasFileDescriptors()) {//intent不能傳文件句柄彻桃,如果有就報錯
throw new IllegalArgumentException("File descriptors passed in Intent");
}
final LaunchingState launchingState;
synchronized (mService.mGlobalLock) {
final ActivityRecord caller = ActivityRecord.forTokenLocked(mRequest.resultTo);
launchingState = mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(
mRequest.intent, caller);//LOG跟蹤的
}
// If the caller hasn't already resolved the activity, we're willing
// to do so here. If the caller is already holding the WM lock here,
// and we need to check dynamic Uri permissions, then we're forced
// to assume those permissions are denied to avoid deadlocking.
if (mRequest.activityInfo == null) {
mRequest.resolveActivity(mSupervisor);//就是初始化mRequest內(nèi)部的activityInfo
}
int res;
synchronized (mService.mGlobalLock) {
final boolean globalConfigWillChange = mRequest.globalConfig != null
&& mService.getGlobalConfiguration().diff(mRequest.globalConfig) != 0;
final ActivityStack stack = mRootWindowContainer.getTopDisplayFocusedStack();//獲取當前使用的activity棧
if (stack != null) {
stack.mConfigWillChange = globalConfigWillChange;
}
if (DEBUG_CONFIGURATION) {
Slog.v(TAG_CONFIGURATION, "Starting activity when config will change = "
+ globalConfigWillChange);
}
final long origId = Binder.clearCallingIdentity();
res = resolveToHeavyWeightSwitcherIfNeeded();//如果這是一個重量級進程赫段,而已經(jīng)有另一個不同的重量級進程在運行融师,則將請求更新為重量級開關(guān)奠旺。
if (res != START_SUCCESS) {
return res;
}
res = executeRequest(mRequest);//看這里看這里宦棺,關(guān)鍵在這里
Binder.restoreCallingIdentity(origId);
if (globalConfigWillChange) {
// If the caller also wants to switch to a new configuration, do so now.
// This allows a clean switch, as we are waiting for the current activity
// to pause (so we will not destroy it), and have not yet started the
// next activity.
mService.mAmInternal.enforceCallingPermission(
android.Manifest.permission.CHANGE_CONFIGURATION,
"updateConfiguration()");
if (stack != null) {
stack.mConfigWillChange = false;
}
if (DEBUG_CONFIGURATION) {
Slog.v(TAG_CONFIGURATION,
"Updating to new configuration after starting activity.");
}
mService.updateConfigurationLocked(mRequest.globalConfig, null, false);
//在ActivityStack中執(zhí)行resumeTopActivityLocked()函數(shù)時舌缤。ActivityStack會先詢問Wms,看Wms中是否會改變該Activity的屏幕方向箕戳。
}
// Notify ActivityMetricsLogger that the activity has launched.
// ActivityMetricsLogger will then wait for the windows to be drawn and populate
// WaitResult.
// 通知 ActivityMetricsLogger activity已啟動。 然后 ActivityMetricsLogger 將等待繪制窗口并填充 WaitResult国撵。
mSupervisor.getActivityMetricsLogger().notifyActivityLaunched(launchingState, res,
mLastStartActivityRecord);
return getExternalResult(mRequest.waitResult == null ? res
: waitForResult(res, mLastStartActivityRecord));//也只是返回一個int陵吸,暫且認為不重要!
}
} finally {
onExecutionComplete();//執(zhí)行完成后介牙,必須要執(zhí)行的 mLastStarter.set mLastStarter,recycle start
}
}
·
executeRequest 里面主要是 檢查各種參數(shù)是否合法壮虫,檢查啟動權(quán)限,請求Intent是否被允許啟動Activity环础、判斷應用程序啟動是否被攔截等囚似,若可正常啟動Activity,則創(chuàng)建一個ActivityRecord對象來描述即將啟動的Activity組件线得。然后進行下一步
/**
* Executing activity start request and starts the journey of starting an activity. Here
* begins with performing several preliminary checks. The normally activity launch flow will
* go through {@link #startActivityUnchecked} to {@link #startActivityInner}.
*/
private int executeRequest(Request request) {
if (TextUtils.isEmpty(request.reason)) {
throw new IllegalArgumentException("Need to specify a reason.");
}
mLastStartReason = request.reason;
mLastStartActivityTimeMs = System.currentTimeMillis();
mLastStartActivityRecord = null;
final IApplicationThread caller = request.caller;//Launcher應用的ApplicationThread對象
Intent intent = request.intent;//這便是啟動Activity時,傳遞過來的intent
NeededUriGrants intentGrants = request.intentGrants;
String resolvedType = request.resolvedType;//調(diào)用intent.resolveTypeIfNeeded而獲取
ActivityInfo aInfo = request.activityInfo;
ResolveInfo rInfo = request.resolveInfo;
final IVoiceInteractionSession voiceSession = request.voiceSession;
final IBinder resultTo = request.resultTo;//來自于Launcher 的 Activity.mToken
String resultWho = request.resultWho;
int requestCode = request.requestCode;//-1;
int callingPid = request.callingPid;
int callingUid = request.callingUid;
String callingPackage = request.callingPackage;
String callingFeatureId = request.callingFeatureId;
final int realCallingPid = request.realCallingPid;
final int realCallingUid = request.realCallingUid;
final int startFlags = request.startFlags;//startFlags = 0;
final SafeActivityOptions options = request.activityOptions;//null
Task inTask = request.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;
// WindowProcessController 這個類允許 AM 包中的 ProcessRecord 對象以結(jié)構(gòu)化的方式將其狀態(tài)的重要更改傳達給 WMS
WindowProcessController callerApp = null;
if (caller != null) {//這個對象就是 調(diào)用進程(launcher)的WindowProcessController 對象,通過它贯钩,WMS能夠同步AMS 中ProcessRecord的信息
callerApp = mService.getProcessController(caller);//通過IApplicationThread 獲得 源進程的WindowProcessController
if (callerApp != null) {
callingPid = callerApp.getPid();//保存pid
callingUid = callerApp.mInfo.uid;//保存uid
} else {
Slog.w(TAG, "Unable to find app for caller " + caller + " (pid=" + callingPid
+ ") when starting: " + intent.toString());
err = ActivityManager.START_PERMISSION_DENIED;//如果找不到caller的WPC對象募狂,這里就報錯
}
}
final int userId = aInfo != null && aInfo.applicationInfo != null
? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0;
if (err == ActivityManager.START_SUCCESS) {
Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false)
+ "} from uid " + callingUid);
}
ActivityRecord sourceRecord = null;//調(diào)用者(Launcher) 的 ActivityRecord
ActivityRecord resultRecord = null;//需要得到返回結(jié)果的 ActivityRecord,這里也是 Launcher
if (resultTo != null) {//需要把結(jié)果返回給一個Activity
sourceRecord = mRootWindowContainer.isInAnyStack(resultTo);//判斷調(diào)用者的AR在不在 stack 中【感覺可以理解為是否活著】
if (DEBUG_RESULTS) {
Slog.v(TAG_RESULTS, "Will send result to " + resultTo + " " + sourceRecord);
}
if (sourceRecord != null) {
if (requestCode >= 0 && !sourceRecord.finishing) {
resultRecord = sourceRecord;// 調(diào)用者(Launcher) 的 ActivityRecord 就是 需要得到返回結(jié)果的 ActivityRecord
}
}
}
final int launchFlags = intent.getFlags();//獲取啟動flag,這里估計是判斷權(quán)限
if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
// Transfer the result target from the source activity to the new one being started,
// including any failures.通過Intent的FLAG_ACTIVITY_FORWARD_RESULT可以將最后一個頁面的值回傳給第一個頁面角雷。
if (requestCode >= 0) {
SafeActivityOptions.abort(options);
return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT;
}
resultRecord = sourceRecord.resultTo;
if (resultRecord != null && !resultRecord.isInStackLocked()) {
resultRecord = null;
}
resultWho = sourceRecord.resultWho;
requestCode = sourceRecord.requestCode;
sourceRecord.resultTo = null;
if (resultRecord != null) {
resultRecord.removeResultsLocked(sourceRecord, resultWho, requestCode);
}
if (sourceRecord.launchedFromUid == callingUid) {
// The new activity is being launched from the same uid as the previous activity
// in the flow, and asking to forward its result back to the previous. In this
// case the activity is serving as a trampoline between the two, so we also want
// to update its launchedFromPackage to be the same as the previous activity.
// Note that this is safe, since we know these two packages come from the same
// uid; the caller could just as well have supplied that same package name itself
// . This specifially deals with the case of an intent picker/chooser being
// launched in the app flow to redirect to an activity picked by the user, where
// we want the final activity to consider it to have been launched by the
// previous app activity.
callingPackage = sourceRecord.launchedFromPackage;
callingFeatureId = sourceRecord.launchedFromFeatureId;
}
}
if (err == ActivityManager.START_SUCCESS && intent.getComponent() == null) {
// We couldn't find a class that can handle the given Intent.
// That's the end of that!
//Component是null,我們找不到可以處理給定 Intent 的類祸穷。 就這樣結(jié)束了!
err = ActivityManager.START_INTENT_NOT_RESOLVED;
}
if (err == ActivityManager.START_SUCCESS && aInfo == null) {
// We couldn't find the specific class specified in the Intent.
// Also the end of the line.
err = ActivityManager.START_CLASS_NOT_FOUND;
}
if (err == ActivityManager.START_SUCCESS && sourceRecord != null
&& sourceRecord.getTask().voiceSession != null) {//如果啟動的是一個語音會話勺三,需要做一些處理
// If this activity is being launched as part of a voice session, we need to ensure
// that it is safe to do so. If the upcoming activity will also be part of the voice
// session, we can only launch it if it has explicitly said it supports the VOICE
// category, or it is a part of the calling app.
if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) == 0
&& sourceRecord.info.applicationInfo.uid != aInfo.applicationInfo.uid) {
try {
intent.addCategory(Intent.CATEGORY_VOICE);
if (!mService.getPackageManager().activitySupportsIntent(
intent.getComponent(), intent, resolvedType)) {
Slog.w(TAG, "Activity being started in current voice task does not support "
+ "voice: " + intent);
err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
}
} catch (RemoteException e) {
Slog.w(TAG, "Failure checking voice capabilities", e);
err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
}
}
}
if (err == ActivityManager.START_SUCCESS && voiceSession != null) {//如果caller是啟動一個語音會話雷滚,只需要目標實際上允許它以這種方式允許
// If the caller is starting a new voice session, just make sure the target
// is actually allowing it to run this way.
try {
if (!mService.getPackageManager().activitySupportsIntent(intent.getComponent(),
intent, resolvedType)) {
Slog.w(TAG,
"Activity being started in new voice task does not support: " + intent);
err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
}
} catch (RemoteException e) {
Slog.w(TAG, "Failure checking voice capabilities", e);
err = ActivityManager.START_NOT_VOICE_COMPATIBLE;
}
}
final ActivityStack resultStack = resultRecord == null
? null : resultRecord.getRootTask();//獲取 resultRecord 的 Activity
//如果參數(shù)非法,就直接return,停止啟動
if (err != START_SUCCESS) {
if (resultRecord != null) {
resultRecord.sendResult(INVALID_UID, resultWho, requestCode, RESULT_CANCELED,
null /* data */, null /* dataGrants */);
}
SafeActivityOptions.abort(options);
return err;
}
//判斷調(diào)用方【Launcher】是否有權(quán)限啟動Activity
boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
requestCode, callingPid, callingUid, callingPackage, callingFeatureId,
request.ignoreTargetSecurity, inTask != null, callerApp, resultRecord, resultStack);
abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
callingPid, resolvedType, aInfo.applicationInfo);
abort |= !mService.getPermissionPolicyInternal().checkStartActivity(intent, callingUid,
callingPackage);
boolean restrictedBgActivity = false;
if (!abort) {//如果不停止
try {
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER,
"shouldAbortBackgroundActivityStart");
restrictedBgActivity = shouldAbortBackgroundActivityStart(callingUid,
callingPid, callingPackage, realCallingUid, realCallingPid, callerApp,
request.originatingPendingIntent, request.allowBackgroundActivityStart,
intent);//這個方法的作用是禁止應用后臺私自啟動Activity吗坚,有3個好處
//可以避免當前頁面操作被打斷(打游戲時候的突然彈窗)
//流氓應用的彈出式廣告
//流氓應用的“一像素逼碓叮活” 沒仔細看源碼
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
}
}
//這一段不太懂啥意思胯舷,目前傳進來的是null
// Merge the two options bundles, while realCallerOptions takes precedence.
ActivityOptions checkedOptions = options != null
? options.getOptions(intent, aInfo, callerApp, mSupervisor) : null;
if (request.allowPendingRemoteAnimationRegistryLookup) {
checkedOptions = mService.getActivityStartController()
.getPendingRemoteAnimationRegistry()
.overrideOptionsIfNeeded(callingPackage, checkedOptions);
}
if (mService.mController != null) {
try {
// The Intent we give to the watcher has the extra data stripped off, since it
// can contain private information.
Intent watchIntent = intent.cloneFilter();
abort |= !mService.mController.activityStarting(watchIntent,
aInfo.applicationInfo.packageName);
} catch (RemoteException e) {
mService.mController = null;
}
}
//mInterceptor【ActivityStartInterceptor】Activity攔截邏輯的類,通過setStates 初始化
mInterceptor.setStates(userId, realCallingPid, realCallingUid, startFlags, callingPackage,
callingFeatureId);
if (mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, callingPid,
callingUid, checkedOptions)) {
// activity start was intercepted, e.g. because the target user is currently in quiet
// mode (turn off work) or the target application is suspended
//活動開始被攔截绊含,例如 因為目標用戶當前處于安靜模式(關(guān)閉工作)或目標應用程序被掛起
intent = mInterceptor.mIntent;
rInfo = mInterceptor.mRInfo;
aInfo = mInterceptor.mAInfo;
resolvedType = mInterceptor.mResolvedType;
inTask = mInterceptor.mInTask;
callingPid = mInterceptor.mCallingPid;
callingUid = mInterceptor.mCallingUid;
checkedOptions = mInterceptor.mActivityOptions;
// The interception target shouldn't get any permission grants
// intended for the original destination
// 攔截目標不應獲得針對原始目標的任何權(quán)限授予
intentGrants = null;
}
if (abort) {//如果確定終止
if (resultRecord != null) {
resultRecord.sendResult(INVALID_UID, resultWho, requestCode, RESULT_CANCELED,
null /* data */, null /* dataGrants */);
}
// We pretend to the caller that it was really started, but they will just get a
// cancel result.
// 我們向調(diào)用者假裝它真的開始了桑嘶,但他們只會得到一個取消結(jié)果。
ActivityOptions.abort(checkedOptions);
return START_ABORTED;
}
// If permissions need a review before any of the app components can run, we
// launch the review activity and pass a pending intent to start the activity
// we are to launching now after the review is completed.
// 如果在任何應用組件可以運行之前權(quán)限需要審查躬充,我們啟動review activity 并傳遞一個 pending intent逃顶,
// 以在審查完成后啟動我們現(xiàn)在要啟動的activity。
if (aInfo != null) {//如果需要重新進行權(quán)限的檢測充甚,那么就進行一次檢測
if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(
aInfo.packageName, userId)) {
final IIntentSender target = mService.getIntentSenderLocked(
ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage, callingFeatureId,
callingUid, userId, null, null, 0, new Intent[]{intent},
new String[]{resolvedType}, PendingIntent.FLAG_CANCEL_CURRENT
| PendingIntent.FLAG_ONE_SHOT, null);
Intent newIntent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);
int flags = intent.getFlags();
flags |= Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
/*
* Prevent reuse of review activity: Each app needs their own review activity. By
* default activities launched with NEW_TASK or NEW_DOCUMENT try to reuse activities
* with the same launch parameters (extras are ignored). Hence to avoid possible
* reuse force a new activity via the MULTIPLE_TASK flag.
*
* Activities that are not launched with NEW_TASK or NEW_DOCUMENT are not re-used,
* hence no need to add the flag in this case.
*/
if ((flags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_NEW_DOCUMENT)) != 0) {
flags |= Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
}
newIntent.setFlags(flags);
newIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, aInfo.packageName);
newIntent.putExtra(Intent.EXTRA_INTENT, new IntentSender(target));
if (resultRecord != null) {
newIntent.putExtra(Intent.EXTRA_RESULT_NEEDED, true);
}
intent = newIntent;
// The permissions review target shouldn't get any permission
// grants intended for the original destination
intentGrants = null;
resolvedType = null;
callingUid = realCallingUid;
callingPid = realCallingPid;
rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId, 0,
computeResolveFilterUid(
callingUid, realCallingUid, request.filterCallingUid));
aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags,
null /*profilerInfo*/);
if (DEBUG_PERMISSIONS_REVIEW) {
final ActivityStack focusedStack =
mRootWindowContainer.getTopDisplayFocusedStack();
Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true,
true, false) + "} from uid " + callingUid + " on display "
+ (focusedStack == null ? DEFAULT_DISPLAY
: focusedStack.getDisplayId()));
}
}
}
// If we have an ephemeral app, abort the process of launching the resolved intent.
// Instead, launch the ephemeral installer. Once the installer is finished, it
// starts either the intent we resolved here [on install error] or the ephemeral
// app [on install success].
if (rInfo != null && rInfo.auxiliaryInfo != null) {//通過PMS獲取rInfo以政,aInfo信息。
intent = createLaunchIntent(rInfo.auxiliaryInfo, request.ephemeralIntent,
callingPackage, callingFeatureId, verificationBundle, resolvedType, userId);
resolvedType = null;
callingUid = realCallingUid;
callingPid = realCallingPid;
// The ephemeral installer shouldn't get any permission grants
// intended for the original destination
intentGrants = null;
aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/);
}
//這里是正式創(chuàng)建ActivityRecord了
final ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
callingPackage, callingFeatureId, intent, resolvedType, aInfo,
mService.getGlobalConfiguration(), resultRecord, resultWho, requestCode,
request.componentSpecified, voiceSession != null, mSupervisor, checkedOptions,
sourceRecord);
mLastStartActivityRecord = r;//保存為全局變量
if (r.appTimeTracker == null && sourceRecord != null) {
// If the caller didn't specify an explicit time tracker, we want to continue
// tracking under any it has.
r.appTimeTracker = sourceRecord.appTimeTracker;//將sourceRecord的appTimeTracker賦值給新的AR
}
final ActivityStack stack = mRootWindowContainer.getTopDisplayFocusedStack();//獲取棧頂?shù)腁ctivityStack
// If we are starting an activity that is not from the same uid as the currently resumed
// one, check whether app switches are allowed.
//如果我們啟動的活動與當前reusume的應用activity的的uid不同伴找,檢查是否允許應用程序切換盈蛮。
if (voiceSession == null && stack != null && (stack.getResumedActivity() == null
|| stack.getResumedActivity().info.applicationInfo.uid != realCallingUid)) {
if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
realCallingPid, realCallingUid, "Activity start")) {
if (!(restrictedBgActivity && handleBackgroundActivityAbort(r))) {
mController.addPendingActivityLaunch(new PendingActivityLaunch(r,
sourceRecord, startFlags, stack, callerApp, intentGrants));
}
ActivityOptions.abort(checkedOptions);
return ActivityManager.START_SWITCHES_CANCELED;
}
}
mService.onStartActivitySetDidAppSwitch();//設(shè)置2個全局變量
mController.doPendingActivityLaunches(false);//處理一些全局啟動的Activity
mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession,//關(guān)鍵是看這里了
request.voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask,
restrictedBgActivity, intentGrants);
if (request.outActivity != null) {
request.outActivity[0] = mLastStartActivityRecord;
}
return mLastStartActivityResult;
}
startActivityUnchecked
startActivityUnchecked 邏輯比較簡單,先別管Finally里面的東西技矮,主流程直接是調(diào)用了startActivityInner
/**
* Start an activity while most of preliminary checks has been done and caller has been
* confirmed that holds necessary permissions to do so.
* Here also ensures that the starting activity is removed if the start wasn't successful.
*/在完成大部分初步檢查并確認調(diào)用者擁有執(zhí)行此操作所需的權(quán)限時啟動activity抖誉,此處還確保在啟動不成功時刪除啟動activity。
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, Task inTask,
boolean restrictedBgActivity, NeededUriGrants intentGrants) {
int result = START_CANCELED;
final ActivityStack startedActivityStack;
try {
mService.deferWindowLayout();//通知暫停布局衰倦,因為啟動的過程中會有多個更改會會觸發(fā)到surfacelayout袒炉。通過這種方式,能夠避免重復刷新
//在最后通過continueSurfaceLayout進行布局的統(tǒng)一刷新樊零,相當于進行了優(yōu)化工作
Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");
result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
startFlags, doResume, options, inTask, restrictedBgActivity, intentGrants);//關(guān)鍵是調(diào)這里
} finally {
Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
startedActivityStack = handleStartResult(r, result);//獲取當前的Activity棧
mService.continueWindowLayout();//恢復暫停的布局
}
postStartActivityProcessing(r, result, startedActivityStack);// 啟動不成功時刪除啟動activity
return result;
}
startActivityInner
startActivityInnerx作用是啟動activity并確定activity是否應添加到現(xiàn)有Task的頂部或向現(xiàn)有活動傳遞新intent我磁。 還將activityTask操作到請求的或有效的stack/Display上。
/**
* Start an activity and determine if the activity should be adding to the top of an existing
* task or delivered new intent to an existing activity. Also manipulating the activity task
* onto requested or valid stack/display.
*啟動activity并確定activity是否應添加到現(xiàn)有Task的頂部或向現(xiàn)有活動傳遞新意圖驻襟。 還將activityTask操作到請求的或有效的stack/Display上夺艰。
* Note: This method should only be called from {@link #startActivityUnchecked}.
*/
// TODO(b/152429287): Make it easier to exercise code paths through startActivityInner
@VisibleForTesting
int startActivityInner(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, Task inTask,
boolean restrictedBgActivity, NeededUriGrants intentGrants) {
setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
voiceInteractor, restrictedBgActivity);
//初始化一些全局變量,如mLaunchFlags沉衣,mLaunchMode郁副、mSupervisor.mUserLeaving等,也會把doResume賦給mDoResume厢蒜,即mDoResume為true
//初始化一些狀態(tài)霞势,這里主要是根據(jù)啟動模式的相關(guān)設(shè)置進行了一些變量的處理。比如newtask斑鸦,document等等
//初始化Activity啟動狀態(tài)愕贡,獲取launchmode flag 同時解決一些falg和launchmode的沖突
computeLaunchingTaskFlags();
//該函數(shù)用于設(shè)置mAddingToTask全局變量,初始化為false巷屿,該變量用于判斷是否要為目標Activity組件創(chuàng)建一個專屬的task固以,為false表示需要
//這里就和Activity4種啟動模式相關(guān)了,單例、棧頂復用憨琳,棧內(nèi)復用诫钓,普通
computeSourceStack();//處理調(diào)用方的任務棧信息。通過mSourceRecord獲取到調(diào)用方的任務棧篙螟。如果調(diào)用方已經(jīng)finish了菌湃,那么啟動一個newtask任務棧來作為調(diào)用方任務棧
mIntent.setFlags(mLaunchFlags);//設(shè)置啟動flag
final Task reusedTask = getReusableTask();//判讀是否可以復用已經(jīng)保存在Task中的Activity實例,如果可以就返回相應的實例遍略,否則返回null
// If requested, freeze the task list
if (mOptions != null && mOptions.freezeRecentTasksReordering()//正常由Launcher進來為null
&& mSupervisor.mRecentTasks.isCallerRecents(r.launchedFromUid)
&& !mSupervisor.mRecentTasks.isFreezeTaskListReorderingSet()) {
mFrozeTaskList = true;
mSupervisor.mRecentTasks.setFreezeTaskListReordering();
}
// Compute if there is an existing task that should be used for.如果有已經(jīng)存在能復用的task惧所,就復用
final Task targetTask = reusedTask != null ? reusedTask : computeTargetTask();
final boolean newTask = targetTask == null;
mTargetTask = targetTask;
computeLaunchParams(r, sourceRecord, targetTask);
// Check if starting activity on given task or on a new task is allowed.
//檢查是否允許在給定task或新task上啟動activity。
int startResult = isAllowedToStart(r, newTask, targetTask);
if (startResult != START_SUCCESS) {
return startResult;
}
final ActivityRecord targetTaskTop = newTask
? null : targetTask.getTopNonFinishingActivity();
if (targetTaskTop != null) {
// Recycle the target task for this launch.
startResult = recycleTask(targetTask, targetTaskTop, reusedTask, intentGrants);
if (startResult != START_SUCCESS) {
return startResult;
}
} else {
mAddingToTask = true;
}
// If the activity being launched is the same as the one currently at the top, then
// we need to check if it should only be launched once.
//如果正在啟動的activity與當前位于頂部的activity相同绪杏,那么我們需要檢查它是否應該只啟動一次下愈。
final ActivityStack topStack = mRootWindowContainer.getTopDisplayFocusedStack();
if (topStack != null) {
startResult = deliverToCurrentTopIfNeeded(topStack, intentGrants);
if (startResult != START_SUCCESS) {
return startResult;
}
}
if (mTargetStack == null) {
mTargetStack = getLaunchStack(mStartActivity, mLaunchFlags, targetTask, mOptions);
}
if (newTask) {
final Task taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
? mSourceRecord.getTask() : null;
setNewTask(taskToAffiliate);
if (mService.getLockTaskController().isLockTaskModeViolation(
mStartActivity.getTask())) {
Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
return START_RETURN_LOCK_TASK_MODE_VIOLATION;
}
} else if (mAddingToTask) {
addOrReparentStartingActivity(targetTask, "adding to task");
}
if (!mAvoidMoveToFront && mDoResume) {
mTargetStack.getStack().moveToFront("reuseOrNewTask", targetTask);
if (mOptions != null) {
if (mOptions.getTaskAlwaysOnTop()) {
mTargetStack.setAlwaysOnTop(true);
}
}
if (!mTargetStack.isTopStackInDisplayArea() && mService.mInternal.isDreaming()) {
// Launching underneath dream activity (fullscreen, always-on-top). Run the launch-
// -behind transition so the Activity gets created and starts in visible state.
mLaunchTaskBehind = true;
r.mLaunchTaskBehind = true;
}
}
mService.mUgmInternal.grantUriPermissionUncheckedFromIntent(intentGrants,
mStartActivity.getUriPermissionsLocked());
if (mStartActivity.resultTo != null && mStartActivity.resultTo.info != null) {
// we need to resolve resultTo to a uid as grantImplicitAccess deals explicitly in UIDs
final PackageManagerInternal pmInternal =
mService.getPackageManagerInternalLocked();
final int resultToUid = pmInternal.getPackageUidInternal(
mStartActivity.resultTo.info.packageName, 0, mStartActivity.mUserId);
pmInternal.grantImplicitAccess(mStartActivity.mUserId, mIntent,
UserHandle.getAppId(mStartActivity.info.applicationInfo.uid) /*recipient*/,
resultToUid /*visible*/, true /*direct*/);
}
if (newTask) {
EventLogTags.writeWmCreateTask(mStartActivity.mUserId,
mStartActivity.getTask().mTaskId);
}
mStartActivity.logStartActivity(
EventLogTags.WM_CREATE_ACTIVITY, mStartActivity.getTask());
mTargetStack.mLastPausedActivity = null;
mRootWindowContainer.sendPowerHintForLaunchStartIfNeeded(
false /* forceSend */, mStartActivity);
mTargetStack.startActivityLocked(mStartActivity,
topStack != null ? topStack.getTopNonFinishingActivity() : null, newTask,
mKeepCurTransition, mOptions);
//將目標Activity組件保存到ActivityStack的mTaskHistory所描述的Activity組件堆棧中
if (mDoResume) {
final ActivityRecord topTaskActivity =
mStartActivity.getTask().topRunningActivityLocked();
if (!mTargetStack.isTopActivityFocusable()
|| (topTaskActivity != null && topTaskActivity.isTaskOverlay()
&& mStartActivity != topTaskActivity)) {
// If the activity is not focusable, we can't resume it, but still would like to
// make sure it becomes visible as it starts (this will also trigger entry
// animation). An example of this are PIP activities.
// Also, we don't want to resume activities in a task that currently has an overlay
// as the starting activity just needs to be in the visible paused state until the
// over is removed.
// Passing {@code null} as the start parameter ensures all activities are made
// visible.
// 如果 Activity 不可聚焦,我們將無法恢復它蕾久,但仍希望確保它在啟動時可見(這也會觸發(fā)進入動畫)势似。
//這方面的一個例子是 PIP 活動。此外僧著,我們不希望在當前具有覆蓋層的任務中恢復活動履因,因為起始活動只
//需要處于可見的暫停狀態(tài),直到覆蓋層被移除霹抛。
mTargetStack.ensureActivitiesVisible(null /* starting */,
0 /* configChanges */, !PRESERVE_WINDOWS);
// Go ahead and tell window manager to execute app transition for this activity
// since the app transition will not be triggered through the resume channel.
// 繼續(xù)并告訴 WM 為此activity執(zhí)行應用程序轉(zhuǎn)換搓逾,因為應用程序轉(zhuǎn)換不會通過resume通道觸發(fā)卷谈。
mTargetStack.getDisplay().mDisplayContent.executeAppTransition();
} else {
// If the target stack was not previously focusable (previous top running activity
// on that stack was not visible) then any prior calls to move the stack to the
// will not update the focused stack. If starting the new activity now allows the
// task stack to be focusable, then ensure that we now update the focused stack
// accordingly.
// 如果目標堆棧先前不可聚焦(該堆棧上先前運行的頂部活動不可見)杯拐,則任何先前將堆棧移至
//的調(diào)用都不會更新聚焦堆棧。 如果現(xiàn)在啟動新活動允許任務堆棧成為焦點世蔗,那么確保我們現(xiàn)在相應地更新焦點堆棧端逼。
if (mTargetStack.isTopActivityFocusable()
&& !mRootWindowContainer.isTopDisplayFocusedStack(mTargetStack)) {
mTargetStack.moveToFront("startActivityInner");
}
//核心,繼續(xù)完成activity的創(chuàng)建工作污淋,判斷是重新啟動一個Activity還是就是當前的Top Activity
mRootWindowContainer.resumeFocusedStacksTopActivities(//關(guān)鍵是這里了
mTargetStack, mStartActivity, mOptions);
}
}
mRootWindowContainer.updateUserStack(mStartActivity.mUserId, mTargetStack);
// Update the recent tasks list immediately when the activity starts
mSupervisor.mRecentTasks.add(mStartActivity.getTask());//activity starts時更新最近Task
mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(),
mPreferredWindowingMode, mPreferredTaskDisplayArea, mTargetStack);
return START_SUCCESS;
}
RootWindowContainer.java services\core\java\com\android\server\wm
RootWindowContainer 是窗口容器的根容器顶滩,子容器是 DisplayContent
resumeFocusedStacksTopActivities
這里的resumeFocusedStacksTopActivities函數(shù)把核心任務交給ActivityStack完成。
boolean resumeFocusedStacksTopActivities() {
return resumeFocusedStacksTopActivities(null, null, null);
}
boolean resumeFocusedStacksTopActivities(
ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
if (!mStackSupervisor.readyToResume()) {
return false;
}
boolean result = false;
if (targetStack != null && (targetStack.isTopStackInDisplayArea()
|| getTopDisplayFocusedStack() == targetStack)) {
result = targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
}//******重點方法******如果當前的activitystack正好處于屏幕的頂部寸爆,那么直接調(diào)用將target設(shè)置到頂部顯示
for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) {
//標記是否已經(jīng)顯示在屏幕上
final DisplayContent display = getChildAt(displayNdx);
boolean resumedOnDisplay = false;
for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) {
final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx);
for (int sNdx = taskDisplayArea.getStackCount() - 1; sNdx >= 0; --sNdx) {
final ActivityStack stack = taskDisplayArea.getStackAt(sNdx);
final ActivityRecord topRunningActivity = stack.topRunningActivity();
//獲取到當前ActivityStack頂部正在運行的Activity
if (!stack.isFocusableAndVisible() || topRunningActivity == null) {
continue;//上面已經(jīng)做過resume處理了礁鲁,所以這里我們就不再做處理了
}
if (stack == targetStack) {
// Simply update the result for targetStack because the targetStack had
// already resumed in above. We don't want to resume it again, especially in
// some cases, it would cause a second launch failure if app process was
// dead.
resumedOnDisplay |= result;
continue;
}
if (taskDisplayArea.isTopStack(stack) && topRunningActivity.isState(RESUMED)) {
// Kick off any lingering app transitions form the MoveTaskToFront
// operation, but only consider the top task and stack on that display.
stack.executeAppTransition(targetOptions);
} else {
resumedOnDisplay |= topRunningActivity.makeActiveIfNeeded(target);
}
}
}
if (!resumedOnDisplay) {//如果仍然沒有顯示在屏幕上,那么就獲取到屏幕當前持有焦點的ActivityStack赁豆,然后將activity顯示在上面
// In cases when there are no valid activities (e.g. device just booted or launcher
// crashed) it's possible that nothing was resumed on a display. Requesting resume
// of top activity in focused stack explicitly will make sure that at least home
// activity is started and resumed, and no recursion occurs.
final ActivityStack focusedStack = display.getFocusedStack();
if (focusedStack != null) {
result |= focusedStack.resumeTopActivityUncheckedLocked(target, targetOptions);
} else if (targetStack == null) {
result |= resumeHomeActivity(null /* prev */, "no-focusable-task",
display.getDefaultTaskDisplayArea());
}
}
}
return result;
}