Android 12的源码链接:Searchhttp://aospxref.com/android-12.0.0_r3/
点击桌面图标会进入Launcher应用的click方法中。
private static void onClick(View v) {
// Make sure that rogue clicks don't get through while allapps is launching, or after the
// view has detached (it's possible for this to happen if the view is removed mid touch).
if (v.getWindowToken() == null) return;
Launcher launcher = Launcher.getLauncher(v.getContext());
if (!launcher.getWorkspace().isFinishedSwitchingState()) return;
Object tag = v.getTag();
if (tag instanceof WorkspaceItemInfo) {
onClickAppShortcut(v, (WorkspaceItemInfo) tag, launcher);
} else if (tag instanceof FolderInfo) {
if (v instanceof FolderIcon) {
onClickFolderIcon(v);
}
} else if (tag instanceof AppInfo) {
startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher
);
} else if (tag instanceof LauncherAppWidgetInfo) {
if (v instanceof PendingAppWidgetHostView) {
onClickPendingWidget((PendingAppWidgetHostView) v, launcher);
}
} else if (tag instanceof SearchActionItemInfo) {
onClickSearchAction(launcher, (SearchActionItemInfo) tag);
}
}
往下走
packages/apps/Launcher3/src/com/android/launcher3/touch/ItemClickHandler.java
public static void onClickAppShortcut(View v, WorkspaceItemInfo shortcut, Launcher launcher) {
if (shortcut.isDisabled() && handleDisabledItemClicked(shortcut, launcher)) {
return;
}
// Check for abandoned promise
if ((v instanceof BubbleTextView) && shortcut.hasPromiseIconUi()) {
String packageName = shortcut.getIntent().getComponent() != null
? shortcut.getIntent().getComponent().getPackageName()
: shortcut.getIntent().getPackage();
if (!TextUtils.isEmpty(packageName)) {
onClickPendingAppItem(
v,
launcher,
packageName,
(shortcut.runtimeStatusFlags
& ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0);
return;
}
}
// Start activities
启动activity
startAppShortcutOrInfoActivity(v, shortcut, launcher);
}
继而往下走
packages/apps/Launcher3/src/com/android/launcher3/touch/ItemClickHandler.java
private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher) {
TestLogging.recordEvent(
TestProtocol.SEQUENCE_MAIN, "start: startAppShortcutOrInfoActivity");
Intent intent;
if (item instanceof ItemInfoWithIcon
&& (((ItemInfoWithIcon) item).runtimeStatusFlags
& ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) {//APP未在安装中
ItemInfoWithIcon appInfo = (ItemInfoWithIcon) item;
根据点击的item解析出package name
intent = new PackageManagerHelper(launcher)
.getMarketIntent(appInfo.getTargetComponent().getPackageName());
} else {
根据点击的item得到intent
intent = item.getIntent();
}
if (intent == null) {
throw new IllegalArgumentException("Input must have a valid intent");
}
if (item instanceof WorkspaceItemInfo) {
WorkspaceItemInfo si = (WorkspaceItemInfo) item;
if (si.hasStatusFlag(WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI)
&& Intent.ACTION_VIEW.equals(intent.getAction())) {
// make a copy of the intent that has the package set to null
// we do this because the platform sometimes disables instant
// apps temporarily (triggered by the user) and fallbacks to the
// web ui. This only works though if the package isn't set
intent = new Intent(intent);
intent.setPackage(null);
}
}
if (v != null && launcher.supportsAdaptiveIconAnimation(v)) {
// Preload the icon to reduce latency b/w swapping the floating view with the original.
FloatingIconView.fetchIcon(launcher, v, item, true /* isOpening */);
}
将解析出的intent传入
launcher.startActivitySafely(v, intent, item);
}
继而会走入super的startActivitySafely
packages/apps/Launcher3/src/com/android/launcher3/Launcher.java
@Override
public boolean startActivitySafely(View v, Intent intent, ItemInfo item) {
//判断是否已经resumed
if (!hasBeenResumed()) {
// Workaround an issue where the WM launch animation is clobbered when finishing the
// recents animation into launcher. Defer launching the activity until Launcher is
// next resumed.
解决当完成从最近任务动画进入launcher时WM启动动画被破坏的问题
addOnResumeCallback(() -> startActivitySafely(v, intent, item));
if (mOnDeferredActivityLaunchCallback != null) {
mOnDeferredActivityLaunchCallback.run();
mOnDeferredActivityLaunchCallback = null;
}
return true;
}
进入super的startActivitySafely
boolean success = super.startActivitySafely(v, intent, item);
if (success && v instanceof BubbleTextView) {
// This is set to the view that launched the activity that navigated the user away
// from launcher. Since there is no callback for when the activity has finished
// launching, enable the press state and keep this reference to reset the press
// state when we return to launcher.
BubbleTextView btv = (BubbleTextView) v;
btv.setStayPressed(true);
addOnResumeCallback(() -> btv.setStayPressed(false));
}
return success;
}
继承关系如下: public class Launcher extends StatefulActivity<LauncherState> implements LauncherExterns, Callbacks, InvariantDeviceProfile.OnIDPChangeListener, PluginListener<OverlayPlugin> public abstract class StatefulActivity<STATE_TYPE extends BaseState<STATE_TYPE>> extends BaseDraggingActivity
public abstract class BaseDraggingActivity extends BaseActivity implements OnColorsChangedListener, DisplayInfoChangeListener
最终走入BaseDraggingActivity的startActivitySafely
public boolean startActivitySafely(View v, Intent intent, @Nullable ItemInfo item) {
if (mIsSafeModeEnabled && !PackageManagerHelper.isSystemApp(this, intent)) {
Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
return false;
}
解析得到bundle
Bundle optsBundle = (v != null) ? getActivityLaunchOptions(v, item).toBundle() : null;
UserHandle user = item == null ? null : item.user;
// Prepare intent
添加FLAG_ACTIVITY_NEW_TASK
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (v != null) {
intent.setSourceBounds(getViewBounds(v));
}
try {
boolean isShortcut = (item instanceof WorkspaceItemInfo)
&& (item.itemType == Favorites.ITEM_TYPE_SHORTCUT
|| item.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT)
&& !((WorkspaceItemInfo) item).isPromise();
if (isShortcut) {
// Shortcuts need some special checks due to legacy reasons.
startShortcutIntentSafely(intent, optsBundle, item);
} else if (user == null || user.equals(Process.myUserHandle())) {
// Could be launching some bookkeeping activity
启动activity
startActivity(intent, optsBundle);
} else {
getSystemService(LauncherApps.class).startMainActivity(
intent.getComponent(), user, intent.getSourceBounds(), optsBundle);
}
if (item != null) {
InstanceId instanceId = new InstanceIdSequence().newInstanceId();
logAppLaunch(item, instanceId);
}
return true;
} catch (NullPointerException | 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;
}
然后会调用基类的
frameworks/base/core/java/android/app/Activity.java中的
startActivityForResult方法
frameworks/base/core/java/android/app/Activity.java
@Override
public void startActivity(Intent intent, @Nullable Bundle options) {
if (mIntent != null && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)
&& mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY)) {
if (TextUtils.equals(getPackageName(),
intent.resolveActivity(getPackageManager()).getPackageName())) {
// Apply Autofill restore mechanism on the started activity by startActivity()
final IBinder token =
mIntent.getIBinderExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN);
// Remove restore ability from current activity
mIntent.removeExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN);
mIntent.removeExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY);
// Put restore token
intent.putExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN, token);
intent.putExtra(AutofillManager.EXTRA_RESTORE_CROSS_ACTIVITY, true);
}
}
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);
}
}
然后在当前类中继续往下走,调用startActivityForResult
frameworks/base/core/java/android/app/Activity.java
@Override
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void startActivityForResult(
String who, Intent intent, int requestCode, @Nullable Bundle options) {
Uri referrer = onProvideReferrer();
if (referrer != null) {
intent.putExtra(Intent.EXTRA_REFERRER, referrer);
}
options = transferSpringboardActivityOptions(options);
通过Instrumentation跨进程启动activity
Instrumentation.ActivityResult ar =
mInstrumentation.execStartActivity(
this, mMainThread.getApplicationThread(), mToken, who,
intent, requestCode, options);
if (ar != null) {
mMainThread.sendActivityResult(
mToken, who, requestCode,
ar.getResultCode(), ar.getResultData());
}
cancelInputsAndStartExitTransition(options);
}
然后走到了Instrumentation中,Instrumentation指的是可以用独立于应用程序之外的代理(agent)程序来监测和协助运行在JVM上的应用程序。这种监测和协助包括但不限于获取JVM运行时状态,替换和修改类定义等。
frameworks/base/core/java/android/app/Instrumentation.java
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) {
IApplicationThread whoThread = (IApplicationThread) contextThread;
...
try {
intent.migrateExtraStreamToClipData(who);
intent.prepareToLeaveProcess(who);
获取ATMS的binder对象,通过对象调用startActivity方法
int result = ActivityTaskManager.getService().startActivity(whoThread,
who.getOpPackageName(), who.getAttributionTag(), 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;
}
然后走到了ActivityTaskManager中,通过AIDL获取到了ActivityTaskManagerService的实例
frameworks/base/core/java/android/app/ActivityTaskManager.java
frameworks/base/core/java/android/app/ActivityTaskManager.java
public static IActivityTaskManager getService() {
return IActivityTaskManagerSingleton.get();
}
@UnsupportedAppUsage(trackingBug = 129726065)
private static final Singleton<IActivityTaskManager> IActivityTaskManagerSingleton =
new Singleton<IActivityTaskManager>() {
@Override
protected IActivityTaskManager create() {
获取ACTIVITY_TASK_SERVICE服务
final IBinder b = ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE);
返回Binder实例
return IActivityTaskManager.Stub.asInterface(b);
}
};
------------------------------------------------------------------------------------------------------------------
从这里开始就走进入系统进程SystemServer中的ActivityTaskManagerService服务中。
frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@Override
public final int startActivity(IApplicationThread caller, String callingPackage,
String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
Bundle bOptions) {
return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions,
UserHandle.getCallingUserId());
}
@Override
public int startActivityAsUser(IApplicationThread caller, String callingPackage,
String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
Bundle bOptions, int userId) {
return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions, userId,
true /*validateIncomingUser*/);
}
private int startActivityAsUser(IApplicationThread caller, String callingPackage,
@Nullable String callingFeatureId, Intent intent, String resolvedType,
IBinder resultTo, String resultWho, int requestCode, int startFlags,
ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
assertPackageMatchesCallingUid(callingPackage);
enforceNotIsolatedCaller("startActivityAsUser");
userId = getActivityStartController().checkTargetUser(userId, validateIncomingUser,
Binder.getCallingPid(), Binder.getCallingUid(), "startActivityAsUser");
将相关设置参数等都设置进去
call:发起者context
callPackage:发起者包名
// TODO: Switch to user app stacks here.
return getActivityStartController().obtainStarter(intent, "startActivityAsUser")
.setCaller(caller)
.setCallingPackage(callingPackage)
.setCallingFeatureId(callingFeatureId)
.setResolvedType(resolvedType)
.setResultTo(resultTo)
.setResultWho(resultWho)
.setRequestCode(requestCode)
.setStartFlags(startFlags)
.setProfilerInfo(profilerInfo)
.setActivityOptions(bOptions)
.setUserId(userId)
执行execute
.execute();
}
frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
private ActivityStartController mActivityStartController;
ActivityStartController getActivityStartController() {
return mActivityStartController;
}
ActivityStarter obtainStarter(Intent intent, String reason) {
return mFactory.obtain().setIntent(intent).setReason(reason);
frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
/** * 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() { ... res = resolveToHeavyWeightSwitcherIfNeeded(); if (res != START_SUCCESS) { return res; } res = executeRequest(mRequest); ... }
frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
/** * 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) { ... //初始值 int err = ActivityManager.START_SUCCESS; ... //根据各参数判断当前是否启动失败 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! 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; } ... //设置ActivityRecord的各种信息,ActivityRecord就代表一个activity,可通过ActivityRecord获取activity的各种信息 final ActivityRecord r = new ActivityRecord.Builder(mService) .setCaller(callerApp) .setLaunchedFromPid(callingPid) .setLaunchedFromUid(callingUid) .setLaunchedFromPackage(callingPackage) .setLaunchedFromFeature(callingFeatureId) .setIntent(intent) .setResolvedType(resolvedType) .setActivityInfo(aInfo) .setConfiguration(mService.getGlobalConfiguration()) .setResultTo(resultRecord) .setResultWho(resultWho) .setRequestCode(requestCode) .setComponentSpecified(request.componentSpecified) .setRootVoiceInteraction(voiceSession != null) .setActivityOptions(checkedOptions) .setSourceRecord(sourceRecord) .build(); ... //启动activity mLastStartActivityResult = startActivityUnchecked(r, sourceRecord, voiceSession, request.voiceInteractor, startFlags, true /* doResume */, checkedOptions, inTask, restrictedBgActivity, intentGrants); ...
frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
/** * 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. */ private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord, IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags, boolean doResume, ActivityOptions options, Task inTask, boolean restrictedBgActivity, NeededUriGrants intentGrants) { ... try { //延迟绘制 mService.deferWindowLayout(); Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner"); //start activity result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,startFlags, doResume, options, inTask, restrictedBgActivity, intentGrants); } finally { Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER); startedActivityRootTask = handleStartResult(r, result); //continue绘制 mService.continueWindowLayout(); ...
frameworks/base/services/core/java/com/android/server/wm/ActivityStarter.java
/** * 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 root-task/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); computeLaunchingTaskFlags(); computeSourceRootTask(); mIntent.setFlags(mLaunchFlags); final Task reusedTask = getReusableTask(); ... computeLaunchParams(r, sourceRecord, targetTask); ... mTargetRootTask.startActivityLocked(mStartActivity, topRootTask != null ? topRootTask.getTopNonFinishingActivity() : null, newTask,mKeepCurTransition, mOptions, sourceRecord); if (mDoResume) { final ActivityRecord topTaskActivity = mStartActivity.getTask().topRunningActivityLocked(); if (!mTargetRootTask.isTopActivityFocusable() || (topTaskActivity != null && topTaskActivity.isTaskOverlay() && mStartActivity != topTaskActivity)) { // mTargetRootTask.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, !PRESERVE_WINDOWS); // mTargetRootTask.mDisplayContent.executeAppTransition(); } else { // if (mTargetRootTask.isTopActivityFocusable() && !mRootWindowContainer.isTopDisplayFocusedRootTask(mTargetRootTask)) { mTargetRootTask.moveToFront("startActivityInner"); } mRootWindowContainer.resumeFocusedTasksTopActivities( mTargetRootTask, mStartActivity, mOptions, mTransientLaunch); } } mRootWindowContainer.updateUserRootTask(mStartActivity.mUserId, mTargetRootTask); // Update the recent tasks list immediately when the activity starts mSupervisor.mRecentTasks.add(mStartActivity.getTask()); mSupervisor.handleNonResizableTaskIfNeeded(mStartActivity.getTask(), mPreferredWindowingMode, mPreferredTaskDisplayArea, mTargetRootTask); return START_SUCCESS; }
frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
boolean resumeFocusedTasksTopActivities() { return resumeFocusedTasksTopActivities(null, null, null); } ---------------------------------------------------------------------------------- boolean resumeFocusedTasksTopActivities( Task targetRootTask, ActivityRecord target, ActivityOptions targetOptions) { return resumeFocusedTasksTopActivities(targetRootTask, target, targetOptions, false /* deferPause */); } ---------------------------------------------------------------------------------- boolean resumeFocusedTasksTopActivities( Task targetRootTask, ActivityRecord target, ActivityOptions targetOptions, boolean deferPause) { if (!mTaskSupervisor.readyToResume()) { return false; } boolean result = false; if (targetRootTask != null && (targetRootTask.isTopRootTaskInDisplayArea() || getTopDisplayFocusedRootTask() == targetRootTask)) { result = targetRootTask.resumeTopActivityUncheckedLocked(target, targetOptions, deferPause); } for (int displayNdx = getChildCount() - 1; displayNdx >= 0; --displayNdx) { final DisplayContent display = getChildAt(displayNdx); final boolean curResult = result; boolean[] resumedOnDisplay = new boolean[1]; display.forAllRootTasks(rootTask -> { final ActivityRecord topRunningActivity = rootTask.topRunningActivity(); if (!rootTask.isFocusableAndVisible() || topRunningActivity == null) { return; } if (rootTask == targetRootTask) { // resumedOnDisplay[0] |= curResult; return; } if (rootTask.getDisplayArea().isTopRootTask(rootTask) && topRunningActivity.isState(RESUMED)) { // rootTask.executeAppTransition(targetOptions); } else { resumedOnDisplay[0] |= topRunningActivity.makeActiveIfNeeded(target); } }); result |= resumedOnDisplay[0]; if (!resumedOnDisplay[0]) { // final Task focusedRoot = display.getFocusedRootTask(); if (focusedRoot != null) { result |= focusedRoot.resumeTopActivityUncheckedLocked(target, targetOptions); } else if (targetRootTask == null) { result |= resumeHomeActivity(null /* prev */, "no-focusable-task", display.getDefaultTaskDisplayArea()); } } } return result; }
frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) { return resumeTopActivityUncheckedLocked(prev, options, false /* skipPause */); } ---------------------------------------------------------------------------- boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options, boolean deferPause) { if (mInResumeTopActivity) { // Don't even start recursing. return false; } boolean someActivityResumed = false; try { // Protect against recursion. mInResumeTopActivity = true; if (isLeafTask()) { if (isFocusableAndVisible()) { // someActivityResumed = resumeTopActivityInnerLocked(prev, options, deferPause); } } else { int idx = mChildren.size() - 1; while (idx >= 0) { final Task child = (Task) getChildAt(idx--); if (!child.isTopActivityFocusable()) { continue; } if (child.getVisibility(null /* starting */) != TASK_VISIBILITY_VISIBLE) { break; } someActivityResumed |= child.resumeTopActivityUncheckedLocked(prev, options, deferPause); // if (idx >= mChildren.size()) { idx = mChildren.size() - 1; } } } // final ActivityRecord next = topRunningActivity(true /* focusableOnly */); if (next == null || !next.canTurnScreenOn()) { checkReadyForSleep(); } } finally { mInResumeTopActivity = false; } return someActivityResumed; }
frameworks/base/services/core/java/com/android/server/wm/RootWindowContainer.java
@GuardedBy("mService") private boolean resumeTopActivityInnerLocked(ActivityRecord prev, ActivityOptions options, boolean deferPause) { ... ActivityRecord next = topRunningActivity(true /* focusableOnly */); final boolean hasRunningActivity = next != null; // TODO: Maybe this entire condition can get removed? if (hasRunningActivity && !isAttached()) { return false; } mRootWindowContainer.cancelInitializingActivities(); if (!hasRunningActivity) { // There are no activities left in the root task, let's look somewhere else. return resumeNextFocusableActivityWhenRootTaskIsEmpty(prev, options); } next.delayedResume = false; final TaskDisplayArea taskDisplayArea = getDisplayArea(); // If the top activity is the resumed one, nothing to do. if (mResumedActivity == next && next.isState(RESUMED) && taskDisplayArea.allResumedActivitiesComplete()) { // Make sure we have executed any pending transitions, since there // should be nothing left to do at this point. executeAppTransition(options); // For devices that are not in fullscreen mode (e.g. freeform windows), it's possible // we still want to check if the visibility of other windows have changed (e.g. bringing // a fullscreen window forward to cover another freeform activity.) if (taskDisplayArea.inMultiWindowMode()) { taskDisplayArea.ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, false /* preserveWindows */, true /* notifyClients */); } ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Top activity " + "resumed %s", next); return false; } if (!next.canResumeByCompat()) { return false; } // If we are currently pausing an activity, then don't do anything until that is done. final boolean allPausedComplete = mRootWindowContainer.allPausedActivitiesComplete(); if (!allPausedComplete) { ProtoLog.v(WM_DEBUG_STATES, "resumeTopActivityLocked: Skip resume: some activity pausing."); return false; } // If we are sleeping, and there is no resumed activity, and the top activity is paused, // well that is the state we want. if (mLastPausedActivity == next && shouldSleepOrShutDownActivities()) { // Make sure we have executed any pending transitions, since there // should be nothing left to do at this point. executeAppTransition(options); ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Going to sleep and" + " all paused"); return false; } // Make sure that the user who owns this activity is started. If not, // we will just leave it as is because someone should be bringing // another user's activities to the top of the stack. if (!mAtmService.mAmInternal.hasStartedUserState(next.mUserId)) { Slog.w(TAG, "Skipping resume of top activity " + next + ": user " + next.mUserId + " is stopped"); return false; } // The activity may be waiting for stop, but that is no longer // appropriate for it. mTaskSupervisor.mStoppingActivities.remove(next); if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming " + next); mTaskSupervisor.setLaunchSource(next.info.applicationInfo.uid); ActivityRecord lastResumed = null; final Task lastFocusedRootTask = taskDisplayArea.getLastFocusedRootTask(); if (lastFocusedRootTask != null && lastFocusedRootTask != getRootTask()) { // So, why aren't we using prev here??? See the param comment on the method. prev // doesn't represent the last resumed activity. However, the last focus stack does if // it isn't null. lastResumed = lastFocusedRootTask.getResumedActivity(); } boolean pausing = !deferPause && taskDisplayArea.pauseBackTasks(next); if (mResumedActivity != null) { ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Pausing %s", mResumedActivity); pausing |= startPausingLocked(false /* uiSleeping */, next, "resumeTopActivityInnerLocked"); } if (pausing) { ProtoLog.v(WM_DEBUG_STATES, "resumeTopActivityLocked: Skip resume: need to" + " start pausing"); // At this point we want to put the upcoming activity's process // at the top of the LRU list, since we know we will be needing it // very soon and it would be a waste to let it get killed if it // happens to be sitting towards the end. if (next.attachedToProcess()) { next.app.updateProcessInfo(false /* updateServiceConnectionActivities */, true /* activityChange */, false /* updateOomAdj */, false /* addPendingTopUid */); } else if (!next.isProcessRunning()) { // Since the start-process is asynchronous, if we already know the process of next // activity isn't running, we can start the process earlier to save the time to wait // for the current activity to be paused. final boolean isTop = this == taskDisplayArea.getFocusedRootTask(); mAtmService.startProcessAsync(next, false /* knownToBeDead */, isTop, isTop ? "pre-top-activity" : "pre-activity"); } if (lastResumed != null) { lastResumed.setWillCloseOrEnterPip(true); } return true; } else if (mResumedActivity == next && next.isState(RESUMED) && taskDisplayArea.allResumedActivitiesComplete()) { // It is possible for the activity to be resumed when we paused back stacks above if the // next activity doesn't have to wait for pause to complete. // So, nothing else to-do except: // Make sure we have executed any pending transitions, since there // should be nothing left to do at this point. executeAppTransition(options); ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Top activity resumed " + "(dontWaitForPause) %s", next); return true; } // If the most recent activity was noHistory but was only stopped rather // than stopped+finished because the device went to sleep, we need to make // sure to finish it as we're making a new activity topmost. if (shouldSleepActivities()) { mTaskSupervisor.finishNoHistoryActivitiesIfNeeded(next); } if (prev != null && prev != next && next.nowVisible) { // The next activity is already visible, so hide the previous // activity's windows right now so we can show the new one ASAP. // We only do this if the previous is finishing, which should mean // it is on top of the one being resumed so hiding it quickly // is good. Otherwise, we want to do the normal route of allowing // the resumed activity to be shown so we can decide if the // previous should actually be hidden depending on whether the // new one is found to be full-screen or not. if (prev.finishing) { prev.setVisibility(false); if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Not waiting for visible to hide: " + prev + ", nowVisible=" + next.nowVisible); } else { if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Previous already visible but still waiting to hide: " + prev + ", nowVisible=" + next.nowVisible); } } // Launching this app's activity, make sure the app is no longer // considered stopped. try { mTaskSupervisor.getActivityMetricsLogger() .notifyBeforePackageUnstopped(next.packageName); mAtmService.getPackageManager().setPackageStoppedState( next.packageName, false, next.mUserId); /* TODO: Verify if correct userid */ } catch (RemoteException e1) { } catch (IllegalArgumentException e) { Slog.w(TAG, "Failed trying to unstop package " + next.packageName + ": " + e); } // We are starting up the next activity, so tell the window manager // that the previous one will be hidden soon. This way it can know // to ignore it when computing the desired screen orientation. boolean anim = true; final DisplayContent dc = taskDisplayArea.mDisplayContent; if (prev != null) { if (prev.finishing) { if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare close transition: prev=" + prev); if (mTaskSupervisor.mNoAnimActivities.contains(prev)) { anim = false; dc.prepareAppTransition(TRANSIT_NONE); } else { dc.prepareAppTransition(TRANSIT_CLOSE); } prev.setVisibility(false); } else { if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: prev=" + prev); if (mTaskSupervisor.mNoAnimActivities.contains(next)) { anim = false; dc.prepareAppTransition(TRANSIT_NONE); } else { dc.prepareAppTransition(TRANSIT_OPEN, next.mLaunchTaskBehind ? TRANSIT_FLAG_OPEN_BEHIND : 0); } } } else { if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: no previous"); if (mTaskSupervisor.mNoAnimActivities.contains(next)) { anim = false; dc.prepareAppTransition(TRANSIT_NONE); } else { dc.prepareAppTransition(TRANSIT_OPEN); } } if (anim) { next.applyOptionsAnimation(); } else { next.abortAndClearOptionsAnimation(); } mTaskSupervisor.mNoAnimActivities.clear(); if (next.attachedToProcess()) { if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resume running: " + next + " stopped=" + next.stopped + " visibleRequested=" + next.mVisibleRequested); // If the previous activity is translucent, force a visibility update of // the next activity, so that it's added to WM's opening app list, and // transition animation can be set up properly. // For example, pressing Home button with a translucent activity in focus. // Launcher is already visible in this case. If we don't add it to opening // apps, maybeUpdateTransitToWallpaper() will fail to identify this as a // TRANSIT_WALLPAPER_OPEN animation, and run some funny animation. final boolean lastActivityTranslucent = lastFocusedRootTask != null && (lastFocusedRootTask.inMultiWindowMode() || (lastFocusedRootTask.mLastPausedActivity != null && !lastFocusedRootTask.mLastPausedActivity.occludesParent())); // This activity is now becoming visible. if (!next.mVisibleRequested || next.stopped || lastActivityTranslucent) { next.setVisibility(true); } // schedule launch ticks to collect information about slow apps. next.startLaunchTickingLocked(); ActivityRecord lastResumedActivity = lastFocusedRootTask == null ? null : lastFocusedRootTask.getResumedActivity(); final ActivityState lastState = next.getState(); mAtmService.updateCpuStats(); ProtoLog.v(WM_DEBUG_STATES, "Moving to RESUMED: %s (in existing)", next); next.setState(RESUMED, "resumeTopActivityInnerLocked"); // Have the window manager re-evaluate the orientation of // the screen based on the new activity order. boolean notUpdated = true; // Activity should also be visible if set mLaunchTaskBehind to true (see // ActivityRecord#shouldBeVisibleIgnoringKeyguard()). if (shouldBeVisible(next)) { // We have special rotation behavior when here is some active activity that // requests specific orientation or Keyguard is locked. Make sure all activity // visibilities are set correctly as well as the transition is updated if needed // to get the correct rotation behavior. Otherwise the following call to update // the orientation may cause incorrect configurations delivered to client as a // result of invisible window resize. // TODO: Remove this once visibilities are set correctly immediately when // starting an activity. notUpdated = !mRootWindowContainer.ensureVisibilityAndConfig(next, getDisplayId(), true /* markFrozenIfConfigChanged */, false /* deferResume */); } if (notUpdated) { // The configuration update wasn't able to keep the existing // instance of the activity, and instead started a new one. // We should be all done, but let's just make sure our activity // is still at the top and schedule another run if something // weird happened. ActivityRecord nextNext = topRunningActivity(); ProtoLog.i(WM_DEBUG_STATES, "Activity config changed during resume: " + "%s, new next: %s", next, nextNext); if (nextNext != next) { // Do over! mTaskSupervisor.scheduleResumeTopActivities(); } if (!next.mVisibleRequested || next.stopped) { next.setVisibility(true); } next.completeResumeLocked(); return true; } try { final ClientTransaction transaction = ClientTransaction.obtain(next.app.getThread(), next.appToken); // Deliver all pending results. ArrayList<ResultInfo> a = next.results; if (a != null) { final int N = a.size(); if (!next.finishing && N > 0) { if (DEBUG_RESULTS) Slog.v(TAG_RESULTS, "Delivering results to " + next + ": " + a); transaction.addCallback(ActivityResultItem.obtain(a)); } } if (next.newIntents != null) { transaction.addCallback( NewIntentItem.obtain(next.newIntents, true /* resume */)); } // Well the app will no longer be stopped. // Clear app token stopped state in window manager if needed. next.notifyAppResumed(next.stopped); EventLogTags.writeWmResumeActivity(next.mUserId, System.identityHashCode(next), next.getTask().mTaskId, next.shortComponentName); mAtmService.getAppWarningsLocked().onResumeActivity(next); next.app.setPendingUiCleanAndForceProcessStateUpTo(mAtmService.mTopProcessState); next.abortAndClearOptionsAnimation(); transaction.setLifecycleStateRequest( ResumeActivityItem.obtain(next.app.getReportedProcState(), dc.isNextTransitionForward())); mAtmService.getLifecycleManager().scheduleTransaction(transaction); ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Resumed %s", next); } catch (Exception e) { // Whoops, need to restart this activity! ProtoLog.v(WM_DEBUG_STATES, "Resume failed; resetting state to %s: " + "%s", lastState, next); next.setState(lastState, "resumeTopActivityInnerLocked"); // lastResumedActivity being non-null implies there is a lastStack present. if (lastResumedActivity != null) { lastResumedActivity.setState(RESUMED, "resumeTopActivityInnerLocked"); } Slog.i(TAG, "Restarting because process died: " + next); if (!next.hasBeenLaunched) { next.hasBeenLaunched = true; } else if (SHOW_APP_STARTING_PREVIEW && lastFocusedRootTask != null && lastFocusedRootTask.isTopRootTaskInDisplayArea()) { next.showStartingWindow(false /* taskSwitch */); } mTaskSupervisor.startSpecificActivity(next, true, false); return true; } // From this point on, if something goes wrong there is no way // to recover the activity. try { next.completeResumeLocked(); } catch (Exception e) { // If any exception gets thrown, toss away this // activity and try the next one. Slog.w(TAG, "Exception thrown during resume of " + next, e); next.finishIfPossible("resume-exception", true /* oomAdj */); return true; } } else { // Whoops, need to restart this activity! if (!next.hasBeenLaunched) { next.hasBeenLaunched = true; } else { if (SHOW_APP_STARTING_PREVIEW) { next.showStartingWindow(false /* taskSwich */); } if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Restarting: " + next); } ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivityLocked: Restarting %s", next); mTaskSupervisor.startSpecificActivity(next, true, true); } return true; }