Activity/應(yīng)用(O/8.0)啟動(dòng)流程(一)
Activity/應(yīng)用(O/8.0)啟動(dòng)流程(二)
Activity/應(yīng)用(O/8.0)啟動(dòng)流程(三)
Activity/應(yīng)用(O/8.0)啟動(dòng)流程(四)
1) 將啟動(dòng)操作從用戶進(jìn)程傳遞到AMS進(jìn)程,
我們平常啟動(dòng)一個(gè)Activity都是通過startActivity來進(jìn)行操作,也是啟動(dòng)Activity的唯一操作,我們從桌面啟動(dòng)一個(gè)應(yīng)用程序來說;
其實(shí)大家都知道桌面也是一個(gè)應(yīng)用程序,通過PMS獲取到所有的安裝程序的信息,然后通過圖標(biāo)的進(jìn)行展示,點(diǎn)擊圖標(biāo)的時(shí)候然后進(jìn)行跳轉(zhuǎn);
系統(tǒng)的桌面程序進(jìn)行展示的Activity為LauncherActivity,通過監(jiān)聽點(diǎn)擊事件進(jìn)行跳轉(zhuǎn)
// LauncherActivity#onListItemClick
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Intent intent = intentForPosition(position);
startActivity(intent);
}
/**
* Return the actual Intent for a specific position in our
* {@link android.widget.ListView}.
* @param position The item whose Intent to return
*/
protected Intent intentForPosition(int position) {
ActivityAdapter adapter = (ActivityAdapter) mAdapter;
return adapter.intentForPosition(position);
}
ActivityAdapter里面存儲(chǔ)著應(yīng)用啟動(dòng)的信息,會(huì)通過下標(biāo)獲取這些信息并加入到Intent里面然后返回,這里就不在多說了。
然后調(diào)用startActivity,這么我們主要看Activity中的startActivity,
@Override
public void startActivity(Intent intent) {
this.startActivity(intent, null);
}
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
// 因?yàn)閛ptions為null,我們走else 從這里們可以看出 startActivity最終調(diào)用的還是startActivityForResult,
// 但是因?yàn)闆]有設(shè)置requestCode,默認(rèn)都是-1,也可以說是<0的值;
if (options != null) {
startActivityForResult(intent, -1, options);
} else {
// Note we want to go through this call for compatibility with
// applications that may have overridden the method.
startActivityForResult(intent, -1);
}
}
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) {
startActivityForResult(intent, requestCode, null);
}
public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,
@Nullable Bundle options) {
if (mParent == null) {
// 前面我們說options = null 所以這里會(huì)通過transferSpringboardActivityOptions去獲取一個(gè)options
// 最終調(diào)用了Instrumentation#execStartActivity
options = transferSpringboardActivityOptions(options);
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, this,
intent, requestCode, options);
if (ar != null) {
mMainThread.sendActivityResult(
mToken, mEmbeddedID, requestCode, ar.getResultCode(),
ar.getResultData());
}
if (requestCode >= 0) {
// If this start is requesting a result, we can avoid making
// the activity visible until the result is received. Setting
// this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
// activity hidden during this time, to avoid flickering.
// This can only be done when a result is requested because
// that guarantees we will get information back when the
// activity is finished, no matter what happens to it.
mStartedActivity = true;
}
cancelInputsAndStartExitTransition(options);
// TODO Consider clearing/flushing other event sources and events for child windows.
} 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);
}
}
}
上面說到了會(huì)獲取一個(gè)ActivityOptions 對(duì)象,這個(gè)對(duì)象的其他作用我們可能不知道,但是在頁面跳轉(zhuǎn)的時(shí)候的跳轉(zhuǎn)動(dòng)畫會(huì)用到ActivityOptions
Pair pairSearch = Pair.create(vSearch,"search");
Pair pairIcon = Pair.create(ivIcon,"iconTransition");
Intent intent = new Intent(SearchTabActivity.this, SearchActivity.class);
getWindow().setSharedElementEnterTransition(transition);
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this,pairSearch,pairIcon);
startActivity(intent, options.toBundle());
我們來看Instrumentation中的execStartActivity,先來看下入?yún)?/p>
who:執(zhí)行啟動(dòng)的上下文環(huán)境,在Activity中的入?yún)閠his
contextThread: Activity對(duì)應(yīng)的ApplicationThread
token: 每個(gè)Activity都有一個(gè)token,用于表示自身 ,在ActivityRecord創(chuàng)建的時(shí)候會(huì)一并創(chuàng)建
target: 代表執(zhí)行啟動(dòng)的Activity,還有一點(diǎn)就是用于接收從將要啟動(dòng)的的Activity返回的信息,onActivityResult()
// Instrumentation#execStartActivity
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);
}
// ... 代碼省略
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;
}
省略了一些代碼,我們可以看到這里將一些初始參數(shù)傳遞到了AMS中,因?yàn)槭茿MS所在的進(jìn)程與用戶進(jìn)程不是同一個(gè)進(jìn)程,所以這里使用了Binder來實(shí)現(xiàn)了跨進(jìn)程的調(diào)用,這里也不多說,下面直接看AMS中的處理。
2)在AMS中對(duì)參數(shù)初始化
同樣先來看下入?yún)?/p>
caller : 執(zhí)行啟動(dòng)的Activity對(duì)應(yīng)的ApplicationThread
callingPackage:執(zhí)行啟動(dòng)的Activity的包名
resultTo:即上面所說的token
resultWho:Activity中的一個(gè)成員變量mEmbeddedID ,也可以理解為Activity獨(dú)有的標(biāo)識(shí)
接下來會(huì)調(diào)用這幾個(gè)方法,因?yàn)槎际侵苯诱{(diào)用,沒有什么特別的參數(shù),包括下面的流程,這種的代碼我都會(huì)給一個(gè)調(diào)用流程,代碼可能就不貼了
AMS.startActivity->AMS.startActivityAsUser -> ActivityStarter.startActivityMayWait
AMS#startActivityAsUser
@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);
// TODO: Switch to user app stacks here.
return mActivityStarter.startActivityMayWait(caller, -1, callingPackage, intent,
resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
profilerInfo, null, null, bOptions, false, userId, null, "startActivityAsUser");
}
因?yàn)檫@里新加了幾個(gè)參數(shù),為了讓大家做好對(duì)比,就把方法貼出來了;同時(shí)此時(shí)PMS將參數(shù)傳遞到了ActivityStarter中
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,
TaskRecord inTask, String reason) {
...代碼省略
// 這里會(huì)通過PMS去解析Intent,得到一個(gè)ResolveInfo信息,里面包含有ActivityInfo、ServiceInfo等信息
ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);
// Collect information about the target of the Intent.
// 根據(jù)解析出來的ResolveInfo,獲取其中的ActivityInfo,即我們即將要啟動(dòng)的Activity信息
ActivityInfo aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, profilerInfo);
.... 代碼省略
ActivityOptions options = ActivityOptions.fromBundle(bOptions);
.... 代碼省略
.... 代碼省略
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, inTask,
reason);
...代碼省略
return res;
}
}
inTask上面?zhèn)鬟f過來是null,這里注意下
這個(gè)方法的作用就是解析Intent,得到將要啟動(dòng)的Activity的信息,解析的過程是在PMS中進(jìn)行的,這里也就不再多說,感興趣同學(xué)的可以進(jìn)去看看。最后調(diào)用了startActivityLocked() -> startActivity() 。
// 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, TaskRecord inTask) {
// 初始化err的值
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) {
// 獲取執(zhí)行啟動(dòng)的Activty所對(duì)應(yīng)的ProcessRecord,在AMS中保存著一個(gè)ProcessRecord集合,存放著所有運(yùn)行中的進(jìn)程
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;
}
}
final int userId = aInfo != 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;
ActivityRecord resultRecord = null;
if (resultTo != null) {
// 從ActivityStackSupervisor中遍歷所有的棧中的所有ActivityRecord,找到與之對(duì)應(yīng)的ActivityRecord,
// 這里返回的也就是執(zhí)行啟動(dòng)的Activity所對(duì)應(yīng)的ActivityRecord
sourceRecord = mSupervisor.isInAnyStackLocked(resultTo);
if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
"Will send result to " + resultTo + " " + sourceRecord);
if (sourceRecord != null) {
// 如果需要返回信息到原Activity 則將原Activity對(duì)應(yīng)的ActivityRecord賦值給resultRecord
if (requestCode >= 0 && !sourceRecord.finishing) {
resultRecord = sourceRecord;
}
}
}
// ... 代碼省略
// 獲取原Activity對(duì)應(yīng)的ActivityStatck
final ActivityStack resultStack = resultRecord == null ? null : resultRecord.getStack();
// 如果上面哪里執(zhí)行錯(cuò)誤,就會(huì)進(jìn)入這個(gè)判斷,通過ActivityStack.sendActivityResultLocked將原Actiivty執(zhí)行暫停操作
if (err != START_SUCCESS) {
if (resultRecord != null) {
resultStack.sendActivityResultLocked(
-1, resultRecord, resultWho, requestCode, RESULT_CANCELED, null);
}
ActivityOptions.abort(options);
return err;
}
boolean abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
requestCode, callingPid, callingUid, callingPackage, ignoreTargetSecurity, callerApp,
resultRecord, resultStack, options);
abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
callingPid, resolvedType, aInfo.applicationInfo);
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.setStates(userId, realCallingPid, realCallingUid, startFlags, callingPackage);
mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, callingPid, callingUid,
options);
intent = mInterceptor.mIntent;
rInfo = mInterceptor.mRInfo;
aInfo = mInterceptor.mAInfo;
resolvedType = mInterceptor.mResolvedType;
inTask = mInterceptor.mInTask;
callingPid = mInterceptor.mCallingPid;
callingUid = mInterceptor.mCallingUid;
options = mInterceptor.mActivityOptions;
if (abort) {
if (resultRecord != null) {
resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode,
RESULT_CANCELED, null);
}
// We pretend to the caller that it was really started, but
// they will just get a cancel result.
ActivityOptions.abort(options);
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.
if (mService.mPermissionReviewRequired && aInfo != null) {
if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(
aInfo.packageName, userId)) {
IIntentSender target = mService.getIntentSenderLocked(
ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
callingUid, userId, null, null, 0, new Intent[]{intent},
new String[]{resolvedType}, PendingIntent.FLAG_CANCEL_CURRENT
| PendingIntent.FLAG_ONE_SHOT, null);
final int flags = intent.getFlags();
Intent newIntent = new Intent(Intent.ACTION_REVIEW_PERMISSIONS);
newIntent.setFlags(flags
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
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;
resolvedType = null;
callingUid = realCallingUid;
callingPid = realCallingPid;
rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId);
aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags,
null /*profilerInfo*/);
if (DEBUG_PERMISSIONS_REVIEW) {
Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true,
true, false) + "} from uid " + callingUid + " on display "
+ (mSupervisor.mFocusedStack == null
? DEFAULT_DISPLAY : mSupervisor.mFocusedStack.mDisplayId));
}
}
}
// 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) {
intent = createLaunchIntent(rInfo.auxiliaryInfo, ephemeralIntent,
callingPackage, verificationBundle, resolvedType, userId);
resolvedType = null;
callingUid = realCallingUid;
callingPid = realCallingPid;
// 從ResultInfo中獲取到對(duì)應(yīng)的ActivityInfo
aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, null /*profilerInfo*/);
}
// 創(chuàng)建一個(gè)包含被啟動(dòng)Activity信息的ActivityRecord
// 里面包含有AM,執(zhí)行啟動(dòng)的Actiivty的進(jìn)程信息、包名,被啟動(dòng)Activity的ActivityInfo等等
ActivityRecord r = new ActivityRecord(mService, callerApp, callingPid, callingUid,
callingPackage, intent, resolvedType, aInfo, mService.getGlobalConfiguration(),
resultRecord, resultWho, requestCode, componentSpecified, voiceSession != null,
mSupervisor, options, sourceRecord);
if (outActivity != null) {
outActivity[0] = 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;
}
// 獲取到目前獲取到焦點(diǎn)的棧
final ActivityStack stack = mSupervisor.mFocusedStack;
// 如果此棧中的的mResumedActivity == null(mResumedActivity 此時(shí)應(yīng)該為執(zhí)行啟動(dòng)的Activity)
// 或者mResumedActivity不等于執(zhí)行啟動(dòng)的Activity,就會(huì)暫時(shí)取消啟動(dòng) ,將要啟動(dòng)的Activity加入到等待隊(duì)列中,
// 也就是mPendingActivityLaunches中
if (voiceSession == null && (stack.mResumedActivity == null
|| stack.mResumedActivity.info.applicationInfo.uid != callingUid)) {
if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
realCallingPid, realCallingUid, "Activity start")) {
PendingActivityLaunch pal = new PendingActivityLaunch(r,
sourceRecord, startFlags, stack, callerApp);
mPendingActivityLaunches.add(pal);
ActivityOptions.abort(options);
return ActivityManager.START_SWITCHES_CANCELED;
}
}
if (mService.mDidAppSwitch) {
// This is the second allowed switch since we stopped switches,
// so now just generally allow switches. Use case: user presses
// home (switches disabled, switch to home, mDidAppSwitch now true);
// user taps a home icon (coming from home so allowed, we hit here
// and now allow anyone to switch again).
mService.mAppSwitchesAllowedTime = 0;
} else {
mService.mDidAppSwitch = true;
}
// 這個(gè)方法是執(zhí)行等待隊(duì)列中的需要被啟動(dòng)的Activity,
doPendingActivityLaunchesLocked(false);
// 這里是執(zhí)行啟動(dòng)的入口,當(dāng)然doPendingActivityLaunchesLocked()也會(huì)調(diào)用此方法
// 不同的地方就是這里傳的 doResume = true,而上面的那個(gè)方法傳的是false
return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
options, inTask, outActivity);
}
這個(gè)方法比較長(zhǎng),下面的流程中還有幾個(gè)方法也比較長(zhǎng),處處是坑,一不小心就跑偏了,真是看得頭疼
ActivityStarter#doPendingActivityLaunchesLocked
final void doPendingActivityLaunchesLocked(boolean doResume) {
// 遍歷等待隊(duì)列中的等待被啟動(dòng)的Activity信息,然后逐個(gè)啟動(dòng)
while (!mPendingActivityLaunches.isEmpty()) {
final PendingActivityLaunch pal = mPendingActivityLaunches.remove(0);
final boolean resume = doResume && mPendingActivityLaunches.isEmpty();
try {
startActivity(pal.r, pal.sourceRecord, null, null, pal.startFlags, resume, null,
null, null /*outRecords*/);
} catch (Exception e) {
Slog.e(TAG, "Exception during pending activity launch pal=" + pal, e);
pal.sendErrorResult(e.getMessage());
}
}
}
我們繼續(xù)往下看 ActivityStarter#startActivity -> startActivityUnchecked,又是一個(gè)特別長(zhǎng)的方法
3)為需要被啟動(dòng)的Activity設(shè)置棧信息
private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
ActivityRecord[] outActivity) {
// 初始化操作
setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
voiceInteractor);
// 解析啟動(dòng)模式
computeLaunchingTaskFlags();
// 獲取原activity對(duì)應(yīng)的ActivityStack
computeSourceStack();
mIntent.setFlags(mLaunchFlags);
// 復(fù)用ActivtiyRecord
ActivityRecord reusedActivity = getReusableIntentActivity();
final int preferredLaunchStackId =
(mOptions != null) ? mOptions.getLaunchStackId() : INVALID_STACK_ID;
final int preferredLaunchDisplayId =
(mOptions != null) ? mOptions.getLaunchDisplayId() : DEFAULT_DISPLAY;
if (reusedActivity != null) {
// 如果得到的復(fù)用的AcitivtyRecord不為空 , 就為即將啟動(dòng)的Activity所對(duì)應(yīng)的ActivityRecord設(shè)置task
// 為復(fù)用的ActivityRecord對(duì)應(yīng)的task信息
// When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused but
// still needs to be a lock task mode violation since the task gets cleared out and
// the device would otherwise leave the locked task.
if (mSupervisor.isLockTaskModeViolation(reusedActivity.getTask(),
(mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) {
mSupervisor.showLockTaskToast();
Slog.e(TAG, "startActivityUnchecked: Attempt to violate Lock Task Mode");
return START_RETURN_LOCK_TASK_MODE_VIOLATION;
}
if (mStartActivity.getTask() == null) {
// 為需要被啟動(dòng)的Activity設(shè)置棧信息
mStartActivity.setTask(reusedActivity.getTask());
}
if (reusedActivity.getTask().intent == null) {
// This task was started because of movement of the activity based on affinity...
// Now that we are actually launching it, we can assign the base intent.
reusedActivity.getTask().setIntent(mStartActivity);
}
// This code path leads to delivering a new intent, we want to make sure we schedule it
// as the first operation, in case the activity will be resumed as a result of later
// operations.
// 如果設(shè)置了FLAG_ACTIVITY_CLEAR_TOP這個(gè)標(biāo)志,并且Activty的啟動(dòng)模式為SIGNLETASK或SINGLEINSTANCE,
// 在啟動(dòng)Activity的時(shí)候,如果在Activity歷史棧中找到了與之一樣的Activity,就會(huì)將舊的Activity上面的其他
// Activity執(zhí)行出棧操作,并將此Activity至于棧頂,同時(shí)調(diào)用onNewIntent方法
if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
|| isDocumentLaunchesIntoExisting(mLaunchFlags)
|| mLaunchSingleInstance || mLaunchSingleTask) {
final TaskRecord task = reusedActivity.getTask();
// In this situation we want to remove all activities from the task up to the one
// being started. In most cases this means we are resetting the task to its initial
// state.
// 執(zhí)行清除棧的操作 并返回棧中與之一樣的ActivityReocrd
final ActivityRecord top = task.performClearTaskForReuseLocked(mStartActivity,
mLaunchFlags);
// The above code can remove {@code reusedActivity} from the task, leading to the
// the {@code ActivityRecord} removing its reference to the {@code TaskRecord}. The
// task reference is needed in the call below to
// {@link setTargetStackAndMoveToFrontIfNeeded}.
if (reusedActivity.getTask() == null) {
reusedActivity.setTask(task);
}
if (top != null) {
if (top.frontOfTask) {
// Activity aliases may mean we use different intents for the top activity,
// so make sure the task now has the identity of the new intent.
top.getTask().setIntent(mStartActivity);
}
// 調(diào)用onNewIntent方法
deliverNewIntent(top);
}
}
sendPowerHintForLaunchStartIfNeeded(false /* forceSend */, reusedActivity);
// 將復(fù)用的ActivityRecord對(duì)應(yīng)的ActivityStack移動(dòng)到前臺(tái)(此時(shí)當(dāng)前獲取到焦點(diǎn)的棧為此Activity所對(duì)應(yīng)的棧 )
reusedActivity = setTargetStackAndMoveToFrontIfNeeded(reusedActivity);
final ActivityRecord outResult =
outActivity != null && outActivity.length > 0 ? outActivity[0] : null;
// When there is a reused activity and the current result is a trampoline activity,
// set the reused activity as the result.
if (outResult != null && (outResult.finishing || outResult.noDisplay)) {
outActivity[0] = reusedActivity;
}
// 如果設(shè)置了START_RETURN_INTENT_TO_CALLER 那么直接調(diào)用該Activity的onResume 而不需要重新啟動(dòng)
if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
// We don't need to start a new activity, and the client said not to do anything
// if that is the case, so this is it! And for paranoia, make sure we have
// correctly resumed the top activity.
resumeTargetStackIfNeeded();
return START_RETURN_INTENT_TO_CALLER;
}
setTaskFromIntentActivity(reusedActivity);
// 如果設(shè)置了SINGLETASK/SINGLEINSTANCE 那么也不需要重新啟動(dòng)Activity,直接調(diào)用其onResume
if (!mAddingToTask && mReuseTask == null) {
// We didn't do anything... but it was needed (a.k.a., client don't use that
// intent!) And for paranoia, make sure we have correctly resumed the top activity.
resumeTargetStackIfNeeded();
if (outActivity != null && outActivity.length > 0) {
outActivity[0] = reusedActivity;
}
return START_TASK_TO_FRONT;
}
}
if (mStartActivity.packageName == null) {
final ActivityStack sourceStack = mStartActivity.resultTo != null
? mStartActivity.resultTo.getStack() : null;
if (sourceStack != null) {
// 這里是執(zhí)行啟動(dòng)的Activity執(zhí)行onPause操作
sourceStack.sendActivityResultLocked(-1 /* callingUid */, mStartActivity.resultTo,
mStartActivity.resultWho, mStartActivity.requestCode, RESULT_CANCELED,
null /* data */);
}
ActivityOptions.abort(mOptions);
return START_CLASS_NOT_FOUND;
}
// 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.
final ActivityStack topStack = mSupervisor.mFocusedStack;
final ActivityRecord topFocused = topStack.topActivity();
final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);
final boolean dontStart = top != null && mStartActivity.resultTo == null
&& top.realActivity.equals(mStartActivity.realActivity)
&& top.userId == mStartActivity.userId
&& top.app != null && top.app.thread != null
&& ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
|| mLaunchSingleTop || mLaunchSingleTask);
if (dontStart) {
// For paranoia, make sure we have correctly resumed the top activity.
topStack.mLastPausedActivity = null;
// 上面說了 傳入的doResume == true,雖然在setInitialState進(jìn)行了初始化 但還是為true
if (mDoResume) {
// 這個(gè)方法有點(diǎn)繞 后面再說
mSupervisor.resumeFocusedStackTopActivityLocked();
}
ActivityOptions.abort(mOptions);
if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
// We don't need to start a new activity, and the client said not to do
// anything if that is the case, so this is it!
return START_RETURN_INTENT_TO_CALLER;
}
// 如果將要啟動(dòng)的Activity是SINGLTOP模式的 并且當(dāng)前執(zhí)行啟動(dòng)的Activity與要被啟動(dòng)的一致 那么調(diào)用其onNewIntent方法
deliverNewIntent(top);
// Don't use mStartActivity.task to show the toast. We're not starting a new activity
// but reusing 'top'. Fields in mStartActivity may not be fully initialized.
mSupervisor.handleNonResizableTaskIfNeeded(top.getTask(), preferredLaunchStackId,
preferredLaunchDisplayId, topStack.mStackId);
return START_DELIVERED_TO_TOP;
}
boolean newTask = false;
final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
? mSourceRecord.getTask() : null;
// Should this be considered a new task?
int result = START_SUCCESS;
// 這里是為要被啟動(dòng)的Activity設(shè)置一個(gè)ActivityStack,并指定給mTargetStack
if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
&& (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
newTask = true;
// 這里是創(chuàng)建一個(gè)新的TaskRecord
result = setTaskFromReuseOrCreateNewTask(
taskToAffiliate, preferredLaunchStackId, topStack);
} else if (mSourceRecord != null) {
// 設(shè)置與啟動(dòng)Activity一樣的棧
result = setTaskFromSourceRecord();
} else if (mInTask != null) {
result = setTaskFromInTask();
} else {
// This not being started from an existing activity, and not part of a new task...
// just put it in the top task, though these days this case should never happen.
setTaskToCurrentTopOrCreateNewTask();
}
if (result != START_SUCCESS) {
return result;
}
mService.grantUriPermissionFromIntentLocked(mCallingUid, mStartActivity.packageName,
mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.userId);
mService.grantEphemeralAccessLocked(mStartActivity.userId, mIntent,
mStartActivity.appInfo.uid, UserHandle.getAppId(mCallingUid));
if (mSourceRecord != null) {
mStartActivity.getTask().setTaskToReturnTo(mSourceRecord);
}
if (newTask) {
EventLog.writeEvent(
EventLogTags.AM_CREATE_TASK, mStartActivity.userId,
mStartActivity.getTask().taskId);
}
ActivityStack.logStartActivity(
EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.getTask());
mTargetStack.mLastPausedActivity = null;
sendPowerHintForLaunchStartIfNeeded(false /* forceSend */, mStartActivity);
// 這里可以暫且理解為為新Activity設(shè)置statck
mTargetStack.startActivityLocked(mStartActivity, topFocused, newTask, mKeepCurTransition,
mOptions);
if (mDoResume) {
final ActivityRecord topTaskActivity =
mStartActivity.getTask().topRunningActivityLocked();
if (!mTargetStack.isFocusable()
|| (topTaskActivity != null && topTaskActivity.mTaskOverlay
&& 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.
mTargetStack.ensureActivitiesVisibleLocked(null, 0, !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.
mWindowManager.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.
if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) {
// 將目標(biāo)棧移動(dòng)到前臺(tái) 即設(shè)置為可以獲取到焦點(diǎn)的棧
mTargetStack.moveToFront("startActivityUnchecked");
}
// 通常都會(huì)走到這里
mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
mOptions);
}
} else {
mTargetStack.addRecentActivityLocked(mStartActivity);
}
mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(), preferredLaunchStackId,
preferredLaunchDisplayId, mTargetStack.mStackId);
return START_SUCCESS;
}
這個(gè)方法很長(zhǎng),也很繞,我們一點(diǎn)點(diǎn)來說
- setInitialState()是初始化參數(shù)
mStartActivity為我們要啟動(dòng)的Activity所代表的ActivityRecord
mSourceRecord為我們執(zhí)行啟動(dòng)的Activity所代表的ActivityRecord
mDoResume值為true - getReusableIntentActivity()查找有沒有可以替代需要被啟動(dòng)的Activity的Activity
// ActivityStarter#getReusableIntentActivity:
private ActivityRecord getReusableIntentActivity() {
// We may want to try to place the new activity in to an existing task. We always
// do this if the target activity is singleTask or singleInstance; we will also do
// this if NEW_TASK has been requested, and there is not an additional qualifier telling
// us to still place it in a new task: multi task, always doc mode, or being asked to
// launch this as a new task behind the current one.
boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
(mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
|| mLaunchSingleInstance || mLaunchSingleTask;
// If bring to front is requested, and no result is requested and we have not been given
// an explicit task to launch in to, and we can find a task that was started with this
// same component, then instead of launching bring that one to the front.
putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
ActivityRecord intentActivity = null;
if (mOptions != null && mOptions.getLaunchTaskId() != -1) {
// 這個(gè)分支一般不會(huì)進(jìn)入,mOptions就是我們開篇說到的ActivityOptions,不為空,但是只有當(dāng)明確知道將要啟動(dòng)的Activity在那個(gè)具體的task中才會(huì)為L(zhǎng)anucherTaskId設(shè)置值,一般情況為-1;
final TaskRecord task = mSupervisor.anyTaskForIdLocked(mOptions.getLaunchTaskId());
intentActivity = task != null ? task.getTopActivity() : null;
} else if (putIntoExistingTask) {
if (mLaunchSingleInstance) {
// 對(duì)應(yīng)SIGNLEINSTANCE 這里會(huì)在所有的stack中以及其所有的task以及其中的activity
// There can be one and only one instance of single instance activity in the
// history, and it is always in its own unique task, so we do a special search.
intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info,
mStartActivity.isHomeActivity());
} else if ((mLaunchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) != 0) {
//這個(gè)用在多窗口的分屏中,指定顯示activity挨著打開這個(gè)activity的旁邊
// For the launch adjacent case we only want to put the activity in an existing
// task if the activity already exists in the history.
intentActivity = mSupervisor.findActivityLocked(mIntent, mStartActivity.info,
!mLaunchSingleTask);
} else {
// 遍歷所有的stack里面的每個(gè)task,找到其top的Activity,并于即將要啟動(dòng)的Activity做比較
// Otherwise find the best task to put the activity in.
intentActivity = mSupervisor.findTaskLocked(mStartActivity, mSourceDisplayId);
}
}
return intentActivity;
}
我們先來看findActivityLocked
// ActivityStackSupervisor#findActivityLocked
ActivityRecord findActivityLocked(Intent intent, ActivityInfo info,
boolean compareIntentFilters) {
// 遍歷ActivityDisplays集合中的所有ActivityStack集合
// 得到每一個(gè)ActivityStack,然后再去與其中儲(chǔ)存的ActivityRecord進(jìn)行對(duì)比
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityRecord ar = stacks.get(stackNdx)
.findActivityLocked(intent, info, compareIntentFilters);
if (ar != null) {
return ar;
}
}
}
return null;
}
// ActivityStack#findActivityLocked
ActivityRecord findActivityLocked(Intent intent, ActivityInfo info,
boolean compareIntentFilters) {
ComponentName cls = intent.getComponent();
if (info.targetActivity != null) {
cls = new ComponentName(info.packageName, info.targetActivity);
}
final int userId = UserHandle.getUserId(info.applicationInfo.uid);
// 遍歷ActivityStack中的歷史棧TaskRecord,將得到的ActivityRecord與歷史棧中的ActivityRecord進(jìn)行對(duì)比
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = mTaskHistory.get(taskNdx);
final ArrayList<ActivityRecord> activities = task.mActivities;
for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
ActivityRecord r = activities.get(activityNdx);
if (!r.okToShowLocked()) {
continue;
}
// 如果歷史棧中的Activity沒有被銷毀,并且是同一用戶空間(針對(duì)Android的多用戶模式,這里可以忽略)
if (!r.finishing && r.userId == userId) {
if (compareIntentFilters) {
// 然后將兩者的Intent信息進(jìn)行比較,如果相同則返回如果不相同則繼續(xù)遍歷
if (r.intent.filterEquals(intent)) {
return r;
}
} else {
if (r.intent.getComponent().equals(cls)) {
return r;
}
}
}
}
}
return null;
}
// 具體比較的Intent信息如下,我們都知道隱式啟動(dòng)Activity會(huì)傳入Action、Data、Categories等,所以這里比較的就是這些數(shù)據(jù)
public boolean filterEquals(Intent other) {
if (other == null) {
return false;
}
if (!Objects.equals(this.mAction, other.mAction)) return false;
if (!Objects.equals(this.mData, other.mData)) return false;
if (!Objects.equals(this.mType, other.mType)) return false;
if (!Objects.equals(this.mPackage, other.mPackage)) return false;
if (!Objects.equals(this.mComponent, other.mComponent)) return false;
if (!Objects.equals(this.mCategories, other.mCategories)) return false;
return true;
}
我們?cè)賮砜醋詈笠粋€(gè)else中的ActivityStackSupervisor#findTaskLocked
ActivityRecord findTaskLocked(ActivityRecord r, int displayId) {
mTmpFindTaskResult.r = null;
mTmpFindTaskResult.matchedByRootAffinity = false;
ActivityRecord affinityMatch = null;
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + r);
// 首先也是遍歷ActivityDisplays集合,得到其中的ActivityStack集合,然后再繼續(xù)遍歷ActivityStack集合
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
if (!checkActivityBelongsInStack(r, stack)) {
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping stack: (mismatch activity/stack) "
+ stack);
continue;
}
// 對(duì)遍歷到的每一個(gè)Stack調(diào)用其findTaskLocked()
stack.findTaskLocked(r, mTmpFindTaskResult);
// It is possible to have tasks in multiple stacks with the same root affinity, so
// we should keep looking after finding an affinity match to see if there is a
// better match in another stack. Also, task affinity isn't a good enough reason
// to target a display which isn't the source of the intent, so skip any affinity
// matches not on the specified display.
if (mTmpFindTaskResult.r != null) {
if (!mTmpFindTaskResult.matchedByRootAffinity) {
return mTmpFindTaskResult.r;
} else if (mTmpFindTaskResult.r.getDisplayId() == displayId) {
// Note: since the traversing through the stacks is top down, the floating
// tasks should always have lower priority than any affinity-matching tasks
// in the fullscreen stacks
affinityMatch = mTmpFindTaskResult.r;
}
}
}
}
if (DEBUG_TASKS && affinityMatch == null) Slog.d(TAG_TASKS, "No task found");
return affinityMatch;
}
// ActivityStack#findTaskLocked
void findTaskLocked(ActivityRecord target, FindTaskResult result) {
Intent intent = target.intent;
ActivityInfo info = target.info;
ComponentName cls = intent.getComponent();
if (info.targetActivity != null) {
cls = new ComponentName(info.packageName, info.targetActivity);
}
final int userId = UserHandle.getUserId(info.applicationInfo.uid);
boolean isDocument = intent != null & intent.isDocument();
// If documentData is non-null then it must match the existing task data.
Uri documentData = isDocument ? intent.getData() : null;
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Looking for task of " + target + " in " + this);
// 遍歷ActivityStack中的TaskRecord集合,
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord task = mTaskHistory.get(taskNdx);
if (task.voiceSession != null) {
// We never match voice sessions; those always run independently.
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": voice session");
continue;
}
if (task.userId != userId) {
// Looking for a different task.
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": different user");
continue;
}
// Overlays should not be considered as the task's logical top activity.
// 得到TaskRecord集中的頂部Activity 并與將要啟動(dòng)的Activity做比較
final ActivityRecord r = task.getTopActivity(false /* includeOverlays */);
if (r == null || r.finishing || r.userId != userId ||
r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": mismatch root " + r);
continue;
}
if (r.mActivityType != target.mActivityType) {
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Skipping " + task + ": mismatch activity type");
continue;
}
final Intent taskIntent = task.intent;
final Intent affinityIntent = task.affinityIntent;
final boolean taskIsDocument;
final Uri taskDocumentData;
if (taskIntent != null && taskIntent.isDocument()) {
taskIsDocument = true;
taskDocumentData = taskIntent.getData();
} else if (affinityIntent != null && affinityIntent.isDocument()) {
taskIsDocument = true;
taskDocumentData = affinityIntent.getData();
} else {
taskIsDocument = false;
taskDocumentData = null;
}
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Comparing existing cls="
+ taskIntent.getComponent().flattenToShortString()
+ "/aff=" + r.getTask().rootAffinity + " to new cls="
+ intent.getComponent().flattenToShortString() + "/aff=" + info.taskAffinity);
// TODO Refactor to remove duplications. Check if logic can be simplified.
// 然后比較兩者的Component,如果相同則賦值給result,因?yàn)樵趂indTaskLocked中會(huì)用到
if (taskIntent != null && taskIntent.getComponent() != null &&
taskIntent.getComponent().compareTo(cls) == 0 &&
Objects.equals(documentData, taskDocumentData)) {
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching class!");
//dump();
if (DEBUG_TASKS) Slog.d(TAG_TASKS,
"For Intent " + intent + " bringing to top: " + r.intent);
result.r = r;
result.matchedByRootAffinity = false;
break;
} else if (affinityIntent != null && affinityIntent.getComponent() != null &&
affinityIntent.getComponent().compareTo(cls) == 0 &&
Objects.equals(documentData, taskDocumentData)) {
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching class!");
//dump();
if (DEBUG_TASKS) Slog.d(TAG_TASKS,
"For Intent " + intent + " bringing to top: " + r.intent);
result.r = r;
result.matchedByRootAffinity = false;
break;
} else if (!isDocument && !taskIsDocument
&& result.r == null && task.rootAffinity != null) {
if (task.rootAffinity.equals(target.taskAffinity)) {
if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Found matching affinity candidate!");
// It is possible for multiple tasks to have the same root affinity especially
// if they are in separate stacks. We save off this candidate, but keep looking
// to see if there is a better candidate.
result.r = r;
result.matchedByRootAffinity = true;
}
} else if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Not a match: " + task);
}
}
// ComponentName#compareTo
public int compareTo(ComponentName that) {
int v;
// 主要是比較包名和類名 如果兩者相同則返回0
v = this.mPackage.compareTo(that.mPackage);
if (v != 0) {
return v;
}
return this.mClass.compareTo(that.mClass);
}
我們來捋一下getReusableIntentActivity():
getReusableIntentActivity()總的來說是查找歷史棧中是否存在與需要被啟動(dòng)的Activity一樣的Activity,如果有則直接返回復(fù)用,沒有則返回null。(復(fù)用的意思就是不會(huì)重新創(chuàng)建,而是直接跳轉(zhuǎn)到)
1)首先對(duì)于SINGLEINSTANCE類型的Activity,需要遍歷所有的ActivityStack中的所有TaskRecord中的ActivityRecord,如果某一個(gè)ActivityRecord中的Intent中的Action、Data、Categories等相同,則認(rèn)定為是同一個(gè)ActivityRecord,可以復(fù)用
2)對(duì)于SIGNTOP類型的Activity來說會(huì)遍歷TaskRecord找到其頂部的ActivityRecord,并與需要被啟動(dòng)的Activity對(duì)比類名和包名,如果相同則返回
(貌似拉下了singleTask的情況,按理說對(duì)于singleTask類型,應(yīng)該也會(huì)類似于single Instance所有的棧進(jìn)行遍歷,但是前面卻加了判斷是否是single Instace的情況,那就是在else里面,但是最后else卻是只取棧頂?shù)腶ctivityrecord,所以我感覺應(yīng)該是如果single Instance,那么必定為single Task)
好了我們返回ActivityStarter#startActivityUnchecked()中繼續(xù)看
- 如果找到了復(fù)用的ActivityReocrd(下面的幾點(diǎn)都是針對(duì)如果有找到了復(fù)用的activity來說的)
1)先是將復(fù)用的ActivityRecord中的信息賦值到等待被啟動(dòng)的ActivityRecord中,比如說棧、intent等,然后將此棧移動(dòng)到前臺(tái),也就是獲取到焦點(diǎn)
2)往下繼續(xù)就會(huì)調(diào)用setTaskFromIntentActivity(),入?yún)閺?fù)用的Activity
private void setTaskFromIntentActivity(ActivityRecord intentActivity) {
if ((mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
// 好多標(biāo)識(shí)雖然看不懂但是通過注釋和FLAG_ACTIVITY_NEW_TASK ,我們可以判斷如果是要開啟一個(gè)新的任務(wù)棧
// 就會(huì)進(jìn)入這個(gè)方法
// The caller has requested to completely replace any existing task with its new
// activity. Well that should not be too hard...
// Note: we must persist the {@link TaskRecord} first as intentActivity could be
// removed from calling performClearTaskLocked (For example, if it is being brought out
// of history or if it is finished immediately), thus disassociating the task. Also note
// that mReuseTask is reset as a result of {@link TaskRecord#performClearTaskLocked}
// launching another activity.
// TODO(b/36119896): We shouldn't trigger activity launches in this path since we are
// already launching one.
final TaskRecord task = intentActivity.getTask();
// 這里會(huì)將此任務(wù)棧中的所有ActivityRecord清除掉 代碼就不貼了
task.performClearTaskLocked();
mReuseTask = task;
mReuseTask.setIntent(mStartActivity);
// When we clear the task - focus will be adjusted, which will bring another task
// to top before we launch the activity we need. This will temporary swap their
// mTaskToReturnTo values and we don't want to overwrite them accidentally.
mMovedOtherTask = true;
} else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
|| mLaunchSingleInstance || mLaunchSingleTask) {
// 如果是single instance 或者是singletask 也會(huì)清除掉任務(wù)棧中的AcitivityRecord,但是只清除此ActivityRecord頂部的ActivityRecord 代碼就不貼了
ActivityRecord top = intentActivity.getTask().performClearTaskLocked(mStartActivity,
mLaunchFlags);
if (top == null) {
// A special case: we need to start the activity because it is not currently
// running, and the caller has asked to clear the current task to have this
// activity at the top.
mAddingToTask = true;
// We are no longer placing the activity in the task we previously thought we were.
mStartActivity.setTask(null);
// Now pretend like this activity is being started by the top of its task, so it
// is put in the right place.
mSourceRecord = intentActivity;
final TaskRecord task = mSourceRecord.getTask();
if (task != null && task.getStack() == null) {
// Target stack got cleared when we all activities were removed above.
// Go ahead and reset it.
mTargetStack = computeStackFocus(mSourceRecord, false /* newTask */,
null /* bounds */, mLaunchFlags, mOptions);
mTargetStack.addTask(task,
!mLaunchTaskBehind /* toTop */, "startActivityUnchecked");
}
}
} else if (mStartActivity.realActivity.equals(intentActivity.getTask().realActivity)) {
// In this case the top activity on the task is the same as the one being launched,
// so we take that as a request to bring the task to the foreground. If the top
// activity in the task is the root activity, deliver this new intent to it if it
// desires.
// 如果棧頂?shù)腁ctivityRecord與需要被啟動(dòng)的Actiivty一致
if (((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 || mLaunchSingleTop)
&& intentActivity.realActivity.equals(mStartActivity.realActivity)) {
// 并如果是singtop類型的
if (intentActivity.frontOfTask) {
intentActivity.getTask().setIntent(mStartActivity);
}
會(huì)調(diào)用其onNewIntent方法
deliverNewIntent(intentActivity);
} else if (!intentActivity.getTask().isSameIntentFilter(mStartActivity)) {
// In this case we are launching the root activity of the task, but with a
// different intent. We should start a new instance on top.
mAddingToTask = true;
mSourceRecord = intentActivity;
}
} else if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
// In this case an activity is being launched in to an existing task, without
// resetting that task. This is typically the situation of launching an activity
// from a notification or shortcut. We want to place the new activity on top of the
// current task.
mAddingToTask = true;
mSourceRecord = intentActivity;
} else if (!intentActivity.getTask().rootWasReset) {
// In this case we are launching into an existing task that has not yet been started
// from its front door. The current task has been brought to the front. Ideally,
// we'd probably like to place this new task at the bottom of its stack, but that's
// a little hard to do with the current organization of the code so for now we'll
// just drop it.
intentActivity.getTask().setIntent(mStartActivity);
}
}
3)在往下就會(huì)調(diào)用ActivityStackSupervisor#resumeFocusedStackTopActivityLocked去進(jìn)行啟動(dòng)這個(gè)放到后面再說
以上就是有復(fù)用ActivityRecord的情況,我們繼續(xù)分析startActivityUnchecked(),
- 獲取當(dāng)前由焦點(diǎn)的棧,以及此棧棧頂?shù)腁ctivityRecord,并判斷是否與執(zhí)行啟動(dòng)的ActivityRecord相同(一般都是同一個(gè)),并且如果是singletop/singleInstance/singleTask標(biāo)識(shí),會(huì)調(diào)用ActivityStackSupervisor#resumeFocusedStackTopActivityLocked(這個(gè)放在后面分析)并且會(huì)調(diào)用其onNewIntent(),然后結(jié)束返回;
*如果即沒有可復(fù)用的ActivityRecord,并且啟動(dòng)模式也不是singtop,那么就需要我們新建一個(gè)task棧或者找到一個(gè)該activity所需要的棧
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 {
// This not being started from an existing activity, and not part of a new task...
// just put it in the top task, though these days this case should never happen.
setTaskToCurrentTopOrCreateNewTask();
}
(棧的創(chuàng)建,會(huì)放在文末來說)
上面的判斷,如果沒有設(shè)置返回?cái)?shù)據(jù)的activity并且inTask == null 以及有FLAG_ACTIVITY_NEW_TASK那我們就需要?jiǎng)?chuàng)建一個(gè)新棧,否則就根據(jù)相應(yīng)的條件判斷,是用啟動(dòng)activity的棧,還是用傳遞進(jìn)來的新棧inStack還是用當(dāng)前頂部的?;蛘邉?chuàng)建一個(gè)新棧,如果是新建一個(gè)TaskRecord就需要將新建的棧保存到ActivityStack中。
- 繼續(xù)往下看
// mDoResume == true
if (mDoResume) {
// 獲取待啟動(dòng)的Activity所在棧的頂部Activity(其實(shí)也就是需要被啟動(dòng)的Activity)
final ActivityRecord topTaskActivity =
mStartActivity.getTask().topRunningActivityLocked();
// 上面說了將此棧移動(dòng)到前臺(tái),也就是獲取到了焦點(diǎn),并且兩個(gè)Activity是同一個(gè),所以會(huì)走else
if (!mTargetStack.isFocusable()
|| (topTaskActivity != null && topTaskActivity.mTaskOverlay
&& 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.
mTargetStack.ensureActivitiesVisibleLocked(null, 0, !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.
mWindowManager.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.
if (mTargetStack.isFocusable() && !mSupervisor.isFocusedStack(mTargetStack)) {
// 這里將ActivityStackSupervisor中的此棧的狀態(tài)設(shè)置為獲取到焦點(diǎn)轉(zhuǎn)臺(tái)
mTargetStack.moveToFront("startActivityUnchecked");
}
mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
mOptions);
}
} else {
mTargetStack.addRecentActivityLocked(mStartActivity);
}
上面在說復(fù)用activity的時(shí)候也談到了resumeFocusedStackTopActivityLocked,singtop模式的時(shí)候也說到了resumeFocusedStackTopActivityLocked,現(xiàn)在這里也用到了,礙于過長(zhǎng)篇幅,簡(jiǎn)書有長(zhǎng)度限制,我們新開一篇來說。本篇就到這里了。