2 * Copyright (C) 2006 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.server.am;
19 import static android.app.ActivityManager.ENABLE_TASK_SNAPSHOTS;
20 import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
21 import static android.app.ActivityManager.StackId;
22 import static android.app.ActivityManager.StackId.ASSISTANT_STACK_ID;
23 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
24 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
25 import static android.app.ActivityManager.StackId.HOME_STACK_ID;
26 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
27 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
28 import static android.app.ActivityManager.TaskDescription.ATTR_TASKDESCRIPTION_PREFIX;
29 import static android.app.ActivityOptions.ANIM_CLIP_REVEAL;
30 import static android.app.ActivityOptions.ANIM_CUSTOM;
31 import static android.app.ActivityOptions.ANIM_SCALE_UP;
32 import static android.app.ActivityOptions.ANIM_SCENE_TRANSITION;
33 import static android.app.ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_DOWN;
34 import static android.app.ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_UP;
35 import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN;
36 import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP;
37 import static android.app.AppOpsManager.MODE_ALLOWED;
38 import static android.app.AppOpsManager.OP_PICTURE_IN_PICTURE;
39 import static android.content.Intent.ACTION_MAIN;
40 import static android.content.Intent.CATEGORY_HOME;
41 import static android.content.Intent.CATEGORY_LAUNCHER;
42 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
43 import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
44 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
45 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
46 import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
47 import static android.content.pm.ActivityInfo.CONFIG_UI_MODE;
48 import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
49 import static android.content.pm.ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS;
50 import static android.content.pm.ActivityInfo.FLAG_IMMERSIVE;
51 import static android.content.pm.ActivityInfo.FLAG_MULTIPROCESS;
52 import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
53 import static android.content.pm.ActivityInfo.FLAG_STATE_NOT_NEEDED;
54 import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
55 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
56 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
57 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
58 import static android.content.pm.ActivityInfo.PERSIST_ACROSS_REBOOTS;
59 import static android.content.pm.ActivityInfo.PERSIST_ROOT_ONLY;
60 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
61 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
62 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
63 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
64 import static android.content.res.Configuration.EMPTY;
65 import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
66 import static android.content.res.Configuration.UI_MODE_TYPE_VR_HEADSET;
67 import static android.os.Build.VERSION_CODES.HONEYCOMB;
68 import static android.os.Build.VERSION_CODES.O;
69 import static android.os.Process.SYSTEM_UID;
70 import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
72 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
73 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE;
74 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SCREENSHOTS;
75 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STATES;
76 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
77 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_THUMBNAILS;
78 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBILITY;
79 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONFIGURATION;
80 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SAVED_STATE;
81 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SCREENSHOTS;
82 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STATES;
83 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
84 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_THUMBNAILS;
85 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBILITY;
86 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
87 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
88 import static com.android.server.am.ActivityManagerService.IS_USER_BUILD;
89 import static com.android.server.am.ActivityManagerService.TAKE_FULLSCREEN_SCREENSHOTS;
90 import static com.android.server.am.ActivityStack.ActivityState.DESTROYED;
91 import static com.android.server.am.ActivityStack.ActivityState.DESTROYING;
92 import static com.android.server.am.ActivityStack.ActivityState.INITIALIZING;
93 import static com.android.server.am.ActivityStack.ActivityState.PAUSED;
94 import static com.android.server.am.ActivityStack.ActivityState.PAUSING;
95 import static com.android.server.am.ActivityStack.ActivityState.RESUMED;
96 import static com.android.server.am.ActivityStack.ActivityState.STOPPED;
97 import static com.android.server.am.ActivityStack.ActivityState.STOPPING;
98 import static com.android.server.am.ActivityStack.LAUNCH_TICK;
99 import static com.android.server.am.ActivityStack.LAUNCH_TICK_MSG;
100 import static com.android.server.am.ActivityStack.PAUSE_TIMEOUT_MSG;
101 import static com.android.server.am.ActivityStack.STACK_INVISIBLE;
102 import static com.android.server.am.ActivityStack.STOP_TIMEOUT_MSG;
103 import static com.android.server.am.EventLogTags.AM_ACTIVITY_FULLY_DRAWN_TIME;
104 import static com.android.server.am.EventLogTags.AM_ACTIVITY_LAUNCH_TIME;
105 import static com.android.server.am.EventLogTags.AM_RELAUNCH_ACTIVITY;
106 import static com.android.server.am.EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY;
107 import static com.android.server.am.TaskPersister.DEBUG;
108 import static com.android.server.am.TaskPersister.IMAGE_EXTENSION;
109 import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
110 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
111 import static org.xmlpull.v1.XmlPullParser.END_TAG;
112 import static org.xmlpull.v1.XmlPullParser.START_TAG;
114 import android.annotation.NonNull;
115 import android.app.ActivityManager.TaskDescription;
116 import android.app.ActivityOptions;
117 import android.app.PendingIntent;
118 import android.app.PictureInPictureArgs;
119 import android.app.ResultInfo;
120 import android.content.ComponentName;
121 import android.content.Intent;
122 import android.content.pm.ActivityInfo;
123 import android.content.pm.ApplicationInfo;
124 import android.content.res.CompatibilityInfo;
125 import android.content.res.Configuration;
126 import android.graphics.Bitmap;
127 import android.graphics.Point;
128 import android.graphics.Rect;
129 import android.os.Bundle;
130 import android.os.Debug;
131 import android.os.IBinder;
132 import android.os.Message;
133 import android.os.PersistableBundle;
134 import android.os.Process;
135 import android.os.RemoteException;
136 import android.os.SystemClock;
137 import android.os.Trace;
138 import android.os.UserHandle;
139 import android.service.voice.IVoiceInteractionSession;
140 import android.util.EventLog;
141 import android.util.Log;
142 import android.util.Slog;
143 import android.util.TimeUtils;
144 import android.view.AppTransitionAnimationSpec;
145 import android.view.IApplicationToken;
146 import android.view.WindowManager.LayoutParams;
148 import com.android.internal.app.ResolverActivity;
149 import com.android.internal.content.ReferrerIntent;
150 import com.android.internal.util.XmlUtils;
151 import com.android.server.AttributeCache;
152 import com.android.server.AttributeCache.Entry;
153 import com.android.server.am.ActivityStack.ActivityState;
154 import com.android.server.am.ActivityStackSupervisor.ActivityContainer;
155 import com.android.server.wm.AppWindowContainerController;
156 import com.android.server.wm.AppWindowContainerListener;
157 import com.android.server.wm.TaskWindowContainerController;
159 import org.xmlpull.v1.XmlPullParser;
160 import org.xmlpull.v1.XmlPullParserException;
161 import org.xmlpull.v1.XmlSerializer;
164 import java.io.IOException;
165 import java.io.PrintWriter;
166 import java.lang.ref.WeakReference;
167 import java.util.ArrayList;
168 import java.util.Arrays;
169 import java.util.HashSet;
170 import java.util.List;
171 import java.util.Objects;
174 * An entry in the history stack, representing an activity.
176 final class ActivityRecord extends ConfigurationContainer implements AppWindowContainerListener {
177 private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityRecord" : TAG_AM;
178 private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION;
179 private static final String TAG_SAVED_STATE = TAG + POSTFIX_SAVED_STATE;
180 private static final String TAG_SCREENSHOTS = TAG + POSTFIX_SCREENSHOTS;
181 private static final String TAG_STATES = TAG + POSTFIX_STATES;
182 private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
183 private static final String TAG_THUMBNAILS = TAG + POSTFIX_THUMBNAILS;
184 private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
186 private static final boolean SHOW_ACTIVITY_START_TIME = true;
187 private static final String RECENTS_PACKAGE_NAME = "com.android.systemui.recents";
189 private static final String ATTR_ID = "id";
190 private static final String TAG_INTENT = "intent";
191 private static final String ATTR_USERID = "user_id";
192 private static final String TAG_PERSISTABLEBUNDLE = "persistable_bundle";
193 private static final String ATTR_LAUNCHEDFROMUID = "launched_from_uid";
194 private static final String ATTR_LAUNCHEDFROMPACKAGE = "launched_from_package";
195 private static final String ATTR_RESOLVEDTYPE = "resolved_type";
196 private static final String ATTR_COMPONENTSPECIFIED = "component_specified";
197 static final String ACTIVITY_ICON_SUFFIX = "_activity_icon_";
199 final ActivityManagerService service; // owner
200 final IApplicationToken.Stub appToken; // window manager token
201 AppWindowContainerController mWindowContainerController;
202 final ActivityInfo info; // all about me
203 final ApplicationInfo appInfo; // information about activity's app
204 final int launchedFromPid; // always the pid who started the activity.
205 final int launchedFromUid; // always the uid who started the activity.
206 final String launchedFromPackage; // always the package who started the activity.
207 final int userId; // Which user is this running for?
208 final Intent intent; // the original intent that generated us
209 final ComponentName realActivity; // the intent component, or target of an alias.
210 final String shortComponentName; // the short component name of the intent
211 final String resolvedType; // as per original caller;
212 final String packageName; // the package implementing intent's component
213 final String processName; // process where this component wants to run
214 final String taskAffinity; // as per ActivityInfo.taskAffinity
215 final boolean stateNotNeeded; // As per ActivityInfo.flags
216 boolean fullscreen; // covers the full screen?
217 final boolean noDisplay; // activity is not displayed?
218 private final boolean componentSpecified; // did caller specify an explicit component?
219 final boolean rootVoiceInteraction; // was this the root activity of a voice interaction?
221 static final int APPLICATION_ACTIVITY_TYPE = 0;
222 static final int HOME_ACTIVITY_TYPE = 1;
223 static final int RECENTS_ACTIVITY_TYPE = 2;
224 static final int ASSISTANT_ACTIVITY_TYPE = 3;
227 private CharSequence nonLocalizedLabel; // the label information from the package mgr.
228 private int labelRes; // the label information from the package mgr.
229 private int icon; // resource identifier of activity's icon.
230 private int logo; // resource identifier of activity's logo.
231 private int theme; // resource identifier of activity's theme.
232 private int realTheme; // actual theme resource we will use, never 0.
233 private int windowFlags; // custom window flags for preview window.
234 private TaskRecord task; // the task this is in.
235 private long createTime = System.currentTimeMillis();
236 long displayStartTime; // when we started launching this activity
237 long fullyDrawnStartTime; // when we started launching this activity
238 private long startTime; // last time this activity was started
239 long lastVisibleTime; // last time this activity became visible
240 long cpuTimeAtResume; // the cpu time of host process at the time of resuming activity
241 long pauseTime; // last time we started pausing the activity
242 long launchTickTime; // base time for launch tick messages
243 // TODO: Refactor mLastReportedConfiguration and mLastReportedOverrideConfiguration to use a
244 // MergedConfiguration object for clarity.
245 private Configuration mLastReportedConfiguration; // configuration activity was last running in
246 // Overridden configuration by the activity task
247 // WARNING: Reference points to {@link TaskRecord#getMergedOverrideConfig}, so its internal
248 // state should never be altered directly.
249 private Configuration mLastReportedOverrideConfiguration;
250 private int mLastReportedDisplayId;
251 CompatibilityInfo compat;// last used compatibility mode
252 ActivityRecord resultTo; // who started this entry, so will get our reply
253 final String resultWho; // additional identifier for use by resultTo.
254 final int requestCode; // code given by requester (resultTo)
255 ArrayList<ResultInfo> results; // pending ActivityResult objs we have received
256 HashSet<WeakReference<PendingIntentRecord>> pendingResults; // all pending intents for this act
257 ArrayList<ReferrerIntent> newIntents; // any pending new intents for single-top mode
258 ActivityOptions pendingOptions; // most recently given options
259 ActivityOptions returningOptions; // options that are coming back via convertToTranslucent
260 AppTimeTracker appTimeTracker; // set if we are tracking the time in this app/task/activity
261 HashSet<ConnectionRecord> connections; // All ConnectionRecord we hold
262 UriPermissionOwner uriPermissions; // current special URI access perms.
263 ProcessRecord app; // if non-null, hosting application
264 ActivityState state; // current state we are in
265 Bundle icicle; // last saved activity state
266 PersistableBundle persistentState; // last persistently saved activity state
267 boolean frontOfTask; // is this the root activity of its task?
268 boolean launchFailed; // set if a launched failed, to abort on 2nd try
269 boolean haveState; // have we gotten the last activity state?
270 boolean stopped; // is activity pause finished?
271 boolean delayedResume; // not yet resumed because of stopped app switches?
272 boolean finishing; // activity in pending finish list?
273 boolean deferRelaunchUntilPaused; // relaunch of activity is being deferred until pause is
275 boolean preserveWindowOnDeferredRelaunch; // activity windows are preserved on deferred relaunch
276 int configChangeFlags; // which config values have changed
277 boolean keysPaused; // has key dispatching been paused for it?
278 int launchMode; // the launch mode activity attribute.
279 boolean visible; // does this activity's window need to be shown?
280 boolean visibleIgnoringKeyguard; // is this activity visible, ignoring the fact that Keyguard
281 // might hide this activity?
282 boolean sleeping; // have we told the activity to sleep?
283 boolean nowVisible; // is this activity's window visible?
284 boolean idle; // has the activity gone idle?
285 boolean hasBeenLaunched;// has this activity ever been launched?
286 boolean frozenBeforeDestroy;// has been frozen but not yet destroyed.
287 boolean immersive; // immersive mode (don't interrupt if possible)
288 boolean forceNewConfig; // force re-create with new config next time
289 private boolean mInMultiWindowMode; // whether or not this activity is currently in multi-window
290 // mode (default false)
291 private boolean mInPictureInPictureMode; // whether or not this activity is currently in
292 // picture-in-picture mode (default false)
293 boolean supportsPictureInPictureWhilePausing; // This flag is set by the system to indicate
294 // that the activity can enter picture in picture while pausing (ie. only when another
295 // task is brought to front or started)
296 PictureInPictureArgs pictureInPictureArgs = new PictureInPictureArgs(); // The PiP
297 // arguments used when deferring the entering of picture-in-picture.
298 int launchCount; // count of launches since last state
299 long lastLaunchTime; // time of last launch of this activity
300 ComponentName requestedVrComponent; // the requested component for handling VR mode.
301 ArrayList<ActivityContainer> mChildContainers = new ArrayList<>();
303 String stringName; // for caching of toString().
305 private boolean inHistory; // are we in the history stack?
306 final ActivityStackSupervisor mStackSupervisor;
308 static final int STARTING_WINDOW_NOT_SHOWN = 0;
309 static final int STARTING_WINDOW_SHOWN = 1;
310 static final int STARTING_WINDOW_REMOVED = 2;
311 int mStartingWindowState = STARTING_WINDOW_NOT_SHOWN;
312 boolean mTaskOverlay = false; // Task is always on-top of other activities in the task.
314 boolean mUpdateTaskThumbnailWhenHidden;
315 ActivityContainer mInitialActivityContainer;
317 TaskDescription taskDescription; // the recents information for this activity
318 boolean mLaunchTaskBehind; // this activity is actively being launched with
319 // ActivityOptions.setLaunchTaskBehind, will be cleared once launch is completed.
321 // These configurations are collected from application's resources based on size-sensitive
322 // qualifiers. For example, layout-w800dp will be added to mHorizontalSizeConfigurations as 800
323 // and drawable-sw400dp will be added to both as 400.
324 private int[] mVerticalSizeConfigurations;
325 private int[] mHorizontalSizeConfigurations;
326 private int[] mSmallestSizeConfigurations;
328 boolean pendingVoiceInteractionStart; // Waiting for activity-invoked voice session
329 IVoiceInteractionSession voiceSession; // Voice interaction session for this activity
331 // A hint to override the window specified rotation animation, or -1
332 // to use the window specified value. We use this so that
333 // we can select the right animation in the cases of starting
334 // windows, where the app hasn't had time to set a value
336 int mRotationAnimationHint = -1;
338 // The bounds of this activity. Mainly used for aspect-ratio compatibility.
339 // TODO(b/36505427): Every level on ConfigurationContainer now has bounds information, which
340 // directly affects the configuration. We should probably move this into that class and have it
341 // handle calculating override configuration from the bounds.
342 private final Rect mBounds = new Rect();
345 * Temp configs used in {@link #ensureActivityConfigurationLocked(int, boolean)}
347 private final Configuration mTmpConfig1 = new Configuration();
348 private final Configuration mTmpConfig2 = new Configuration();
349 private final Configuration mTmpConfig3 = new Configuration();
350 private final Point mTmpPoint = new Point();
351 private final Rect mTmpBounds = new Rect();
353 private static String startingWindowStateToString(int state) {
355 case STARTING_WINDOW_NOT_SHOWN:
356 return "STARTING_WINDOW_NOT_SHOWN";
357 case STARTING_WINDOW_SHOWN:
358 return "STARTING_WINDOW_SHOWN";
359 case STARTING_WINDOW_REMOVED:
360 return "STARTING_WINDOW_REMOVED";
362 return "unknown state=" + state;
366 void dump(PrintWriter pw, String prefix) {
367 final long now = SystemClock.uptimeMillis();
368 pw.print(prefix); pw.print("packageName="); pw.print(packageName);
369 pw.print(" processName="); pw.println(processName);
370 pw.print(prefix); pw.print("launchedFromUid="); pw.print(launchedFromUid);
371 pw.print(" launchedFromPackage="); pw.print(launchedFromPackage);
372 pw.print(" userId="); pw.println(userId);
373 pw.print(prefix); pw.print("app="); pw.println(app);
374 pw.print(prefix); pw.println(intent.toInsecureStringWithClip());
375 pw.print(prefix); pw.print("frontOfTask="); pw.print(frontOfTask);
376 pw.print(" task="); pw.println(task);
377 pw.print(prefix); pw.print("taskAffinity="); pw.println(taskAffinity);
378 pw.print(prefix); pw.print("realActivity=");
379 pw.println(realActivity.flattenToShortString());
380 if (appInfo != null) {
381 pw.print(prefix); pw.print("baseDir="); pw.println(appInfo.sourceDir);
382 if (!Objects.equals(appInfo.sourceDir, appInfo.publicSourceDir)) {
383 pw.print(prefix); pw.print("resDir="); pw.println(appInfo.publicSourceDir);
385 pw.print(prefix); pw.print("dataDir="); pw.println(appInfo.dataDir);
386 if (appInfo.splitSourceDirs != null) {
387 pw.print(prefix); pw.print("splitDir=");
388 pw.println(Arrays.toString(appInfo.splitSourceDirs));
391 pw.print(prefix); pw.print("stateNotNeeded="); pw.print(stateNotNeeded);
392 pw.print(" componentSpecified="); pw.print(componentSpecified);
393 pw.print(" mActivityType="); pw.println(mActivityType);
394 if (rootVoiceInteraction) {
395 pw.print(prefix); pw.print("rootVoiceInteraction="); pw.println(rootVoiceInteraction);
397 pw.print(prefix); pw.print("compat="); pw.print(compat);
398 pw.print(" labelRes=0x"); pw.print(Integer.toHexString(labelRes));
399 pw.print(" icon=0x"); pw.print(Integer.toHexString(icon));
400 pw.print(" theme=0x"); pw.println(Integer.toHexString(theme));
401 pw.print(prefix); pw.print("mLastReportedConfiguration=");
402 pw.println(mLastReportedConfiguration);
403 pw.print(prefix); pw.print("mLastReportedOverrideConfiguration=");
404 pw.println(mLastReportedOverrideConfiguration);
405 pw.print(prefix); pw.print("CurrentConfiguration="); pw.println(getConfiguration());
406 if (!getOverrideConfiguration().equals(EMPTY)) {
407 pw.println(prefix + "OverrideConfiguration=" + getOverrideConfiguration());
409 if (!mBounds.isEmpty()) {
410 pw.println(prefix + "mBounds=" + mBounds);
412 if (resultTo != null || resultWho != null) {
413 pw.print(prefix); pw.print("resultTo="); pw.print(resultTo);
414 pw.print(" resultWho="); pw.print(resultWho);
415 pw.print(" resultCode="); pw.println(requestCode);
417 if (taskDescription != null) {
418 final String iconFilename = taskDescription.getIconFilename();
419 if (iconFilename != null || taskDescription.getLabel() != null ||
420 taskDescription.getPrimaryColor() != 0) {
421 pw.print(prefix); pw.print("taskDescription:");
422 pw.print(" iconFilename="); pw.print(taskDescription.getIconFilename());
423 pw.print(" label=\""); pw.print(taskDescription.getLabel());
425 pw.print(" primaryColor=");
426 pw.println(Integer.toHexString(taskDescription.getPrimaryColor()));
427 pw.print(prefix + " backgroundColor=");
428 pw.println(Integer.toHexString(taskDescription.getBackgroundColor()));
429 pw.print(prefix + " statusBarColor=");
430 pw.println(Integer.toHexString(taskDescription.getStatusBarColor()));
431 pw.print(prefix + " navigationBarColor=");
432 pw.println(Integer.toHexString(taskDescription.getNavigationBarColor()));
434 if (iconFilename == null && taskDescription.getIcon() != null) {
435 pw.print(prefix); pw.println("taskDescription contains Bitmap");
438 if (results != null) {
439 pw.print(prefix); pw.print("results="); pw.println(results);
441 if (pendingResults != null && pendingResults.size() > 0) {
442 pw.print(prefix); pw.println("Pending Results:");
443 for (WeakReference<PendingIntentRecord> wpir : pendingResults) {
444 PendingIntentRecord pir = wpir != null ? wpir.get() : null;
445 pw.print(prefix); pw.print(" - ");
450 pir.dump(pw, prefix + " ");
454 if (newIntents != null && newIntents.size() > 0) {
455 pw.print(prefix); pw.println("Pending New Intents:");
456 for (int i=0; i<newIntents.size(); i++) {
457 Intent intent = newIntents.get(i);
458 pw.print(prefix); pw.print(" - ");
459 if (intent == null) {
462 pw.println(intent.toShortString(false, true, false, true));
466 if (pendingOptions != null) {
467 pw.print(prefix); pw.print("pendingOptions="); pw.println(pendingOptions);
469 if (appTimeTracker != null) {
470 appTimeTracker.dumpWithHeader(pw, prefix, false);
472 if (uriPermissions != null) {
473 uriPermissions.dump(pw, prefix);
475 pw.print(prefix); pw.print("launchFailed="); pw.print(launchFailed);
476 pw.print(" launchCount="); pw.print(launchCount);
477 pw.print(" lastLaunchTime=");
478 if (lastLaunchTime == 0) pw.print("0");
479 else TimeUtils.formatDuration(lastLaunchTime, now, pw);
481 pw.print(prefix); pw.print("haveState="); pw.print(haveState);
482 pw.print(" icicle="); pw.println(icicle);
483 pw.print(prefix); pw.print("state="); pw.print(state);
484 pw.print(" stopped="); pw.print(stopped);
485 pw.print(" delayedResume="); pw.print(delayedResume);
486 pw.print(" finishing="); pw.println(finishing);
487 pw.print(prefix); pw.print("keysPaused="); pw.print(keysPaused);
488 pw.print(" inHistory="); pw.print(inHistory);
489 pw.print(" visible="); pw.print(visible);
490 pw.print(" sleeping="); pw.print(sleeping);
491 pw.print(" idle="); pw.print(idle);
492 pw.print(" mStartingWindowState=");
493 pw.println(startingWindowStateToString(mStartingWindowState));
494 pw.print(prefix); pw.print("fullscreen="); pw.print(fullscreen);
495 pw.print(" noDisplay="); pw.print(noDisplay);
496 pw.print(" immersive="); pw.print(immersive);
497 pw.print(" launchMode="); pw.println(launchMode);
498 pw.print(prefix); pw.print("frozenBeforeDestroy="); pw.print(frozenBeforeDestroy);
499 pw.print(" forceNewConfig="); pw.println(forceNewConfig);
500 pw.print(prefix); pw.print("mActivityType=");
501 pw.println(activityTypeToString(mActivityType));
502 if (requestedVrComponent != null) {
504 pw.print("requestedVrComponent=");
505 pw.println(requestedVrComponent);
507 if (displayStartTime != 0 || startTime != 0) {
508 pw.print(prefix); pw.print("displayStartTime=");
509 if (displayStartTime == 0) pw.print("0");
510 else TimeUtils.formatDuration(displayStartTime, now, pw);
511 pw.print(" startTime=");
512 if (startTime == 0) pw.print("0");
513 else TimeUtils.formatDuration(startTime, now, pw);
516 final boolean waitingVisible =
517 mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(this);
518 if (lastVisibleTime != 0 || waitingVisible || nowVisible) {
519 pw.print(prefix); pw.print("waitingVisible="); pw.print(waitingVisible);
520 pw.print(" nowVisible="); pw.print(nowVisible);
521 pw.print(" lastVisibleTime=");
522 if (lastVisibleTime == 0) pw.print("0");
523 else TimeUtils.formatDuration(lastVisibleTime, now, pw);
526 if (deferRelaunchUntilPaused || configChangeFlags != 0) {
527 pw.print(prefix); pw.print("deferRelaunchUntilPaused="); pw.print(deferRelaunchUntilPaused);
528 pw.print(" configChangeFlags=");
529 pw.println(Integer.toHexString(configChangeFlags));
531 if (connections != null) {
532 pw.print(prefix); pw.print("connections="); pw.println(connections);
535 pw.println(prefix + "resizeMode=" + ActivityInfo.resizeModeToString(info.resizeMode));
536 if (info.supportsPictureInPicture()) {
537 pw.println(prefix + "supportsPictureInPicture=" + info.supportsPictureInPicture());
538 pw.println(prefix + "supportsPictureInPictureWhilePausing: "
539 + supportsPictureInPictureWhilePausing);
541 if (info.maxAspectRatio != 0) {
542 pw.println(prefix + "maxAspectRatio=" + info.maxAspectRatio);
547 private boolean crossesHorizontalSizeThreshold(int firstDp, int secondDp) {
548 return crossesSizeThreshold(mHorizontalSizeConfigurations, firstDp, secondDp);
551 private boolean crossesVerticalSizeThreshold(int firstDp, int secondDp) {
552 return crossesSizeThreshold(mVerticalSizeConfigurations, firstDp, secondDp);
555 private boolean crossesSmallestSizeThreshold(int firstDp, int secondDp) {
556 return crossesSizeThreshold(mSmallestSizeConfigurations, firstDp, secondDp);
560 * The purpose of this method is to decide whether the activity needs to be relaunched upon
561 * changing its size. In most cases the activities don't need to be relaunched, if the resize
562 * is small, all the activity content has to do is relayout itself within new bounds. There are
563 * cases however, where the activity's content would be completely changed in the new size and
564 * the full relaunch is required.
566 * The activity will report to us vertical and horizontal thresholds after which a relaunch is
567 * required. These thresholds are collected from the application resource qualifiers. For
568 * example, if application has layout-w600dp resource directory, then it needs a relaunch when
569 * we resize from width of 650dp to 550dp, as it crosses the 600dp threshold. However, if
570 * it resizes width from 620dp to 700dp, it won't be relaunched as it stays on the same side
573 private static boolean crossesSizeThreshold(int[] thresholds, int firstDp,
575 if (thresholds == null) {
578 for (int i = thresholds.length - 1; i >= 0; i--) {
579 final int threshold = thresholds[i];
580 if ((firstDp < threshold && secondDp >= threshold)
581 || (firstDp >= threshold && secondDp < threshold)) {
588 void setSizeConfigurations(int[] horizontalSizeConfiguration,
589 int[] verticalSizeConfigurations, int[] smallestSizeConfigurations) {
590 mHorizontalSizeConfigurations = horizontalSizeConfiguration;
591 mVerticalSizeConfigurations = verticalSizeConfigurations;
592 mSmallestSizeConfigurations = smallestSizeConfigurations;
595 private void scheduleActivityMovedToDisplay(int displayId, Configuration config) {
596 if (app == null || app.thread == null) {
597 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.w(TAG,
598 "Can't report activity moved to display - client not running, activityRecord="
599 + this + ", displayId=" + displayId);
603 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG,
604 "Reporting activity moved to display" + ", activityRecord=" + this
605 + ", displayId=" + displayId + ", config=" + config);
607 app.thread.scheduleActivityMovedToDisplay(appToken, displayId,
608 new Configuration(config));
609 } catch (RemoteException e) {
610 // If process died, whatever.
614 private void scheduleConfigurationChanged(Configuration config) {
615 if (app == null || app.thread == null) {
616 if (DEBUG_CONFIGURATION) Slog.w(TAG,
617 "Can't report activity configuration update - client not running"
618 + ", activityRecord=" + this);
622 if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + this + ", config: "
625 app.thread.scheduleActivityConfigurationChanged(appToken, new Configuration(config));
626 } catch (RemoteException e) {
627 // If process died, whatever.
631 void updateMultiWindowMode() {
632 if (task == null || task.getStack() == null || app == null || app.thread == null) {
636 // An activity is considered to be in multi-window mode if its task isn't fullscreen.
637 final boolean inMultiWindowMode = !task.mFullscreen;
638 if (inMultiWindowMode != mInMultiWindowMode) {
639 mInMultiWindowMode = inMultiWindowMode;
640 scheduleMultiWindowModeChanged(getConfiguration());
644 private void scheduleMultiWindowModeChanged(Configuration overrideConfig) {
646 app.thread.scheduleMultiWindowModeChanged(appToken, mInMultiWindowMode,
648 } catch (Exception e) {
649 // If process died, I don't care.
653 void updatePictureInPictureMode(Rect targetStackBounds) {
654 if (task == null || task.getStack() == null || app == null || app.thread == null) {
658 final boolean inPictureInPictureMode = (task.getStackId() == PINNED_STACK_ID) &&
659 (targetStackBounds != null);
660 if (inPictureInPictureMode != mInPictureInPictureMode) {
661 // Picture-in-picture mode changes also trigger a multi-window mode change as well, so
662 // update that here in order
663 mInPictureInPictureMode = inPictureInPictureMode;
664 mInMultiWindowMode = inPictureInPictureMode;
665 final Configuration newConfig = task.computeNewOverrideConfigurationForBounds(
666 targetStackBounds, null);
667 schedulePictureInPictureModeChanged(newConfig);
668 scheduleMultiWindowModeChanged(newConfig);
672 private void schedulePictureInPictureModeChanged(Configuration overrideConfig) {
674 app.thread.schedulePictureInPictureModeChanged(appToken, mInPictureInPictureMode,
676 } catch (Exception e) {
677 // If process died, no one cares.
681 boolean isFreeform() {
682 return task != null && task.getStackId() == FREEFORM_WORKSPACE_STACK_ID;
686 protected int getChildCount() {
687 // {@link ActivityRecord} is a leaf node and has no children.
692 protected ConfigurationContainer getChildAt(int index) {
697 protected ConfigurationContainer getParent() {
701 TaskRecord getTask() {
706 * Sets reference to the {@link TaskRecord} the {@link ActivityRecord} will treat as its parent.
707 * Note that this does not actually add the {@link ActivityRecord} as a {@link TaskRecord}
708 * children. However, this method will clean up references to this {@link ActivityRecord} in
709 * {@link ActivityStack}.
710 * @param task The new parent {@link TaskRecord}.
712 void setTask(TaskRecord task) {
713 setTask(task, false /*reparenting*/);
717 * This method should only be called by {@link TaskRecord#removeActivity(ActivityRecord)}.
719 void setTask(TaskRecord task, boolean reparenting) {
720 // Do nothing if the {@link TaskRecord} is the same as the current {@link getTask}.
721 if (task != null && task == getTask()) {
725 final ActivityStack stack = getStack();
727 // If the new {@link TaskRecord} is from a different {@link ActivityStack}, remove this
728 // {@link ActivityRecord} from its current {@link ActivityStack}.
729 if (!reparenting && stack != null && (task == null || stack != task.getStack())) {
730 stack.onActivityRemovedFromStack(this);
740 static class Token extends IApplicationToken.Stub {
741 private final WeakReference<ActivityRecord> weakActivity;
743 Token(ActivityRecord activity) {
744 weakActivity = new WeakReference<>(activity);
747 private static ActivityRecord tokenToActivityRecordLocked(Token token) {
751 ActivityRecord r = token.weakActivity.get();
752 if (r == null || r.getStack() == null) {
759 public String toString() {
760 StringBuilder sb = new StringBuilder(128);
762 sb.append(Integer.toHexString(System.identityHashCode(this)));
764 sb.append(weakActivity.get());
766 return sb.toString();
770 static ActivityRecord forTokenLocked(IBinder token) {
772 return Token.tokenToActivityRecordLocked((Token)token);
773 } catch (ClassCastException e) {
774 Slog.w(TAG, "Bad activity token: " + token, e);
779 boolean isResolverActivity() {
780 return ResolverActivity.class.getName().equals(realActivity.getClassName());
783 ActivityRecord(ActivityManagerService _service, ProcessRecord _caller, int _launchedFromPid,
784 int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType,
785 ActivityInfo aInfo, Configuration _configuration,
786 ActivityRecord _resultTo, String _resultWho, int _reqCode,
787 boolean _componentSpecified, boolean _rootVoiceInteraction,
788 ActivityStackSupervisor supervisor,
789 ActivityContainer container, ActivityOptions options, ActivityRecord sourceRecord) {
791 appToken = new Token(this);
793 launchedFromPid = _launchedFromPid;
794 launchedFromUid = _launchedFromUid;
795 launchedFromPackage = _launchedFromPackage;
796 userId = UserHandle.getUserId(aInfo.applicationInfo.uid);
798 shortComponentName = _intent.getComponent().flattenToShortString();
799 resolvedType = _resolvedType;
800 componentSpecified = _componentSpecified;
801 rootVoiceInteraction = _rootVoiceInteraction;
802 mLastReportedConfiguration = new Configuration(_configuration);
803 mLastReportedOverrideConfiguration = new Configuration();
804 resultTo = _resultTo;
805 resultWho = _resultWho;
806 requestCode = _reqCode;
807 state = INITIALIZING;
809 launchFailed = false;
811 delayedResume = false;
813 deferRelaunchUntilPaused = false;
819 hasBeenLaunched = false;
820 mStackSupervisor = supervisor;
821 mInitialActivityContainer = container;
823 mRotationAnimationHint = aInfo.rotationAnimation;
825 if (options != null) {
826 pendingOptions = options;
827 mLaunchTaskBehind = pendingOptions.getLaunchTaskBehind();
829 final int rotationAnimation = pendingOptions.getRotationAnimationHint();
830 // Only override manifest supplied option if set.
831 if (rotationAnimation >= 0) {
832 mRotationAnimationHint = rotationAnimation;
834 PendingIntent usageReport = pendingOptions.getUsageTimeReport();
835 if (usageReport != null) {
836 appTimeTracker = new AppTimeTracker(usageReport);
840 // This starts out true, since the initial state of an activity is that we have everything,
841 // and we shouldn't never consider it lacking in state to be removed if it dies.
844 // If the class name in the intent doesn't match that of the target, this is
845 // probably an alias. We have to create a new ComponentName object to keep track
846 // of the real activity name, so that FLAG_ACTIVITY_CLEAR_TOP is handled properly.
847 if (aInfo.targetActivity == null
848 || (aInfo.targetActivity.equals(_intent.getComponent().getClassName())
849 && (aInfo.launchMode == LAUNCH_MULTIPLE
850 || aInfo.launchMode == LAUNCH_SINGLE_TOP))) {
851 realActivity = _intent.getComponent();
853 realActivity = new ComponentName(aInfo.packageName, aInfo.targetActivity);
855 taskAffinity = aInfo.taskAffinity;
856 stateNotNeeded = (aInfo.flags & FLAG_STATE_NOT_NEEDED) != 0;
857 appInfo = aInfo.applicationInfo;
858 nonLocalizedLabel = aInfo.nonLocalizedLabel;
859 labelRes = aInfo.labelRes;
860 if (nonLocalizedLabel == null && labelRes == 0) {
861 ApplicationInfo app = aInfo.applicationInfo;
862 nonLocalizedLabel = app.nonLocalizedLabel;
863 labelRes = app.labelRes;
865 icon = aInfo.getIconResource();
866 logo = aInfo.getLogoResource();
867 theme = aInfo.getThemeResource();
869 if (realTheme == 0) {
870 realTheme = aInfo.applicationInfo.targetSdkVersion < HONEYCOMB
871 ? android.R.style.Theme : android.R.style.Theme_Holo;
873 if ((aInfo.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
874 windowFlags |= LayoutParams.FLAG_HARDWARE_ACCELERATED;
876 if ((aInfo.flags & FLAG_MULTIPROCESS) != 0 && _caller != null
877 && (aInfo.applicationInfo.uid == SYSTEM_UID
878 || aInfo.applicationInfo.uid == _caller.info.uid)) {
879 processName = _caller.processName;
881 processName = aInfo.processName;
884 if ((aInfo.flags & FLAG_EXCLUDE_FROM_RECENTS) != 0) {
885 intent.addFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
888 packageName = aInfo.applicationInfo.packageName;
889 launchMode = aInfo.launchMode;
891 Entry ent = AttributeCache.instance().get(packageName,
892 realTheme, com.android.internal.R.styleable.Window, userId);
893 final boolean translucent = ent != null && (ent.array.getBoolean(
894 com.android.internal.R.styleable.Window_windowIsTranslucent, false)
895 || (!ent.array.hasValue(
896 com.android.internal.R.styleable.Window_windowIsTranslucent)
897 && ent.array.getBoolean(
898 com.android.internal.R.styleable.Window_windowSwipeToDismiss,
900 fullscreen = ent != null && !ent.array.getBoolean(
901 com.android.internal.R.styleable.Window_windowIsFloating, false) && !translucent;
902 noDisplay = ent != null && ent.array.getBoolean(
903 com.android.internal.R.styleable.Window_windowNoDisplay, false);
905 setActivityType(_componentSpecified, _launchedFromUid, _intent, options, sourceRecord);
907 immersive = (aInfo.flags & FLAG_IMMERSIVE) != 0;
909 requestedVrComponent = (aInfo.requestedVrComponent == null) ?
910 null : ComponentName.unflattenFromString(aInfo.requestedVrComponent);
913 AppWindowContainerController getWindowContainerController() {
914 return mWindowContainerController;
917 void createWindowContainer() {
918 if (mWindowContainerController != null) {
919 throw new IllegalArgumentException("Window container=" + mWindowContainerController
920 + " already created for r=" + this);
925 final TaskWindowContainerController taskController = task.getWindowContainerController();
927 // TODO(b/36505427): Maybe this call should be moved inside updateOverrideConfiguration()
928 task.updateOverrideConfigurationFromLaunchBounds();
929 // Make sure override configuration is up-to-date before using to create window controller.
930 updateOverrideConfiguration();
932 mWindowContainerController = new AppWindowContainerController(taskController, appToken,
933 this, Integer.MAX_VALUE /* add on top */, info.screenOrientation, fullscreen,
934 (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, info.configChanges,
935 task.voiceSession != null, mLaunchTaskBehind, isAlwaysFocusable(),
936 appInfo.targetSdkVersion, mRotationAnimationHint,
937 ActivityManagerService.getInputDispatchingTimeoutLocked(this) * 1000000L,
938 getOverrideConfiguration(), mBounds);
940 task.addActivityToTop(this);
942 onOverrideConfigurationSent();
945 void removeWindowContainer() {
946 // Resume key dispatching if it is currently paused before we remove the container.
947 resumeKeyDispatchingLocked();
949 mWindowContainerController.removeContainer(getDisplayId());
950 mWindowContainerController = null;
954 * Reparents this activity into {@param newTask} at the provided {@param position}. The caller
955 * should ensure that the {@param newTask} is not already the parent of this activity.
957 void reparent(TaskRecord newTask, int position, String reason) {
958 final TaskRecord prevTask = task;
959 if (prevTask == newTask) {
960 throw new IllegalArgumentException(reason + ": task=" + newTask
961 + " is already the parent of r=" + this);
964 // TODO: Ensure that we do not directly reparent activities across stacks, as that may leave
965 // the stacks in strange states. For now, we should use Task.reparent() to ensure that
966 // the stack is left in an OK state.
967 if (prevTask != null && newTask != null && prevTask.getStack() != newTask.getStack()) {
968 throw new IllegalArgumentException(reason + ": task=" + newTask
969 + " is in a different stack (" + newTask.getStackId() + ") than the parent of"
970 + " r=" + this + " (" + prevTask.getStackId() + ")");
973 // Must reparent first in window manager
974 mWindowContainerController.reparent(newTask.getWindowContainerController(), position);
976 // Remove the activity from the old task and add it to the new task.
977 prevTask.removeActivity(this, true /*reparenting*/);
979 newTask.addActivityAtIndex(position, this);
982 private boolean isHomeIntent(Intent intent) {
983 return ACTION_MAIN.equals(intent.getAction())
984 && intent.hasCategory(CATEGORY_HOME)
985 && intent.getCategories().size() == 1
986 && intent.getData() == null
987 && intent.getType() == null;
990 static boolean isMainIntent(Intent intent) {
991 return ACTION_MAIN.equals(intent.getAction())
992 && intent.hasCategory(CATEGORY_LAUNCHER)
993 && intent.getCategories().size() == 1
994 && intent.getData() == null
995 && intent.getType() == null;
998 private boolean canLaunchHomeActivity(int uid, ActivityRecord sourceRecord) {
999 if (uid == Process.myUid() || uid == 0) {
1000 // System process can launch home activity.
1003 // Resolver activity can launch home activity.
1004 return sourceRecord != null && sourceRecord.isResolverActivity();
1008 * @return whether the given package name can launch an assist activity.
1010 private boolean canLaunchAssistActivity(String packageName) {
1011 if (service.mAssistUtils == null) {
1015 final ComponentName assistComponent = service.mAssistUtils.getActiveServiceComponentName();
1016 if (assistComponent != null) {
1017 return assistComponent.getPackageName().equals(packageName);
1022 private void setActivityType(boolean componentSpecified, int launchedFromUid, Intent intent,
1023 ActivityOptions options, ActivityRecord sourceRecord) {
1024 if ((!componentSpecified || canLaunchHomeActivity(launchedFromUid, sourceRecord))
1025 && isHomeIntent(intent) && !isResolverActivity()) {
1026 // This sure looks like a home activity!
1027 mActivityType = HOME_ACTIVITY_TYPE;
1029 if (info.resizeMode == RESIZE_MODE_FORCE_RESIZEABLE
1030 || info.resizeMode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) {
1031 // We only allow home activities to be resizeable if they explicitly requested it.
1032 info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
1034 } else if (realActivity.getClassName().contains(RECENTS_PACKAGE_NAME)) {
1035 mActivityType = RECENTS_ACTIVITY_TYPE;
1036 } else if (options != null && options.getLaunchStackId() == ASSISTANT_STACK_ID
1037 && canLaunchAssistActivity(launchedFromPackage)) {
1038 mActivityType = ASSISTANT_ACTIVITY_TYPE;
1040 mActivityType = APPLICATION_ACTIVITY_TYPE;
1044 void setTaskToAffiliateWith(TaskRecord taskToAffiliateWith) {
1045 if (launchMode != LAUNCH_SINGLE_INSTANCE && launchMode != LAUNCH_SINGLE_TASK) {
1046 task.setTaskToAffiliateWith(taskToAffiliateWith);
1051 * @return Stack value from current task, null if there is no task.
1053 <T extends ActivityStack> T getStack() {
1054 return task != null ? (T) task.getStack() : null;
1057 private int getStackId() {
1058 return getStack() != null ? getStack().mStackId : INVALID_STACK_ID;
1061 boolean changeWindowTranslucency(boolean toOpaque) {
1062 if (fullscreen == toOpaque) {
1066 // Keep track of the number of fullscreen activities in this task.
1067 task.numFullscreen += toOpaque ? +1 : -1;
1069 fullscreen = toOpaque;
1073 void takeFromHistory() {
1076 if (task != null && !finishing) {
1079 clearOptionsLocked();
1083 boolean isInHistory() {
1087 boolean isInStackLocked() {
1088 final ActivityStack stack = getStack();
1089 return stack != null && stack.isInStackLocked(this) != null;
1092 boolean isHomeActivity() {
1093 return mActivityType == HOME_ACTIVITY_TYPE;
1096 boolean isRecentsActivity() {
1097 return mActivityType == RECENTS_ACTIVITY_TYPE;
1100 boolean isAssistantActivity() {
1101 return mActivityType == ASSISTANT_ACTIVITY_TYPE;
1104 boolean isApplicationActivity() {
1105 return mActivityType == APPLICATION_ACTIVITY_TYPE;
1108 boolean isPersistable() {
1109 return (info.persistableMode == PERSIST_ROOT_ONLY ||
1110 info.persistableMode == PERSIST_ACROSS_REBOOTS) &&
1112 (intent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0);
1115 boolean isFocusable() {
1116 return StackId.canReceiveKeys(task.getStackId()) || isAlwaysFocusable();
1119 boolean isResizeable() {
1120 return ActivityInfo.isResizeableMode(info.resizeMode) || info.supportsPictureInPicture();
1124 * @return whether this activity is non-resizeable or forced to be resizeable
1126 boolean isNonResizableOrForcedResizable() {
1127 return info.resizeMode != RESIZE_MODE_RESIZEABLE
1128 && info.resizeMode != RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
1132 * @return whether this activity supports PiP multi-window and can be put in the pinned stack.
1134 boolean supportsPictureInPicture() {
1135 return service.mSupportsPictureInPicture && !isHomeActivity()
1136 && info.supportsPictureInPicture();
1140 * @return whether this activity supports split-screen multi-window and can be put in the docked
1143 boolean supportsSplitScreen() {
1144 // An activity can not be docked even if it is considered resizeable because it only
1145 // supports picture-in-picture mode but has a non-resizeable resizeMode
1146 return service.mSupportsSplitScreenMultiWindow && supportsResizeableMultiWindow();
1150 * @return whether this activity supports freeform multi-window and can be put in the freeform
1153 boolean supportsFreeform() {
1154 return service.mSupportsFreeformWindowManagement && supportsResizeableMultiWindow();
1158 * @return whether this activity supports non-PiP multi-window.
1160 private boolean supportsResizeableMultiWindow() {
1161 return service.mSupportsMultiWindow && !isHomeActivity()
1162 && (ActivityInfo.isResizeableMode(info.resizeMode)
1163 || service.mForceResizableActivities);
1167 * Check whether this activity can be launched on the specified display.
1168 * @param displayId Target display id.
1169 * @return {@code true} if either it is the default display or this activity is resizeable and
1170 * can be put a secondary screen.
1172 boolean canBeLaunchedOnDisplay(int displayId) {
1173 return service.mStackSupervisor.canPlaceEntityOnDisplay(displayId,
1174 supportsResizeableMultiWindow());
1178 * @param beforeStopping Whether this check is for an auto-enter-pip operation, that is to say
1179 * the activity has requested to enter PiP when it would otherwise be stopped.
1181 * @return whether this activity is currently allowed to enter PIP, throwing an exception if
1182 * the activity is not currently visible and {@param noThrow} is not set.
1184 boolean checkEnterPictureInPictureState(String caller, boolean noThrow, boolean beforeStopping) {
1185 if (!supportsPictureInPicture()) {
1189 // Check app-ops and see if PiP is supported for this package
1190 if (!checkEnterPictureInPictureAppOpsState()) {
1194 // Check to see if we are in VR mode, and disallow PiP if so
1195 if (service.shouldDisableNonVrUiLocked()) {
1199 boolean isKeyguardLocked = service.isKeyguardLocked();
1200 boolean isCurrentAppLocked = mStackSupervisor.getLockTaskModeState() != LOCK_TASK_MODE_NONE;
1201 boolean hasPinnedStack = mStackSupervisor.getStack(PINNED_STACK_ID) != null;
1202 // Don't return early if !isNotLocked, since we want to throw an exception if the activity
1203 // is in an incorrect state
1204 boolean isNotLockedOrOnKeyguard = !isKeyguardLocked && !isCurrentAppLocked;
1206 // We don't allow auto-PiP when something else is already pipped.
1207 if (beforeStopping && hasPinnedStack) {
1213 // When visible, allow entering PiP if the app is not locked. If it is over the
1214 // keyguard, then we will prompt to unlock in the caller before entering PiP.
1215 return !isCurrentAppLocked &&
1216 (supportsPictureInPictureWhilePausing || !beforeStopping);
1219 // When pausing, then only allow enter PiP as in the resume state, and in addition,
1220 // require that there is not an existing PiP activity and that the current system
1221 // state supports entering PiP
1222 return isNotLockedOrOnKeyguard && !hasPinnedStack
1223 && supportsPictureInPictureWhilePausing;
1225 // When stopping in a valid state, then only allow enter PiP as in the pause state.
1226 // Otherwise, fall through to throw an exception if the caller is trying to enter
1227 // PiP in an invalid stopping state.
1228 if (supportsPictureInPictureWhilePausing) {
1229 return isNotLockedOrOnKeyguard && !hasPinnedStack;
1235 throw new IllegalStateException(caller
1236 + ": Current activity is not visible (state=" + state.name() + ") "
1243 * @return Whether AppOps allows this package to enter picture-in-picture.
1245 private boolean checkEnterPictureInPictureAppOpsState() {
1247 return service.getAppOpsService().checkOperation(OP_PICTURE_IN_PICTURE,
1248 appInfo.uid, packageName) == MODE_ALLOWED;
1249 } catch (RemoteException e) {
1255 boolean isAlwaysFocusable() {
1256 return (info.flags & FLAG_ALWAYS_FOCUSABLE) != 0;
1260 * @return true if the activity contains windows that have
1261 * {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} set
1263 boolean hasShowWhenLockedWindows() {
1264 return service.mWindowManager.containsShowWhenLockedWindow(appToken);
1268 * @return true if the activity contains windows that have
1269 * {@link LayoutParams#FLAG_DISMISS_KEYGUARD} set
1271 boolean hasDismissKeyguardWindows() {
1272 return service.mWindowManager.containsDismissKeyguardWindow(appToken);
1275 void makeFinishingLocked() {
1277 final ActivityStack stack = getStack();
1278 if (stack != null && this == stack.getVisibleBehindActivity()) {
1279 // A finishing activity should not remain as visible in the background
1280 mStackSupervisor.requestVisibleBehindLocked(this, false);
1284 clearOptionsLocked();
1287 if (service != null) {
1288 service.mTaskChangeNotificationController.notifyTaskStackChanged();
1293 UriPermissionOwner getUriPermissionsLocked() {
1294 if (uriPermissions == null) {
1295 uriPermissions = new UriPermissionOwner(service, this);
1297 return uriPermissions;
1300 void addResultLocked(ActivityRecord from, String resultWho,
1301 int requestCode, int resultCode,
1302 Intent resultData) {
1303 ActivityResult r = new ActivityResult(from, resultWho,
1304 requestCode, resultCode, resultData);
1305 if (results == null) {
1306 results = new ArrayList<ResultInfo>();
1311 void removeResultsLocked(ActivityRecord from, String resultWho,
1313 if (results != null) {
1314 for (int i=results.size()-1; i>=0; i--) {
1315 ActivityResult r = (ActivityResult)results.get(i);
1316 if (r.mFrom != from) continue;
1317 if (r.mResultWho == null) {
1318 if (resultWho != null) continue;
1320 if (!r.mResultWho.equals(resultWho)) continue;
1322 if (r.mRequestCode != requestCode) continue;
1329 private void addNewIntentLocked(ReferrerIntent intent) {
1330 if (newIntents == null) {
1331 newIntents = new ArrayList<>();
1333 newIntents.add(intent);
1337 * Deliver a new Intent to an existing activity, so that its onNewIntent()
1338 * method will be called at the proper time.
1340 final void deliverNewIntentLocked(int callingUid, Intent intent, String referrer) {
1341 // The activity now gets access to the data associated with this Intent.
1342 service.grantUriPermissionFromIntentLocked(callingUid, packageName,
1343 intent, getUriPermissionsLocked(), userId);
1344 final ReferrerIntent rintent = new ReferrerIntent(intent, referrer);
1345 boolean unsent = true;
1346 final ActivityStack stack = getStack();
1347 final boolean isTopActivityInStack =
1348 stack != null && stack.topRunningActivityLocked() == this;
1349 final boolean isTopActivityWhileSleeping =
1350 service.isSleepingLocked() && isTopActivityInStack;
1352 // We want to immediately deliver the intent to the activity if:
1353 // - It is currently resumed or paused. i.e. it is currently visible to the user and we want
1354 // the user to see the visual effects caused by the intent delivery now.
1355 // - The device is sleeping and it is the top activity behind the lock screen (b/6700897).
1356 if ((state == RESUMED || state == PAUSED
1357 || isTopActivityWhileSleeping) && app != null && app.thread != null) {
1359 ArrayList<ReferrerIntent> ar = new ArrayList<>(1);
1361 app.thread.scheduleNewIntent(
1362 ar, appToken, state == PAUSED /* andPause */);
1364 } catch (RemoteException e) {
1365 Slog.w(TAG, "Exception thrown sending new intent to " + this, e);
1366 } catch (NullPointerException e) {
1367 Slog.w(TAG, "Exception thrown sending new intent to " + this, e);
1371 addNewIntentLocked(rintent);
1375 void updateOptionsLocked(ActivityOptions options) {
1376 if (options != null) {
1377 if (pendingOptions != null) {
1378 pendingOptions.abort();
1380 pendingOptions = options;
1384 void applyOptionsLocked() {
1385 if (pendingOptions != null
1386 && pendingOptions.getAnimationType() != ANIM_SCENE_TRANSITION) {
1387 final int animationType = pendingOptions.getAnimationType();
1388 switch (animationType) {
1390 service.mWindowManager.overridePendingAppTransition(
1391 pendingOptions.getPackageName(),
1392 pendingOptions.getCustomEnterResId(),
1393 pendingOptions.getCustomExitResId(),
1394 pendingOptions.getOnAnimationStartListener());
1396 case ANIM_CLIP_REVEAL:
1397 service.mWindowManager.overridePendingAppTransitionClipReveal(
1398 pendingOptions.getStartX(), pendingOptions.getStartY(),
1399 pendingOptions.getWidth(), pendingOptions.getHeight());
1400 if (intent.getSourceBounds() == null) {
1401 intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
1402 pendingOptions.getStartY(),
1403 pendingOptions.getStartX()+pendingOptions.getWidth(),
1404 pendingOptions.getStartY()+pendingOptions.getHeight()));
1408 service.mWindowManager.overridePendingAppTransitionScaleUp(
1409 pendingOptions.getStartX(), pendingOptions.getStartY(),
1410 pendingOptions.getWidth(), pendingOptions.getHeight());
1411 if (intent.getSourceBounds() == null) {
1412 intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
1413 pendingOptions.getStartY(),
1414 pendingOptions.getStartX()+pendingOptions.getWidth(),
1415 pendingOptions.getStartY()+pendingOptions.getHeight()));
1418 case ANIM_THUMBNAIL_SCALE_UP:
1419 case ANIM_THUMBNAIL_SCALE_DOWN:
1420 boolean scaleUp = (animationType == ANIM_THUMBNAIL_SCALE_UP);
1421 service.mWindowManager.overridePendingAppTransitionThumb(
1422 pendingOptions.getThumbnail(),
1423 pendingOptions.getStartX(), pendingOptions.getStartY(),
1424 pendingOptions.getOnAnimationStartListener(),
1426 if (intent.getSourceBounds() == null) {
1427 intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
1428 pendingOptions.getStartY(),
1429 pendingOptions.getStartX()
1430 + pendingOptions.getThumbnail().getWidth(),
1431 pendingOptions.getStartY()
1432 + pendingOptions.getThumbnail().getHeight()));
1435 case ANIM_THUMBNAIL_ASPECT_SCALE_UP:
1436 case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN:
1437 final AppTransitionAnimationSpec[] specs = pendingOptions.getAnimSpecs();
1438 if (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_DOWN
1440 service.mWindowManager.overridePendingAppTransitionMultiThumb(
1441 specs, pendingOptions.getOnAnimationStartListener(),
1442 pendingOptions.getAnimationFinishedListener(), false);
1444 service.mWindowManager.overridePendingAppTransitionAspectScaledThumb(
1445 pendingOptions.getThumbnail(),
1446 pendingOptions.getStartX(), pendingOptions.getStartY(),
1447 pendingOptions.getWidth(), pendingOptions.getHeight(),
1448 pendingOptions.getOnAnimationStartListener(),
1449 (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_UP));
1450 if (intent.getSourceBounds() == null) {
1451 intent.setSourceBounds(new Rect(pendingOptions.getStartX(),
1452 pendingOptions.getStartY(),
1453 pendingOptions.getStartX() + pendingOptions.getWidth(),
1454 pendingOptions.getStartY() + pendingOptions.getHeight()));
1459 Slog.e(TAG, "applyOptionsLocked: Unknown animationType=" + animationType);
1462 pendingOptions = null;
1466 ActivityOptions getOptionsForTargetActivityLocked() {
1467 return pendingOptions != null ? pendingOptions.forTargetActivity() : null;
1470 void clearOptionsLocked() {
1471 if (pendingOptions != null) {
1472 pendingOptions.abort();
1473 pendingOptions = null;
1477 ActivityOptions takeOptionsLocked() {
1478 ActivityOptions opts = pendingOptions;
1479 pendingOptions = null;
1483 void removeUriPermissionsLocked() {
1484 if (uriPermissions != null) {
1485 uriPermissions.removeUriPermissionsLocked();
1486 uriPermissions = null;
1490 void pauseKeyDispatchingLocked() {
1493 mWindowContainerController.pauseKeyDispatching();
1497 void resumeKeyDispatchingLocked() {
1500 mWindowContainerController.resumeKeyDispatching();
1504 void updateThumbnailLocked(Bitmap newThumbnail, CharSequence description) {
1505 if (newThumbnail != null) {
1506 if (DEBUG_THUMBNAILS) Slog.i(TAG_THUMBNAILS,
1507 "Setting thumbnail of " + this + " to " + newThumbnail);
1508 boolean thumbnailUpdated = task.setLastThumbnailLocked(newThumbnail);
1509 if (thumbnailUpdated && isPersistable()) {
1510 service.notifyTaskPersisterLocked(task, false);
1513 task.lastDescription = description;
1516 final Bitmap screenshotActivityLocked() {
1517 if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "screenshotActivityLocked: " + this);
1519 if (ENABLE_TASK_SNAPSHOTS) {
1520 // No need to screenshot if snapshots are enabled.
1521 if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS,
1522 "\tSnapshots are enabled, abort taking screenshot");
1527 if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "\tNo display");
1531 final ActivityStack stack = getStack();
1532 if (stack.isHomeOrRecentsStack()) {
1533 // This is an optimization -- since we never show Home or Recents within Recents itself,
1534 // we can just go ahead and skip taking the screenshot if this is the home stack.
1535 if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, stack.getStackId() == HOME_STACK_ID ?
1536 "\tHome stack" : "\tRecents stack");
1540 int w = service.mThumbnailWidth;
1541 int h = service.mThumbnailHeight;
1544 Slog.e(TAG, "\tInvalid thumbnail dimensions: " + w + "x" + h);
1548 if (stack.mStackId == DOCKED_STACK_ID && mStackSupervisor.mIsDockMinimized) {
1549 // When the docked stack is minimized its app windows are cropped significantly so any
1550 // screenshot taken will not display the apps contain. So, we avoid taking a screenshot
1552 if (DEBUG_SCREENSHOTS) Slog.e(TAG, "\tIn minimized docked stack");
1557 if (DEBUG_SCREENSHOTS) Slog.d(TAG_SCREENSHOTS, "\tTaking screenshot");
1559 // When this flag is set, we currently take the fullscreen screenshot of the activity but
1560 // scaled to half the size. This gives us a "good-enough" fullscreen thumbnail to use within
1561 // SystemUI while keeping memory usage low.
1562 if (TAKE_FULLSCREEN_SCREENSHOTS) {
1564 scale = service.mFullscreenThumbnailScale;
1567 return mWindowContainerController.screenshotApplications(getDisplayId(), w, h, scale);
1570 void setVisibility(boolean visible) {
1571 mWindowContainerController.setVisibility(visible, false /* deferHidingClient */);
1574 void setVisible(boolean newVisible) {
1575 setVisible(newVisible, false /* deferHidingClient */);
1578 // TODO: Look into merging with #setVisibility()
1579 void setVisible(boolean newVisible, boolean deferHidingClient) {
1580 visible = newVisible;
1581 if (!visible && mUpdateTaskThumbnailWhenHidden) {
1582 updateThumbnailLocked(screenshotActivityLocked(), null /* description */);
1583 mUpdateTaskThumbnailWhenHidden = false;
1585 mWindowContainerController.setVisibility(visible, deferHidingClient);
1586 final ArrayList<ActivityContainer> containers = mChildContainers;
1587 for (int containerNdx = containers.size() - 1; containerNdx >= 0; --containerNdx) {
1588 final ActivityContainer container = containers.get(containerNdx);
1589 container.setVisible(visible);
1591 mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
1594 void notifyAppResumed(boolean wasStopped) {
1595 mWindowContainerController.notifyAppResumed(wasStopped);
1598 void notifyUnknownVisibilityLaunched() {
1599 mWindowContainerController.notifyUnknownVisibilityLaunched();
1603 * @return true if the input activity should be made visible, ignoring any effect Keyguard
1604 * might have on the visibility
1606 * @see {@link ActivityStack#checkKeyguardVisibility}
1608 boolean shouldBeVisibleIgnoringKeyguard(boolean behindTranslucentActivity,
1609 boolean stackVisibleBehind, ActivityRecord visibleBehind,
1610 boolean behindFullscreenActivity) {
1611 if (!okToShowLocked()) {
1615 // mLaunchingBehind: Activities launching behind are at the back of the task stack
1616 // but must be drawn initially for the animation as though they were visible.
1617 final boolean activityVisibleBehind =
1618 (behindTranslucentActivity || stackVisibleBehind) && visibleBehind == this;
1621 !behindFullscreenActivity || mLaunchTaskBehind || activityVisibleBehind;
1623 if (service.mSupportsLeanbackOnly && isVisible && isRecentsActivity()) {
1624 // On devices that support leanback only (Android TV), Recents activity can only be
1625 // visible if the home stack is the focused stack or we are in split-screen mode.
1626 isVisible = mStackSupervisor.getStack(DOCKED_STACK_ID) != null
1627 || mStackSupervisor.isFocusedStack(getStack());
1633 void makeVisibleIfNeeded(ActivityRecord starting) {
1634 // This activity is not currently visible, but is running. Tell it to become visible.
1635 if (state == RESUMED || this == starting) {
1636 if (DEBUG_VISIBILITY) Slog.d(TAG_VISIBILITY,
1637 "Not making visible, r=" + this + " state=" + state + " starting=" + starting);
1641 // If this activity is paused, tell it to now show its window.
1642 if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY,
1643 "Making visible and scheduling visibility: " + this);
1644 final ActivityStack stack = getStack();
1646 if (stack.mTranslucentActivityWaiting != null) {
1647 updateOptionsLocked(returningOptions);
1648 stack.mUndrawnActivitiesBelowTopTranslucent.add(this);
1652 app.pendingUiClean = true;
1653 app.thread.scheduleWindowVisibility(appToken, true /* showWindow */);
1654 // The activity may be waiting for stop, but that is no longer appropriate for it.
1655 mStackSupervisor.mStoppingActivities.remove(this);
1656 mStackSupervisor.mGoingToSleepActivities.remove(this);
1657 } catch (Exception e) {
1658 // Just skip on any failure; we'll make it visible when it next restarts.
1659 Slog.w(TAG, "Exception thrown making visibile: " + intent.getComponent(), e);
1661 handleAlreadyVisible();
1664 boolean handleAlreadyVisible() {
1665 stopFreezingScreenLocked(false);
1667 if (returningOptions != null) {
1668 app.thread.scheduleOnNewActivityOptions(appToken, returningOptions.toBundle());
1670 } catch(RemoteException e) {
1672 return state == RESUMED;
1675 static void activityResumedLocked(IBinder token) {
1676 final ActivityRecord r = ActivityRecord.forTokenLocked(token);
1677 if (DEBUG_SAVED_STATE) Slog.i(TAG_STATES, "Resumed activity; dropping state of: " + r);
1680 r.haveState = false;
1685 * Once we know that we have asked an application to put an activity in the resumed state
1686 * (either by launching it or explicitly telling it), this function updates the rest of our
1687 * state to match that fact.
1689 void completeResumeLocked() {
1690 final boolean wasVisible = visible;
1693 // Visibility has changed, so take a note of it so we call the TaskStackChangedListener
1694 mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
1701 if (isHomeActivity()) {
1702 ProcessRecord app = task.mActivities.get(0).app;
1703 if (app != null && app != service.mHomeProcess) {
1704 service.mHomeProcess = app;
1709 // We won't get a call to reportActivityVisibleLocked() so dismiss lockscreen now.
1710 mStackSupervisor.reportActivityVisibleLocked(this);
1713 // Schedule an idle timeout in case the app doesn't do it for us.
1714 mStackSupervisor.scheduleIdleTimeoutLocked(this);
1716 mStackSupervisor.reportResumedActivityLocked(this);
1718 resumeKeyDispatchingLocked();
1719 final ActivityStack stack = getStack();
1720 stack.mNoAnimActivities.clear();
1722 // Mark the point when the activity is resuming
1723 // TODO: To be more accurate, the mark should be before the onCreate,
1724 // not after the onResume. But for subsequent starts, onResume is fine.
1726 cpuTimeAtResume = service.mProcessCpuTracker.getCpuTimeForPid(app.pid);
1728 cpuTimeAtResume = 0; // Couldn't get the cpu time of process
1731 returningOptions = null;
1733 if (stack.getVisibleBehindActivity() == this) {
1734 // When resuming an activity, require it to call requestVisibleBehind() again.
1735 stack.setVisibleBehindActivity(null /* ActivityRecord */);
1737 mStackSupervisor.checkReadyForSleepLocked();
1740 final void activityStoppedLocked(Bundle newIcicle, PersistableBundle newPersistentState,
1741 CharSequence description) {
1742 final ActivityStack stack = getStack();
1743 if (state != STOPPING) {
1744 Slog.i(TAG, "Activity reported stop, but no longer stopping: " + this);
1745 stack.mHandler.removeMessages(STOP_TIMEOUT_MSG, this);
1748 if (newPersistentState != null) {
1749 persistentState = newPersistentState;
1750 service.notifyTaskPersisterLocked(task, false);
1752 if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE, "Saving icicle of " + this + ": " + icicle);
1754 if (newIcicle != null) {
1755 // If icicle is null, this is happening due to a timeout, so we haven't really saved
1760 updateThumbnailLocked(null /* newThumbnail */, description);
1763 if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to STOPPED: " + this + " (stop complete)");
1764 stack.mHandler.removeMessages(STOP_TIMEOUT_MSG, this);
1768 mWindowContainerController.notifyAppStopped();
1770 if (stack.getVisibleBehindActivity() == this) {
1771 mStackSupervisor.requestVisibleBehindLocked(this, false /* visible */);
1774 clearOptionsLocked();
1776 if (deferRelaunchUntilPaused) {
1777 stack.destroyActivityLocked(this, true /* removeFromApp */, "stop-config");
1778 mStackSupervisor.resumeFocusedStackTopActivityLocked();
1780 mStackSupervisor.updatePreviousProcessLocked(this);
1786 void startLaunchTickingLocked() {
1787 if (IS_USER_BUILD) {
1790 if (launchTickTime == 0) {
1791 launchTickTime = SystemClock.uptimeMillis();
1792 continueLaunchTickingLocked();
1796 boolean continueLaunchTickingLocked() {
1797 if (launchTickTime == 0) {
1801 final ActivityStack stack = getStack();
1802 if (stack == null) {
1806 Message msg = stack.mHandler.obtainMessage(LAUNCH_TICK_MSG, this);
1807 stack.mHandler.removeMessages(LAUNCH_TICK_MSG);
1808 stack.mHandler.sendMessageDelayed(msg, LAUNCH_TICK);
1812 void finishLaunchTickingLocked() {
1814 final ActivityStack stack = getStack();
1815 if (stack != null) {
1816 stack.mHandler.removeMessages(LAUNCH_TICK_MSG);
1820 // IApplicationToken
1822 public boolean mayFreezeScreenLocked(ProcessRecord app) {
1823 // Only freeze the screen if this activity is currently attached to
1824 // an application, and that application is not blocked or unresponding.
1825 // In any other case, we can't count on getting the screen unfrozen,
1826 // so it is best to leave as-is.
1827 return app != null && !app.crashing && !app.notResponding;
1830 public void startFreezingScreenLocked(ProcessRecord app, int configChanges) {
1831 if (mayFreezeScreenLocked(app)) {
1832 mWindowContainerController.startFreezingScreen(configChanges);
1836 public void stopFreezingScreenLocked(boolean force) {
1837 if (force || frozenBeforeDestroy) {
1838 frozenBeforeDestroy = false;
1839 mWindowContainerController.stopFreezingScreen(force);
1843 public void reportFullyDrawnLocked() {
1844 final long curTime = SystemClock.uptimeMillis();
1845 if (displayStartTime != 0) {
1846 reportLaunchTimeLocked(curTime);
1848 final ActivityStack stack = getStack();
1849 if (fullyDrawnStartTime != 0 && stack != null) {
1850 final long thisTime = curTime - fullyDrawnStartTime;
1851 final long totalTime = stack.mFullyDrawnStartTime != 0
1852 ? (curTime - stack.mFullyDrawnStartTime) : thisTime;
1853 if (SHOW_ACTIVITY_START_TIME) {
1854 Trace.asyncTraceEnd(TRACE_TAG_ACTIVITY_MANAGER, "drawing", 0);
1855 EventLog.writeEvent(AM_ACTIVITY_FULLY_DRAWN_TIME,
1856 userId, System.identityHashCode(this), shortComponentName,
1857 thisTime, totalTime);
1858 StringBuilder sb = service.mStringBuilder;
1860 sb.append("Fully drawn ");
1861 sb.append(shortComponentName);
1863 TimeUtils.formatDuration(thisTime, sb);
1864 if (thisTime != totalTime) {
1865 sb.append(" (total ");
1866 TimeUtils.formatDuration(totalTime, sb);
1869 Log.i(TAG, sb.toString());
1871 if (totalTime > 0) {
1872 //service.mUsageStatsService.noteFullyDrawnTime(realActivity, (int) totalTime);
1874 stack.mFullyDrawnStartTime = 0;
1876 fullyDrawnStartTime = 0;
1879 private void reportLaunchTimeLocked(final long curTime) {
1880 final ActivityStack stack = getStack();
1881 if (stack == null) {
1884 final long thisTime = curTime - displayStartTime;
1885 final long totalTime = stack.mLaunchStartTime != 0
1886 ? (curTime - stack.mLaunchStartTime) : thisTime;
1887 if (SHOW_ACTIVITY_START_TIME) {
1888 Trace.asyncTraceEnd(TRACE_TAG_ACTIVITY_MANAGER, "launching: " + packageName, 0);
1889 EventLog.writeEvent(AM_ACTIVITY_LAUNCH_TIME,
1890 userId, System.identityHashCode(this), shortComponentName,
1891 thisTime, totalTime);
1892 StringBuilder sb = service.mStringBuilder;
1894 sb.append("Displayed ");
1895 sb.append(shortComponentName);
1897 TimeUtils.formatDuration(thisTime, sb);
1898 if (thisTime != totalTime) {
1899 sb.append(" (total ");
1900 TimeUtils.formatDuration(totalTime, sb);
1903 Log.i(TAG, sb.toString());
1905 mStackSupervisor.reportActivityLaunchedLocked(false, this, thisTime, totalTime);
1906 if (totalTime > 0) {
1907 //service.mUsageStatsService.noteLaunchTime(realActivity, (int)totalTime);
1909 displayStartTime = 0;
1910 stack.mLaunchStartTime = 0;
1914 public void onStartingWindowDrawn() {
1915 synchronized (service) {
1916 mStackSupervisor.mActivityMetricsLogger.notifyStartingWindowDrawn(getStackId());
1921 public void onWindowsDrawn() {
1922 synchronized (service) {
1923 mStackSupervisor.mActivityMetricsLogger.notifyWindowsDrawn(getStackId());
1924 if (displayStartTime != 0) {
1925 reportLaunchTimeLocked(SystemClock.uptimeMillis());
1927 mStackSupervisor.sendWaitingVisibleReportLocked(this);
1929 finishLaunchTickingLocked();
1931 task.hasBeenVisible = true;
1937 public void onWindowsVisible() {
1938 synchronized (service) {
1939 mStackSupervisor.reportActivityVisibleLocked(this);
1940 if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsVisibleLocked(): " + this);
1943 lastVisibleTime = SystemClock.uptimeMillis();
1945 // Instead of doing the full stop routine here, let's just hide any activities
1946 // we now can, and let them stop when the normal idle happens.
1947 mStackSupervisor.processStoppingActivitiesLocked(null /* idleActivity */,
1948 false /* remove */, true /* processPausingActivities */);
1950 // If this activity was already idle, then we now need to make sure we perform
1951 // the full stop of any activities that are waiting to do so. This is because
1952 // we won't do that while they are still waiting for this one to become visible.
1953 final int size = mStackSupervisor.mActivitiesWaitingForVisibleActivity.size();
1955 for (int i = 0; i < size; i++) {
1956 final ActivityRecord r =
1957 mStackSupervisor.mActivitiesWaitingForVisibleActivity.get(i);
1958 if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "Was waiting for visible: " + r);
1960 mStackSupervisor.mActivitiesWaitingForVisibleActivity.clear();
1961 mStackSupervisor.scheduleIdleLocked();
1964 service.scheduleAppGcsLocked();
1970 public void onWindowsGone() {
1971 synchronized (service) {
1972 if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsGone(): " + this);
1978 public boolean keyDispatchingTimedOut(String reason, int windowPid) {
1979 ActivityRecord anrActivity;
1980 ProcessRecord anrApp;
1981 boolean windowFromSameProcessAsActivity;
1982 synchronized (service) {
1983 anrActivity = getWaitingHistoryRecordLocked();
1985 windowFromSameProcessAsActivity =
1986 app == null || app.pid == windowPid || windowPid == -1;
1988 if (windowFromSameProcessAsActivity) {
1989 return service.inputDispatchingTimedOut(anrApp, anrActivity, this, false, reason);
1991 // In this case another process added windows using this activity token. So, we call the
1992 // generic service input dispatch timed out method so that the right process is blamed.
1993 return service.inputDispatchingTimedOut(windowPid, false /* aboveSystem */, reason) < 0;
1997 private ActivityRecord getWaitingHistoryRecordLocked() {
1998 // First find the real culprit... if this activity is waiting for
1999 // another activity to start or has stopped, then the key dispatching
2000 // timeout should not be caused by this.
2001 if (mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(this) || stopped) {
2002 final ActivityStack stack = mStackSupervisor.getFocusedStack();
2003 // Try to use the one which is closest to top.
2004 ActivityRecord r = stack.mResumedActivity;
2006 r = stack.mPausingActivity;
2015 /** Checks whether the activity should be shown for current user. */
2016 public boolean okToShowLocked() {
2017 return (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0
2018 || (mStackSupervisor.isCurrentProfileLocked(userId)
2019 && !service.mUserController.isUserStoppingOrShuttingDownLocked(userId));
2023 * This method will return true if the activity is either visible, is becoming visible, is
2024 * currently pausing, or is resumed.
2026 public boolean isInterestingToUserLocked() {
2027 return visible || nowVisible || state == PAUSING ||
2031 void setSleeping(boolean _sleeping) {
2032 setSleeping(_sleeping, false);
2035 void setSleeping(boolean _sleeping, boolean force) {
2036 if (!force && sleeping == _sleeping) {
2039 if (app != null && app.thread != null) {
2041 app.thread.scheduleSleeping(appToken, _sleeping);
2042 if (_sleeping && !mStackSupervisor.mGoingToSleepActivities.contains(this)) {
2043 mStackSupervisor.mGoingToSleepActivities.add(this);
2045 sleeping = _sleeping;
2046 } catch (RemoteException e) {
2047 Slog.w(TAG, "Exception thrown when sleeping: " + intent.getComponent(), e);
2052 static int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
2053 final ActivityRecord r = ActivityRecord.forTokenLocked(token);
2055 return INVALID_TASK_ID;
2057 final TaskRecord task = r.task;
2058 final int activityNdx = task.mActivities.indexOf(r);
2059 if (activityNdx < 0 || (onlyRoot && activityNdx > task.findEffectiveRootIndex())) {
2060 return INVALID_TASK_ID;
2065 static ActivityRecord isInStackLocked(IBinder token) {
2066 final ActivityRecord r = ActivityRecord.forTokenLocked(token);
2067 return (r != null) ? r.getStack().isInStackLocked(r) : null;
2070 static ActivityStack getStackLocked(IBinder token) {
2071 final ActivityRecord r = ActivityRecord.isInStackLocked(token);
2073 return r.getStack();
2079 * @return display id to which this record is attached, -1 if not attached.
2081 int getDisplayId() {
2082 final ActivityStack stack = getStack();
2083 if (stack == null) {
2086 return stack.mDisplayId;
2089 final boolean isDestroyable() {
2090 if (finishing || app == null || state == DESTROYING
2091 || state == DESTROYED) {
2092 // This would be redundant.
2095 final ActivityStack stack = getStack();
2096 if (stack == null || this == stack.mResumedActivity || this == stack.mPausingActivity
2097 || !haveState || !stopped) {
2098 // We're not ready for this kind of thing.
2102 // The user would notice this!
2108 private static String createImageFilename(long createTime, int taskId) {
2109 return String.valueOf(taskId) + ACTIVITY_ICON_SUFFIX + createTime +
2113 void setTaskDescription(TaskDescription _taskDescription) {
2115 if (_taskDescription.getIconFilename() == null &&
2116 (icon = _taskDescription.getIcon()) != null) {
2117 final String iconFilename = createImageFilename(createTime, task.taskId);
2118 final File iconFile = new File(TaskPersister.getUserImagesDir(task.userId),
2120 final String iconFilePath = iconFile.getAbsolutePath();
2121 service.mRecentTasks.saveImage(icon, iconFilePath);
2122 _taskDescription.setIconFilename(iconFilePath);
2124 taskDescription = _taskDescription;
2127 void setVoiceSessionLocked(IVoiceInteractionSession session) {
2128 voiceSession = session;
2129 pendingVoiceInteractionStart = false;
2132 void clearVoiceSessionLocked() {
2133 voiceSession = null;
2134 pendingVoiceInteractionStart = false;
2137 void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch) {
2138 if (mWindowContainerController == null) {
2142 // We don't show starting window for overlay activities.
2146 final CompatibilityInfo compatInfo =
2147 service.compatibilityInfoForPackageLocked(info.applicationInfo);
2148 final boolean shown = mWindowContainerController.addStartingWindow(packageName, theme,
2149 compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags,
2150 prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning(),
2151 allowTaskSnapshot());
2153 mStartingWindowState = STARTING_WINDOW_SHOWN;
2157 void removeOrphanedStartingWindow(boolean behindFullscreenActivity) {
2158 if (state == INITIALIZING
2159 && mStartingWindowState == STARTING_WINDOW_SHOWN
2160 && behindFullscreenActivity) {
2161 if (DEBUG_VISIBILITY) Slog.w(TAG_VISIBILITY, "Found orphaned starting window " + this);
2162 mStartingWindowState = STARTING_WINDOW_REMOVED;
2163 mWindowContainerController.removeStartingWindow();
2167 int getRequestedOrientation() {
2168 return mWindowContainerController.getOrientation();
2171 void setRequestedOrientation(int requestedOrientation) {
2172 final int displayId = getDisplayId();
2173 final Configuration displayConfig =
2174 mStackSupervisor.getDisplayOverrideConfiguration(displayId);
2176 final Configuration config = mWindowContainerController.setOrientation(requestedOrientation,
2177 displayId, displayConfig, mayFreezeScreenLocked(app));
2178 if (config != null) {
2179 frozenBeforeDestroy = true;
2180 if (!service.updateDisplayOverrideConfigurationLocked(config, this,
2181 false /* deferResume */, displayId)) {
2182 mStackSupervisor.resumeFocusedStackTopActivityLocked();
2185 service.mTaskChangeNotificationController.notifyActivityRequestedOrientationChanged(
2186 task.taskId, requestedOrientation);
2189 void setDisablePreviewScreenshots(boolean disable) {
2190 mWindowContainerController.setDisablePreviewScreenshots(disable);
2194 * Set the last reported global configuration to the client. Should be called whenever a new
2195 * global configuration is sent to the client for this activity.
2197 void setLastReportedGlobalConfiguration(@NonNull Configuration config) {
2198 mLastReportedConfiguration.setTo(config);
2202 * Set the last reported merged override configuration to the client. Should be called whenever
2203 * a new merged configuration is sent to the client for this activity.
2205 void setLastReportedMergedOverrideConfiguration(@NonNull Configuration config) {
2206 mLastReportedOverrideConfiguration.setTo(config);
2209 /** Call when override config was sent to the Window Manager to update internal records. */
2210 // TODO(b/36505427): Why do we set last reported based on sending the config to WM? Seems like
2211 // we should only set this when we actually report to the activity which is what the method
2212 // setLastReportedMergedOverrideConfiguration() does. Investigate if this is really needed.
2213 void onOverrideConfigurationSent() {
2214 mLastReportedOverrideConfiguration.setTo(getMergedOverrideConfiguration());
2218 void onOverrideConfigurationChanged(Configuration overrideConfiguration) {
2219 super.onOverrideConfigurationChanged(overrideConfiguration);
2220 if (mWindowContainerController != null) {
2221 mWindowContainerController.onOverrideConfigurationChanged(
2222 overrideConfiguration, mBounds);
2223 // TODO(b/36505427): Can we consolidate the call points of onOverrideConfigurationSent()
2224 // to just use this method instead?
2225 onOverrideConfigurationSent();
2229 // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
2230 private boolean updateOverrideConfiguration() {
2231 computeBounds(mTmpBounds);
2232 if (mTmpBounds.equals(mBounds)) {
2235 mBounds.set(mTmpBounds);
2236 // Bounds changed...update configuration to match.
2237 mTmpConfig1.unset();
2238 task.computeOverrideConfiguration(mTmpConfig1, mBounds, null /* insetBounds */,
2239 false /* overrideWidth */, false /* overrideHeight */);
2240 onOverrideConfigurationChanged(mTmpConfig1);
2245 * Computes the bounds to fit the Activity within the bounds of the {@link Configuration}.
2247 // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer.
2248 private void computeBounds(Rect outBounds) {
2249 outBounds.setEmpty();
2250 final float maxAspectRatio = info.maxAspectRatio;
2251 final ActivityStack stack = getStack();
2252 if (task == null || stack == null || !task.mFullscreen || maxAspectRatio == 0) {
2253 // We don't set override configuration if that activity task isn't fullscreen. I.e. the
2254 // activity is in multi-window mode. Or, there isn't a max aspect ratio specified for
2255 // the activity. This is indicated by an empty {@link outBounds}.
2259 // We must base this on the parent configuration, because we set our override
2260 // configuration's appBounds based on the result of this method. If we used our own
2261 // configuration, it would be influenced by past invocations.
2262 final Configuration configuration = getParent().getConfiguration();
2263 final int containingAppWidth = configuration.appBounds.width();
2264 final int containingAppHeight = configuration.appBounds.height();
2265 int maxActivityWidth = containingAppWidth;
2266 int maxActivityHeight = containingAppHeight;
2268 if (containingAppWidth < containingAppHeight) {
2269 // Width is the shorter side, so we use that to figure-out what the max. height should
2270 // be given the aspect ratio.
2271 maxActivityHeight = (int) ((maxActivityWidth * maxAspectRatio) + 0.5f);
2273 // Height is the shorter side, so we use that to figure-out what the max. width should
2274 // be given the aspect ratio.
2275 maxActivityWidth = (int) ((maxActivityHeight * maxAspectRatio) + 0.5f);
2278 if (containingAppWidth <= maxActivityWidth && containingAppHeight <= maxActivityHeight) {
2279 // The display matches or is less than the activity aspect ratio, so nothing else to do.
2280 // Return the existing bounds. If this method is running for the first time,
2281 // {@link mBounds} will be empty (representing no override). If the method has run
2282 // before, then effect of {@link mBounds} will already have been applied to the
2283 // value returned from {@link getConfiguration}. Refer to
2284 // {@link TaskRecord#computeOverrideConfiguration}.
2285 outBounds.set(mBounds);
2289 // Compute configuration based on max supported width and height.
2290 outBounds.set(0, 0, maxActivityWidth, maxActivityHeight);
2294 * Make sure the given activity matches the current configuration. Returns false if the activity
2295 * had to be destroyed. Returns true if the configuration is the same, or the activity will
2296 * remain running as-is for whatever reason. Ensures the HistoryRecord is updated with the
2297 * correct configuration and all other bookkeeping is handled.
2299 boolean ensureActivityConfigurationLocked(int globalChanges, boolean preserveWindow) {
2300 final ActivityStack stack = getStack();
2301 if (stack.mConfigWillChange) {
2302 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
2303 "Skipping config check (will change): " + this);
2307 // We don't worry about activities that are finishing.
2309 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
2310 "Configuration doesn't matter in finishing " + this);
2311 stopFreezingScreenLocked(false);
2315 // Skip updating configuration for activity that are stopping or stopped.
2316 if (state == STOPPING || state == STOPPED) {
2317 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
2318 "Skipping config check stopped or stopping: " + this);
2322 // Skip updating configuration for activity is a stack that shouldn't be visible.
2323 if (stack.shouldBeVisible(null /* starting */) == STACK_INVISIBLE) {
2324 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
2325 "Skipping config check invisible stack: " + this);
2329 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
2330 "Ensuring correct configuration: " + this);
2332 final int newDisplayId = getDisplayId();
2333 final boolean displayChanged = mLastReportedDisplayId != newDisplayId;
2334 if (displayChanged) {
2335 mLastReportedDisplayId = newDisplayId;
2337 // TODO(b/36505427): Is there a better place to do this?
2338 updateOverrideConfiguration();
2340 // Short circuit: if the two full configurations are equal (the common case), then there is
2341 // nothing to do. We test the full configuration instead of the global and merged override
2342 // configurations because there are cases (like moving a task to the pinned stack) where
2343 // the combine configurations are equal, but would otherwise differ in the override config
2344 mTmpConfig1.setTo(mLastReportedConfiguration);
2345 mTmpConfig1.updateFrom(mLastReportedOverrideConfiguration);
2346 if (getConfiguration().equals(mTmpConfig1) && !forceNewConfig && !displayChanged) {
2347 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
2348 "Configuration & display unchanged in " + this);
2352 // Okay we now are going to make this activity have the new config.
2353 // But then we need to figure out how it needs to deal with that.
2355 // Find changes between last reported merged configuration and the current one. This is used
2356 // to decide whether to relaunch an activity or just report a configuration change.
2357 final int changes = getConfigurationChanges(mTmpConfig1);
2359 // Preserve configuration used to generate this set of configuration changes.
2360 mTmpConfig3.setTo(mTmpConfig1);
2362 // Update last reported values.
2363 final Configuration newGlobalConfig = service.getGlobalConfiguration();
2364 final Configuration newMergedOverrideConfig = getMergedOverrideConfiguration();
2365 mTmpConfig1.setTo(mLastReportedConfiguration);
2366 mTmpConfig2.setTo(mLastReportedOverrideConfiguration);
2367 mLastReportedConfiguration.setTo(newGlobalConfig);
2368 mLastReportedOverrideConfiguration.setTo(newMergedOverrideConfig);
2370 if (changes == 0 && !forceNewConfig) {
2371 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
2372 "Configuration no differences in " + this);
2373 // There are no significant differences, so we won't relaunch but should still deliver
2374 // the new configuration to the client process.
2375 if (displayChanged) {
2376 scheduleActivityMovedToDisplay(newDisplayId, newMergedOverrideConfig);
2378 scheduleConfigurationChanged(newMergedOverrideConfig);
2383 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
2384 "Configuration changes for " + this + ", allChanges="
2385 + Configuration.configurationDiffToString(changes));
2387 // If the activity isn't currently running, just leave the new configuration and it will
2388 // pick that up next time it starts.
2389 if (app == null || app.thread == null) {
2390 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
2391 "Configuration doesn't matter not running " + this);
2392 stopFreezingScreenLocked(false);
2393 forceNewConfig = false;
2397 // Figure out how to handle the changes between the configurations.
2398 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
2399 "Checking to restart " + info.name + ": changed=0x"
2400 + Integer.toHexString(changes) + ", handles=0x"
2401 + Integer.toHexString(info.getRealConfigChanged())
2402 + ", newGlobalConfig=" + newGlobalConfig
2403 + ", newMergedOverrideConfig=" + newMergedOverrideConfig);
2405 if (shouldRelaunchLocked(changes, mTmpConfig3) || forceNewConfig) {
2406 // Aha, the activity isn't handling the change, so DIE DIE DIE.
2407 configChangeFlags |= changes;
2408 startFreezingScreenLocked(app, globalChanges);
2409 forceNewConfig = false;
2410 preserveWindow &= isResizeOnlyChange(changes);
2411 if (app == null || app.thread == null) {
2412 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
2413 "Config is destroying non-running " + this);
2414 stack.destroyActivityLocked(this, true, "config");
2415 } else if (state == PAUSING) {
2416 // A little annoying: we are waiting for this activity to finish pausing. Let's not
2417 // do anything now, but just flag that it needs to be restarted when done pausing.
2418 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
2419 "Config is skipping already pausing " + this);
2420 deferRelaunchUntilPaused = true;
2421 preserveWindowOnDeferredRelaunch = preserveWindow;
2423 } else if (state == RESUMED) {
2424 // Try to optimize this case: the configuration is changing and we need to restart
2425 // the top, resumed activity. Instead of doing the normal handshaking, just say
2427 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
2428 "Config is relaunching resumed " + this);
2430 if (DEBUG_STATES && !visible) {
2431 Slog.v(TAG_STATES, "Config is relaunching resumed invisible activity " + this
2432 + " called by " + Debug.getCallers(4));
2435 relaunchActivityLocked(true /* andResume */, preserveWindow);
2437 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
2438 "Config is relaunching non-resumed " + this);
2439 relaunchActivityLocked(false /* andResume */, preserveWindow);
2442 // All done... tell the caller we weren't able to keep this activity around.
2446 // Default case: the activity can handle this new configuration, so hand it over.
2447 // NOTE: We only forward the override configuration as the system level configuration
2448 // changes is always sent to all processes when they happen so it can just use whatever
2449 // system level configuration it last got.
2450 if (displayChanged) {
2451 scheduleActivityMovedToDisplay(newDisplayId, newMergedOverrideConfig);
2453 scheduleConfigurationChanged(newMergedOverrideConfig);
2455 stopFreezingScreenLocked(false);
2461 * When assessing a configuration change, decide if the changes flags and the new configurations
2462 * should cause the Activity to relaunch.
2464 * @param changes the changes due to the given configuration.
2465 * @param changesConfig the configuration that was used to calculate the given changes via a
2466 * call to getConfigurationChanges.
2468 private boolean shouldRelaunchLocked(int changes, Configuration changesConfig) {
2469 int configChanged = info.getRealConfigChanged();
2470 boolean onlyVrUiModeChanged = onlyVrUiModeChanged(changes, changesConfig);
2472 // Override for apps targeting pre-O sdks
2473 // If a device is in VR mode, and we're transitioning into VR ui mode, add ignore ui mode
2474 // to the config change.
2475 // For O and later, apps will be required to add configChanges="uimode" to their manifest.
2476 if (appInfo.targetSdkVersion < O
2477 && requestedVrComponent != null
2478 && onlyVrUiModeChanged) {
2479 configChanged |= CONFIG_UI_MODE;
2482 return (changes&(~configChanged)) != 0;
2486 * Returns true if the configuration change is solely due to the UI mode switching into or out
2487 * of UI_MODE_TYPE_VR_HEADSET.
2489 private boolean onlyVrUiModeChanged(int changes, Configuration lastReportedConfig) {
2490 final Configuration currentConfig = getConfiguration();
2491 return changes == CONFIG_UI_MODE && (isInVrUiMode(currentConfig)
2492 != isInVrUiMode(lastReportedConfig));
2495 private int getConfigurationChanges(Configuration lastReportedConfig) {
2496 // Determine what has changed. May be nothing, if this is a config that has come back from
2497 // the app after going idle. In that case we just want to leave the official config object
2498 // now in the activity and do nothing else.
2499 final Configuration currentConfig = getConfiguration();
2500 int changes = lastReportedConfig.diff(currentConfig);
2501 // We don't want to use size changes if they don't cross boundaries that are important to
2503 if ((changes & CONFIG_SCREEN_SIZE) != 0) {
2504 final boolean crosses = crossesHorizontalSizeThreshold(lastReportedConfig.screenWidthDp,
2505 currentConfig.screenWidthDp)
2506 || crossesVerticalSizeThreshold(lastReportedConfig.screenHeightDp,
2507 currentConfig.screenHeightDp);
2509 changes &= ~CONFIG_SCREEN_SIZE;
2512 if ((changes & CONFIG_SMALLEST_SCREEN_SIZE) != 0) {
2513 final int oldSmallest = lastReportedConfig.smallestScreenWidthDp;
2514 final int newSmallest = currentConfig.smallestScreenWidthDp;
2515 if (!crossesSmallestSizeThreshold(oldSmallest, newSmallest)) {
2516 changes &= ~CONFIG_SMALLEST_SCREEN_SIZE;
2522 private static boolean isResizeOnlyChange(int change) {
2523 return (change & ~(CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE | CONFIG_ORIENTATION
2524 | CONFIG_SCREEN_LAYOUT)) == 0;
2527 void relaunchActivityLocked(boolean andResume, boolean preserveWindow) {
2528 if (service.mSuppressResizeConfigChanges && preserveWindow) {
2529 configChangeFlags = 0;
2533 List<ResultInfo> pendingResults = null;
2534 List<ReferrerIntent> pendingNewIntents = null;
2536 pendingResults = results;
2537 pendingNewIntents = newIntents;
2539 if (DEBUG_SWITCH) Slog.v(TAG_SWITCH,
2540 "Relaunching: " + this + " with results=" + pendingResults
2541 + " newIntents=" + pendingNewIntents + " andResume=" + andResume
2542 + " preserveWindow=" + preserveWindow);
2543 EventLog.writeEvent(andResume ? AM_RELAUNCH_RESUME_ACTIVITY
2544 : AM_RELAUNCH_ACTIVITY, userId, System.identityHashCode(this),
2545 task.taskId, shortComponentName);
2547 startFreezingScreenLocked(app, 0);
2549 mStackSupervisor.removeChildActivityContainers(this);
2552 if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH,
2553 "Moving to " + (andResume ? "RESUMED" : "PAUSED") + " Relaunching " + this
2554 + " callers=" + Debug.getCallers(6));
2555 forceNewConfig = false;
2556 mStackSupervisor.activityRelaunchingLocked(this);
2557 app.thread.scheduleRelaunchActivity(appToken, pendingResults, pendingNewIntents,
2558 configChangeFlags, !andResume,
2559 new Configuration(service.getGlobalConfiguration()),
2560 new Configuration(getMergedOverrideConfiguration()), preserveWindow);
2561 // Note: don't need to call pauseIfSleepingLocked() here, because the caller will only
2562 // pass in 'andResume' if this activity is currently resumed, which implies we aren't
2564 } catch (RemoteException e) {
2565 if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH, "Relaunch failed", e);
2570 Slog.d(TAG_STATES, "Resumed after relaunch " + this);
2574 service.showUnsupportedZoomDialogIfNeededLocked(this);
2575 service.showAskCompatModeDialogLocked(this);
2577 service.mHandler.removeMessages(PAUSE_TIMEOUT_MSG, this);
2579 // if the app is relaunched when it's stopped, and we're not resuming,
2580 // put it back into stopped state.
2582 getStack().addToStopping(this, true /* scheduleIdle */, false /* idleDelayed */);
2586 configChangeFlags = 0;
2587 deferRelaunchUntilPaused = false;
2588 preserveWindowOnDeferredRelaunch = false;
2591 private boolean isProcessRunning() {
2592 ProcessRecord proc = app;
2594 proc = service.mProcessNames.get(processName, info.applicationInfo.uid);
2596 return proc != null && proc.thread != null;
2600 * @return Whether a task snapshot starting window may be shown.
2602 private boolean allowTaskSnapshot() {
2603 if (newIntents == null) {
2607 // Restrict task snapshot starting window to launcher start, or there is no intent at all
2608 // (eg. task being brought to front). If the intent is something else, likely the app is
2609 // going to show some specific page or view, instead of what's left last time.
2610 for (int i = newIntents.size() - 1; i >= 0; i--) {
2611 final Intent intent = newIntents.get(i);
2612 if (intent != null && !ActivityRecord.isMainIntent(intent)) {
2619 void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
2620 out.attribute(null, ATTR_ID, String.valueOf(createTime));
2621 out.attribute(null, ATTR_LAUNCHEDFROMUID, String.valueOf(launchedFromUid));
2622 if (launchedFromPackage != null) {
2623 out.attribute(null, ATTR_LAUNCHEDFROMPACKAGE, launchedFromPackage);
2625 if (resolvedType != null) {
2626 out.attribute(null, ATTR_RESOLVEDTYPE, resolvedType);
2628 out.attribute(null, ATTR_COMPONENTSPECIFIED, String.valueOf(componentSpecified));
2629 out.attribute(null, ATTR_USERID, String.valueOf(userId));
2631 if (taskDescription != null) {
2632 taskDescription.saveToXml(out);
2635 out.startTag(null, TAG_INTENT);
2636 intent.saveToXml(out);
2637 out.endTag(null, TAG_INTENT);
2639 if (isPersistable() && persistentState != null) {
2640 out.startTag(null, TAG_PERSISTABLEBUNDLE);
2641 persistentState.saveToXml(out);
2642 out.endTag(null, TAG_PERSISTABLEBUNDLE);
2646 static ActivityRecord restoreFromXml(XmlPullParser in,
2647 ActivityStackSupervisor stackSupervisor) throws IOException, XmlPullParserException {
2648 Intent intent = null;
2649 PersistableBundle persistentState = null;
2650 int launchedFromUid = 0;
2651 String launchedFromPackage = null;
2652 String resolvedType = null;
2653 boolean componentSpecified = false;
2655 long createTime = -1;
2656 final int outerDepth = in.getDepth();
2657 TaskDescription taskDescription = new TaskDescription();
2659 for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
2660 final String attrName = in.getAttributeName(attrNdx);
2661 final String attrValue = in.getAttributeValue(attrNdx);
2662 if (DEBUG) Slog.d(TaskPersister.TAG,
2663 "ActivityRecord: attribute name=" + attrName + " value=" + attrValue);
2664 if (ATTR_ID.equals(attrName)) {
2665 createTime = Long.parseLong(attrValue);
2666 } else if (ATTR_LAUNCHEDFROMUID.equals(attrName)) {
2667 launchedFromUid = Integer.parseInt(attrValue);
2668 } else if (ATTR_LAUNCHEDFROMPACKAGE.equals(attrName)) {
2669 launchedFromPackage = attrValue;
2670 } else if (ATTR_RESOLVEDTYPE.equals(attrName)) {
2671 resolvedType = attrValue;
2672 } else if (ATTR_COMPONENTSPECIFIED.equals(attrName)) {
2673 componentSpecified = Boolean.parseBoolean(attrValue);
2674 } else if (ATTR_USERID.equals(attrName)) {
2675 userId = Integer.parseInt(attrValue);
2676 } else if (attrName.startsWith(ATTR_TASKDESCRIPTION_PREFIX)) {
2677 taskDescription.restoreFromXml(attrName, attrValue);
2679 Log.d(TAG, "Unknown ActivityRecord attribute=" + attrName);
2684 while (((event = in.next()) != END_DOCUMENT) &&
2685 (event != END_TAG || in.getDepth() >= outerDepth)) {
2686 if (event == START_TAG) {
2687 final String name = in.getName();
2689 Slog.d(TaskPersister.TAG, "ActivityRecord: START_TAG name=" + name);
2690 if (TAG_INTENT.equals(name)) {
2691 intent = Intent.restoreFromXml(in);
2693 Slog.d(TaskPersister.TAG, "ActivityRecord: intent=" + intent);
2694 } else if (TAG_PERSISTABLEBUNDLE.equals(name)) {
2695 persistentState = PersistableBundle.restoreFromXml(in);
2696 if (DEBUG) Slog.d(TaskPersister.TAG,
2697 "ActivityRecord: persistentState=" + persistentState);
2699 Slog.w(TAG, "restoreActivity: unexpected name=" + name);
2700 XmlUtils.skipCurrentTag(in);
2705 if (intent == null) {
2706 throw new XmlPullParserException("restoreActivity error intent=" + intent);
2709 final ActivityManagerService service = stackSupervisor.mService;
2710 final ActivityInfo aInfo = stackSupervisor.resolveActivity(intent, resolvedType, 0, null,
2712 if (aInfo == null) {
2713 throw new XmlPullParserException("restoreActivity resolver error. Intent=" + intent +
2714 " resolvedType=" + resolvedType);
2716 final ActivityRecord r = new ActivityRecord(service, null /* caller */,
2717 0 /* launchedFromPid */, launchedFromUid, launchedFromPackage, intent, resolvedType,
2718 aInfo, service.getConfiguration(), null /* resultTo */, null /* resultWho */,
2719 0 /* reqCode */, componentSpecified, false /* rootVoiceInteraction */,
2720 stackSupervisor, null /* container */, null /* options */, null /* sourceRecord */);
2722 r.persistentState = persistentState;
2723 r.taskDescription = taskDescription;
2724 r.createTime = createTime;
2729 private static String activityTypeToString(int type) {
2731 case APPLICATION_ACTIVITY_TYPE: return "APPLICATION_ACTIVITY_TYPE";
2732 case HOME_ACTIVITY_TYPE: return "HOME_ACTIVITY_TYPE";
2733 case RECENTS_ACTIVITY_TYPE: return "RECENTS_ACTIVITY_TYPE";
2734 case ASSISTANT_ACTIVITY_TYPE: return "ASSISTANT_ACTIVITY_TYPE";
2735 default: return Integer.toString(type);
2739 private static boolean isInVrUiMode(Configuration config) {
2740 return (config.uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_VR_HEADSET;
2744 return info.applicationInfo.uid;
2748 public String toString() {
2749 if (stringName != null) {
2750 return stringName + " t" + (task == null ? INVALID_TASK_ID : task.taskId) +
2751 (finishing ? " f}" : "}");
2753 StringBuilder sb = new StringBuilder(128);
2754 sb.append("ActivityRecord{");
2755 sb.append(Integer.toHexString(System.identityHashCode(this)));
2759 sb.append(intent.getComponent().flattenToShortString());
2760 stringName = sb.toString();