1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 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 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 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. 15 */ 16 17 package com.android.server.wm; 18 19 import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; 20 import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; 21 import static android.app.ActivityManager.TaskDescription.ATTR_TASKDESCRIPTION_PREFIX; 22 import static android.app.ActivityOptions.ANIM_CLIP_REVEAL; 23 import static android.app.ActivityOptions.ANIM_CUSTOM; 24 import static android.app.ActivityOptions.ANIM_NONE; 25 import static android.app.ActivityOptions.ANIM_OPEN_CROSS_PROFILE_APPS; 26 import static android.app.ActivityOptions.ANIM_REMOTE_ANIMATION; 27 import static android.app.ActivityOptions.ANIM_SCALE_UP; 28 import static android.app.ActivityOptions.ANIM_SCENE_TRANSITION; 29 import static android.app.ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_DOWN; 30 import static android.app.ActivityOptions.ANIM_THUMBNAIL_ASPECT_SCALE_UP; 31 import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_DOWN; 32 import static android.app.ActivityOptions.ANIM_THUMBNAIL_SCALE_UP; 33 import static android.app.ActivityTaskManager.INVALID_STACK_ID; 34 import static android.app.ActivityTaskManager.INVALID_TASK_ID; 35 import static android.app.AppOpsManager.MODE_ALLOWED; 36 import static android.app.AppOpsManager.OP_PICTURE_IN_PICTURE; 37 import static android.app.WaitResult.INVALID_DELAY; 38 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; 39 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; 40 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; 41 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; 42 import static android.app.WindowConfiguration.ROTATION_UNDEFINED; 43 import static android.app.WindowConfiguration.activityTypeToString; 44 import static android.content.Intent.ACTION_MAIN; 45 import static android.content.Intent.CATEGORY_HOME; 46 import static android.content.Intent.CATEGORY_LAUNCHER; 47 import static android.content.Intent.CATEGORY_SECONDARY_HOME; 48 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; 49 import static android.content.Intent.FLAG_ACTIVITY_NO_HISTORY; 50 import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION; 51 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT; 52 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE; 53 import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; 54 import static android.content.pm.ActivityInfo.CONFIG_UI_MODE; 55 import static android.content.pm.ActivityInfo.CONFIG_WINDOW_CONFIGURATION; 56 import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; 57 import static android.content.pm.ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS; 58 import static android.content.pm.ActivityInfo.FLAG_IMMERSIVE; 59 import static android.content.pm.ActivityInfo.FLAG_INHERIT_SHOW_WHEN_LOCKED; 60 import static android.content.pm.ActivityInfo.FLAG_MULTIPROCESS; 61 import static android.content.pm.ActivityInfo.FLAG_NO_HISTORY; 62 import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; 63 import static android.content.pm.ActivityInfo.FLAG_SHOW_WHEN_LOCKED; 64 import static android.content.pm.ActivityInfo.FLAG_STATE_NOT_NEEDED; 65 import static android.content.pm.ActivityInfo.FLAG_TURN_SCREEN_ON; 66 import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE; 67 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE; 68 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK; 69 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP; 70 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS; 71 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT; 72 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED; 73 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER; 74 import static android.content.pm.ActivityInfo.PERSIST_ACROSS_REBOOTS; 75 import static android.content.pm.ActivityInfo.PERSIST_ROOT_ONLY; 76 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; 77 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; 78 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; 79 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; 80 import static android.content.pm.ActivityInfo.isFixedOrientationLandscape; 81 import static android.content.pm.ActivityInfo.isFixedOrientationPortrait; 82 import static android.content.res.Configuration.EMPTY; 83 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; 84 import static android.content.res.Configuration.ORIENTATION_PORTRAIT; 85 import static android.content.res.Configuration.ORIENTATION_UNDEFINED; 86 import static android.content.res.Configuration.UI_MODE_TYPE_MASK; 87 import static android.content.res.Configuration.UI_MODE_TYPE_VR_HEADSET; 88 import static android.os.Build.VERSION_CODES.HONEYCOMB; 89 import static android.os.Build.VERSION_CODES.O; 90 import static android.os.Process.SYSTEM_UID; 91 import static android.view.Display.DEFAULT_DISPLAY; 92 import static android.view.Display.INVALID_DISPLAY; 93 import static android.view.Surface.ROTATION_270; 94 import static android.view.Surface.ROTATION_90; 95 96 import static com.android.server.am.ActivityRecordProto.CONFIGURATION_CONTAINER; 97 import static com.android.server.am.ActivityRecordProto.FRONT_OF_TASK; 98 import static com.android.server.am.ActivityRecordProto.IDENTIFIER; 99 import static com.android.server.am.ActivityRecordProto.PROC_ID; 100 import static com.android.server.am.ActivityRecordProto.STATE; 101 import static com.android.server.am.ActivityRecordProto.TRANSLUCENT; 102 import static com.android.server.am.ActivityRecordProto.VISIBLE; 103 import static com.android.server.am.EventLogTags.AM_RELAUNCH_ACTIVITY; 104 import static com.android.server.am.EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY; 105 import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED; 106 import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING; 107 import static com.android.server.wm.ActivityStack.ActivityState.PAUSED; 108 import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; 109 import static com.android.server.wm.ActivityStack.ActivityState.RESTARTING_PROCESS; 110 import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; 111 import static com.android.server.wm.ActivityStack.ActivityState.STOPPED; 112 import static com.android.server.wm.ActivityStack.ActivityState.STOPPING; 113 import static com.android.server.wm.ActivityStack.LAUNCH_TICK; 114 import static com.android.server.wm.ActivityStack.LAUNCH_TICK_MSG; 115 import static com.android.server.wm.ActivityStack.PAUSE_TIMEOUT_MSG; 116 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE; 117 import static com.android.server.wm.ActivityStack.STOP_TIMEOUT_MSG; 118 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION; 119 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_FOCUS; 120 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SAVED_STATE; 121 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES; 122 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; 123 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TRANSITION; 124 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_VISIBILITY; 125 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION; 126 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_FOCUS; 127 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SAVED_STATE; 128 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STATES; 129 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH; 130 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY; 131 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; 132 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; 133 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE; 134 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE; 135 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; 136 import static com.android.server.wm.IdentifierProto.HASH_CODE; 137 import static com.android.server.wm.IdentifierProto.TITLE; 138 import static com.android.server.wm.IdentifierProto.USER_ID; 139 import static com.android.server.wm.TaskPersister.DEBUG; 140 import static com.android.server.wm.TaskPersister.IMAGE_EXTENSION; 141 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE; 142 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; 143 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW; 144 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT; 145 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 146 147 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; 148 import static org.xmlpull.v1.XmlPullParser.END_TAG; 149 import static org.xmlpull.v1.XmlPullParser.START_TAG; 150 151 import android.annotation.NonNull; 152 import android.annotation.Nullable; 153 import android.app.ActivityManager.TaskDescription; 154 import android.app.ActivityOptions; 155 import android.app.PendingIntent; 156 import android.app.PictureInPictureParams; 157 import android.app.ResultInfo; 158 import android.app.WaitResult.LaunchState; 159 import android.app.servertransaction.ActivityConfigurationChangeItem; 160 import android.app.servertransaction.ActivityLifecycleItem; 161 import android.app.servertransaction.ActivityRelaunchItem; 162 import android.app.servertransaction.ClientTransaction; 163 import android.app.servertransaction.ClientTransactionItem; 164 import android.app.servertransaction.MoveToDisplayItem; 165 import android.app.servertransaction.MultiWindowModeChangeItem; 166 import android.app.servertransaction.NewIntentItem; 167 import android.app.servertransaction.PauseActivityItem; 168 import android.app.servertransaction.PipModeChangeItem; 169 import android.app.servertransaction.ResumeActivityItem; 170 import android.app.servertransaction.StopActivityItem; 171 import android.app.servertransaction.TopResumedActivityChangeItem; 172 import android.app.servertransaction.WindowVisibilityItem; 173 import android.app.usage.UsageEvents.Event; 174 import android.content.ComponentName; 175 import android.content.Intent; 176 import android.content.pm.ActivityInfo; 177 import android.content.pm.ApplicationInfo; 178 import android.content.res.CompatibilityInfo; 179 import android.content.res.Configuration; 180 import android.graphics.Bitmap; 181 import android.graphics.GraphicBuffer; 182 import android.graphics.Rect; 183 import android.os.Binder; 184 import android.os.Build; 185 import android.os.Bundle; 186 import android.os.Debug; 187 import android.os.IBinder; 188 import android.os.Message; 189 import android.os.PersistableBundle; 190 import android.os.Process; 191 import android.os.RemoteException; 192 import android.os.SystemClock; 193 import android.os.UserHandle; 194 import android.os.storage.StorageManager; 195 import android.service.voice.IVoiceInteractionSession; 196 import android.util.EventLog; 197 import android.util.Log; 198 import android.util.MergedConfiguration; 199 import android.util.Slog; 200 import android.util.TimeUtils; 201 import android.util.proto.ProtoOutputStream; 202 import android.view.AppTransitionAnimationSpec; 203 import android.view.DisplayCutout; 204 import android.view.IAppTransitionAnimationSpecsFuture; 205 import android.view.IApplicationToken; 206 import android.view.RemoteAnimationDefinition; 207 import android.view.WindowManager.LayoutParams; 208 209 import com.android.internal.R; 210 import com.android.internal.annotations.VisibleForTesting; 211 import com.android.internal.app.ResolverActivity; 212 import com.android.internal.content.ReferrerIntent; 213 import com.android.internal.util.XmlUtils; 214 import com.android.server.AttributeCache; 215 import com.android.server.AttributeCache.Entry; 216 import com.android.server.am.AppTimeTracker; 217 import com.android.server.am.PendingIntentRecord; 218 import com.android.server.uri.UriPermissionOwner; 219 import com.android.server.wm.ActivityMetricsLogger.WindowingModeTransitionInfoSnapshot; 220 import com.android.server.wm.ActivityStack.ActivityState; 221 222 import org.xmlpull.v1.XmlPullParser; 223 import org.xmlpull.v1.XmlPullParserException; 224 import org.xmlpull.v1.XmlSerializer; 225 226 import java.io.File; 227 import java.io.IOException; 228 import java.io.PrintWriter; 229 import java.lang.ref.WeakReference; 230 import java.util.ArrayList; 231 import java.util.Arrays; 232 import java.util.HashSet; 233 import java.util.List; 234 import java.util.Objects; 235 236 /** 237 * An entry in the history stack, representing an activity. 238 */ 239 final class ActivityRecord extends ConfigurationContainer { 240 private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityRecord" : TAG_ATM; 241 private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION; 242 private static final String TAG_SAVED_STATE = TAG + POSTFIX_SAVED_STATE; 243 private static final String TAG_STATES = TAG + POSTFIX_STATES; 244 private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH; 245 private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY; 246 private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS; 247 // TODO(b/67864419): Remove once recents component is overridden 248 private static final String LEGACY_RECENTS_PACKAGE_NAME = "com.android.systemui.recents"; 249 250 private static final boolean SHOW_ACTIVITY_START_TIME = true; 251 252 private static final String ATTR_ID = "id"; 253 private static final String TAG_INTENT = "intent"; 254 private static final String ATTR_USERID = "user_id"; 255 private static final String TAG_PERSISTABLEBUNDLE = "persistable_bundle"; 256 private static final String ATTR_LAUNCHEDFROMUID = "launched_from_uid"; 257 private static final String ATTR_LAUNCHEDFROMPACKAGE = "launched_from_package"; 258 private static final String ATTR_RESOLVEDTYPE = "resolved_type"; 259 private static final String ATTR_COMPONENTSPECIFIED = "component_specified"; 260 static final String ACTIVITY_ICON_SUFFIX = "_activity_icon_"; 261 262 final ActivityTaskManagerService mAtmService; // owner 263 final IApplicationToken.Stub appToken; // window manager token 264 // TODO: Remove after unification 265 AppWindowToken mAppWindowToken; 266 267 final ActivityInfo info; // all about me 268 // TODO: This is duplicated state already contained in info.applicationInfo - remove 269 ApplicationInfo appInfo; // information about activity's app 270 final int launchedFromPid; // always the pid who started the activity. 271 final int launchedFromUid; // always the uid who started the activity. 272 final String launchedFromPackage; // always the package who started the activity. 273 final int mUserId; // Which user is this running for? 274 final Intent intent; // the original intent that generated us 275 final ComponentName mActivityComponent; // the intent component, or target of an alias. 276 final String shortComponentName; // the short component name of the intent 277 final String resolvedType; // as per original caller; 278 final String packageName; // the package implementing intent's component 279 final String processName; // process where this component wants to run 280 final String taskAffinity; // as per ActivityInfo.taskAffinity 281 final boolean stateNotNeeded; // As per ActivityInfo.flags 282 boolean fullscreen; // The activity is opaque and fills the entire space of this task. 283 // TODO: See if it possible to combine this with the fullscreen field. 284 final boolean hasWallpaper; // Has a wallpaper window as a background. 285 @VisibleForTesting 286 boolean noDisplay; // activity is not displayed? 287 @VisibleForTesting 288 int mHandoverLaunchDisplayId = INVALID_DISPLAY; // Handover launch display id to next activity. 289 private final boolean componentSpecified; // did caller specify an explicit component? 290 final boolean rootVoiceInteraction; // was this the root activity of a voice interaction? 291 292 private CharSequence nonLocalizedLabel; // the label information from the package mgr. 293 private int labelRes; // the label information from the package mgr. 294 private int icon; // resource identifier of activity's icon. 295 private int logo; // resource identifier of activity's logo. 296 private int theme; // resource identifier of activity's theme. 297 private int realTheme; // actual theme resource we will use, never 0. 298 private int windowFlags; // custom window flags for preview window. 299 private TaskRecord task; // the task this is in. 300 private long createTime = System.currentTimeMillis(); 301 long lastVisibleTime; // last time this activity became visible 302 long cpuTimeAtResume; // the cpu time of host process at the time of resuming activity 303 long pauseTime; // last time we started pausing the activity 304 long launchTickTime; // base time for launch tick messages 305 long topResumedStateLossTime; // last time we reported top resumed state loss to an activity 306 // Last configuration reported to the activity in the client process. 307 private MergedConfiguration mLastReportedConfiguration; 308 private int mLastReportedDisplayId; 309 private boolean mLastReportedMultiWindowMode; 310 private boolean mLastReportedPictureInPictureMode; 311 CompatibilityInfo compat;// last used compatibility mode 312 ActivityRecord resultTo; // who started this entry, so will get our reply 313 final String resultWho; // additional identifier for use by resultTo. 314 final int requestCode; // code given by requester (resultTo) 315 ArrayList<ResultInfo> results; // pending ActivityResult objs we have received 316 HashSet<WeakReference<PendingIntentRecord>> pendingResults; // all pending intents for this act 317 ArrayList<ReferrerIntent> newIntents; // any pending new intents for single-top mode 318 ActivityOptions pendingOptions; // most recently given options 319 ActivityOptions returningOptions; // options that are coming back via convertToTranslucent 320 AppTimeTracker appTimeTracker; // set if we are tracking the time in this app/task/activity 321 ActivityServiceConnectionsHolder mServiceConnectionsHolder; // Service connections. 322 UriPermissionOwner uriPermissions; // current special URI access perms. 323 WindowProcessController app; // if non-null, hosting application 324 private ActivityState mState; // current state we are in 325 Bundle icicle; // last saved activity state 326 PersistableBundle persistentState; // last persistently saved activity state 327 // TODO: See if this is still needed. 328 boolean frontOfTask; // is this the root activity of its task? 329 boolean launchFailed; // set if a launched failed, to abort on 2nd try 330 boolean haveState; // have we gotten the last activity state? 331 boolean stopped; // is activity pause finished? 332 boolean delayedResume; // not yet resumed because of stopped app switches? 333 boolean finishing; // activity in pending finish list? 334 boolean deferRelaunchUntilPaused; // relaunch of activity is being deferred until pause is 335 // completed 336 boolean preserveWindowOnDeferredRelaunch; // activity windows are preserved on deferred relaunch 337 int configChangeFlags; // which config values have changed 338 private boolean keysPaused; // has key dispatching been paused for it? 339 int launchMode; // the launch mode activity attribute. 340 int lockTaskLaunchMode; // the lockTaskMode manifest attribute, subject to override 341 boolean visible; // does this activity's window need to be shown? 342 boolean visibleIgnoringKeyguard; // is this activity visible, ignoring the fact that Keyguard 343 // might hide this activity? 344 private boolean mDeferHidingClient; // If true we told WM to defer reporting to the client 345 // process that it is hidden. 346 boolean sleeping; // have we told the activity to sleep? 347 boolean nowVisible; // is this activity's window visible? 348 boolean mDrawn; // is this activity's window drawn? 349 boolean mClientVisibilityDeferred;// was the visibility change message to client deferred? 350 boolean idle; // has the activity gone idle? 351 boolean hasBeenLaunched;// has this activity ever been launched? 352 boolean frozenBeforeDestroy;// has been frozen but not yet destroyed. 353 boolean immersive; // immersive mode (don't interrupt if possible) 354 boolean forceNewConfig; // force re-create with new config next time 355 boolean supportsEnterPipOnTaskSwitch; // This flag is set by the system to indicate that the 356 // activity can enter picture in picture while pausing (only when switching to another task) 357 PictureInPictureParams pictureInPictureArgs = new PictureInPictureParams.Builder().build(); 358 // The PiP params used when deferring the entering of picture-in-picture. 359 int launchCount; // count of launches since last state 360 long lastLaunchTime; // time of last launch of this activity 361 ComponentName requestedVrComponent; // the requested component for handling VR mode. 362 363 String stringName; // for caching of toString(). 364 365 private boolean inHistory; // are we in the history stack? 366 final ActivityStackSupervisor mStackSupervisor; 367 final RootActivityContainer mRootActivityContainer; 368 369 static final int STARTING_WINDOW_NOT_SHOWN = 0; 370 static final int STARTING_WINDOW_SHOWN = 1; 371 static final int STARTING_WINDOW_REMOVED = 2; 372 int mStartingWindowState = STARTING_WINDOW_NOT_SHOWN; 373 boolean mTaskOverlay = false; // Task is always on-top of other activities in the task. 374 375 // Marking the reason why this activity is being relaunched. Mainly used to track that this 376 // activity is being relaunched to fulfill a resize request due to compatibility issues, e.g. in 377 // pre-NYC apps that don't have a sense of being resized. 378 int mRelaunchReason = RELAUNCH_REASON_NONE; 379 380 TaskDescription taskDescription; // the recents information for this activity 381 boolean mLaunchTaskBehind; // this activity is actively being launched with 382 // ActivityOptions.setLaunchTaskBehind, will be cleared once launch is completed. 383 384 // These configurations are collected from application's resources based on size-sensitive 385 // qualifiers. For example, layout-w800dp will be added to mHorizontalSizeConfigurations as 800 386 // and drawable-sw400dp will be added to both as 400. 387 private int[] mVerticalSizeConfigurations; 388 private int[] mHorizontalSizeConfigurations; 389 private int[] mSmallestSizeConfigurations; 390 391 /** 392 * The precomputed display insets for resolving configuration. It will be non-null if 393 * {@link #shouldUseSizeCompatMode} returns {@code true}. 394 */ 395 private CompatDisplayInsets mCompatDisplayInsets; 396 397 boolean pendingVoiceInteractionStart; // Waiting for activity-invoked voice session 398 IVoiceInteractionSession voiceSession; // Voice interaction session for this activity 399 400 // A hint to override the window specified rotation animation, or -1 401 // to use the window specified value. We use this so that 402 // we can select the right animation in the cases of starting 403 // windows, where the app hasn't had time to set a value 404 // on the window. 405 int mRotationAnimationHint = -1; 406 407 private boolean mShowWhenLocked; 408 private boolean mInheritShownWhenLocked; 409 private boolean mTurnScreenOn; 410 411 /** 412 * Current sequencing integer of the configuration, for skipping old activity configurations. 413 */ 414 private int mConfigurationSeq; 415 416 /** 417 * Temp configs used in {@link #ensureActivityConfiguration(int, boolean)} 418 */ 419 private final Configuration mTmpConfig = new Configuration(); 420 private final Rect mTmpBounds = new Rect(); 421 422 // Token for targeting this activity for assist purposes. 423 final Binder assistToken = new Binder(); 424 startingWindowStateToString(int state)425 private static String startingWindowStateToString(int state) { 426 switch (state) { 427 case STARTING_WINDOW_NOT_SHOWN: 428 return "STARTING_WINDOW_NOT_SHOWN"; 429 case STARTING_WINDOW_SHOWN: 430 return "STARTING_WINDOW_SHOWN"; 431 case STARTING_WINDOW_REMOVED: 432 return "STARTING_WINDOW_REMOVED"; 433 default: 434 return "unknown state=" + state; 435 } 436 } 437 dump(PrintWriter pw, String prefix)438 void dump(PrintWriter pw, String prefix) { 439 final long now = SystemClock.uptimeMillis(); 440 pw.print(prefix); pw.print("packageName="); pw.print(packageName); 441 pw.print(" processName="); pw.println(processName); 442 pw.print(prefix); pw.print("launchedFromUid="); pw.print(launchedFromUid); 443 pw.print(" launchedFromPackage="); pw.print(launchedFromPackage); 444 pw.print(" userId="); pw.println(mUserId); 445 pw.print(prefix); pw.print("app="); pw.println(app); 446 pw.print(prefix); pw.println(intent.toInsecureStringWithClip()); 447 pw.print(prefix); pw.print("frontOfTask="); pw.print(frontOfTask); 448 pw.print(" task="); pw.println(task); 449 pw.print(prefix); pw.print("taskAffinity="); pw.println(taskAffinity); 450 pw.print(prefix); pw.print("mActivityComponent="); 451 pw.println(mActivityComponent.flattenToShortString()); 452 if (appInfo != null) { 453 pw.print(prefix); pw.print("baseDir="); pw.println(appInfo.sourceDir); 454 if (!Objects.equals(appInfo.sourceDir, appInfo.publicSourceDir)) { 455 pw.print(prefix); pw.print("resDir="); pw.println(appInfo.publicSourceDir); 456 } 457 pw.print(prefix); pw.print("dataDir="); pw.println(appInfo.dataDir); 458 if (appInfo.splitSourceDirs != null) { 459 pw.print(prefix); pw.print("splitDir="); 460 pw.println(Arrays.toString(appInfo.splitSourceDirs)); 461 } 462 } 463 pw.print(prefix); pw.print("stateNotNeeded="); pw.print(stateNotNeeded); 464 pw.print(" componentSpecified="); pw.print(componentSpecified); 465 pw.print(" mActivityType="); pw.println( 466 activityTypeToString(getActivityType())); 467 if (rootVoiceInteraction) { 468 pw.print(prefix); pw.print("rootVoiceInteraction="); pw.println(rootVoiceInteraction); 469 } 470 pw.print(prefix); pw.print("compat="); pw.print(compat); 471 pw.print(" labelRes=0x"); pw.print(Integer.toHexString(labelRes)); 472 pw.print(" icon=0x"); pw.print(Integer.toHexString(icon)); 473 pw.print(" theme=0x"); pw.println(Integer.toHexString(theme)); 474 pw.println(prefix + "mLastReportedConfigurations:"); 475 mLastReportedConfiguration.dump(pw, prefix + " "); 476 477 pw.print(prefix); pw.print("CurrentConfiguration="); pw.println(getConfiguration()); 478 if (!getRequestedOverrideConfiguration().equals(EMPTY)) { 479 pw.println(prefix + "RequestedOverrideConfiguration=" 480 + getRequestedOverrideConfiguration()); 481 } 482 if (!getResolvedOverrideConfiguration().equals(getRequestedOverrideConfiguration())) { 483 pw.println(prefix + "ResolvedOverrideConfiguration=" 484 + getResolvedOverrideConfiguration()); 485 } 486 if (!matchParentBounds()) { 487 pw.println(prefix + "bounds=" + getBounds()); 488 } 489 if (resultTo != null || resultWho != null) { 490 pw.print(prefix); pw.print("resultTo="); pw.print(resultTo); 491 pw.print(" resultWho="); pw.print(resultWho); 492 pw.print(" resultCode="); pw.println(requestCode); 493 } 494 if (taskDescription != null) { 495 final String iconFilename = taskDescription.getIconFilename(); 496 if (iconFilename != null || taskDescription.getLabel() != null || 497 taskDescription.getPrimaryColor() != 0) { 498 pw.print(prefix); pw.print("taskDescription:"); 499 pw.print(" label=\""); pw.print(taskDescription.getLabel()); 500 pw.print("\""); 501 pw.print(" icon="); pw.print(taskDescription.getInMemoryIcon() != null 502 ? taskDescription.getInMemoryIcon().getByteCount() + " bytes" 503 : "null"); 504 pw.print(" iconResource="); pw.print(taskDescription.getIconResource()); 505 pw.print(" iconFilename="); pw.print(taskDescription.getIconFilename()); 506 pw.print(" primaryColor="); 507 pw.println(Integer.toHexString(taskDescription.getPrimaryColor())); 508 pw.print(prefix + " backgroundColor="); 509 pw.println(Integer.toHexString(taskDescription.getBackgroundColor())); 510 pw.print(prefix + " statusBarColor="); 511 pw.println(Integer.toHexString(taskDescription.getStatusBarColor())); 512 pw.print(prefix + " navigationBarColor="); 513 pw.println(Integer.toHexString(taskDescription.getNavigationBarColor())); 514 } 515 } 516 if (results != null) { 517 pw.print(prefix); pw.print("results="); pw.println(results); 518 } 519 if (pendingResults != null && pendingResults.size() > 0) { 520 pw.print(prefix); pw.println("Pending Results:"); 521 for (WeakReference<PendingIntentRecord> wpir : pendingResults) { 522 PendingIntentRecord pir = wpir != null ? wpir.get() : null; 523 pw.print(prefix); pw.print(" - "); 524 if (pir == null) { 525 pw.println("null"); 526 } else { 527 pw.println(pir); 528 pir.dump(pw, prefix + " "); 529 } 530 } 531 } 532 if (newIntents != null && newIntents.size() > 0) { 533 pw.print(prefix); pw.println("Pending New Intents:"); 534 for (int i=0; i<newIntents.size(); i++) { 535 Intent intent = newIntents.get(i); 536 pw.print(prefix); pw.print(" - "); 537 if (intent == null) { 538 pw.println("null"); 539 } else { 540 pw.println(intent.toShortString(false, true, false, true)); 541 } 542 } 543 } 544 if (pendingOptions != null) { 545 pw.print(prefix); pw.print("pendingOptions="); pw.println(pendingOptions); 546 } 547 if (appTimeTracker != null) { 548 appTimeTracker.dumpWithHeader(pw, prefix, false); 549 } 550 if (uriPermissions != null) { 551 uriPermissions.dump(pw, prefix); 552 } 553 pw.print(prefix); pw.print("launchFailed="); pw.print(launchFailed); 554 pw.print(" launchCount="); pw.print(launchCount); 555 pw.print(" lastLaunchTime="); 556 if (lastLaunchTime == 0) pw.print("0"); 557 else TimeUtils.formatDuration(lastLaunchTime, now, pw); 558 pw.println(); 559 pw.print(prefix); pw.print("haveState="); pw.print(haveState); 560 pw.print(" icicle="); pw.println(icicle); 561 pw.print(prefix); pw.print("state="); pw.print(mState); 562 pw.print(" stopped="); pw.print(stopped); 563 pw.print(" delayedResume="); pw.print(delayedResume); 564 pw.print(" finishing="); pw.println(finishing); 565 pw.print(prefix); pw.print("keysPaused="); pw.print(keysPaused); 566 pw.print(" inHistory="); pw.print(inHistory); 567 pw.print(" visible="); pw.print(visible); 568 pw.print(" sleeping="); pw.print(sleeping); 569 pw.print(" idle="); pw.print(idle); 570 pw.print(" mStartingWindowState="); 571 pw.println(startingWindowStateToString(mStartingWindowState)); 572 pw.print(prefix); pw.print("fullscreen="); pw.print(fullscreen); 573 pw.print(" noDisplay="); pw.print(noDisplay); 574 pw.print(" immersive="); pw.print(immersive); 575 pw.print(" launchMode="); pw.println(launchMode); 576 pw.print(prefix); pw.print("frozenBeforeDestroy="); pw.print(frozenBeforeDestroy); 577 pw.print(" forceNewConfig="); pw.println(forceNewConfig); 578 pw.print(prefix); pw.print("mActivityType="); 579 pw.println(activityTypeToString(getActivityType())); 580 if (requestedVrComponent != null) { 581 pw.print(prefix); 582 pw.print("requestedVrComponent="); 583 pw.println(requestedVrComponent); 584 } 585 if (lastVisibleTime != 0 || nowVisible) { 586 pw.print(prefix); pw.print(" nowVisible="); pw.print(nowVisible); 587 pw.print(" lastVisibleTime="); 588 if (lastVisibleTime == 0) pw.print("0"); 589 else TimeUtils.formatDuration(lastVisibleTime, now, pw); 590 pw.println(); 591 } 592 if (mDeferHidingClient) { 593 pw.println(prefix + "mDeferHidingClient=" + mDeferHidingClient); 594 } 595 if (deferRelaunchUntilPaused || configChangeFlags != 0) { 596 pw.print(prefix); pw.print("deferRelaunchUntilPaused="); pw.print(deferRelaunchUntilPaused); 597 pw.print(" configChangeFlags="); 598 pw.println(Integer.toHexString(configChangeFlags)); 599 } 600 if (mServiceConnectionsHolder != null) { 601 pw.print(prefix); pw.print("connections="); pw.println(mServiceConnectionsHolder); 602 } 603 if (info != null) { 604 pw.println(prefix + "resizeMode=" + ActivityInfo.resizeModeToString(info.resizeMode)); 605 pw.println(prefix + "mLastReportedMultiWindowMode=" + mLastReportedMultiWindowMode 606 + " mLastReportedPictureInPictureMode=" + mLastReportedPictureInPictureMode); 607 if (info.supportsPictureInPicture()) { 608 pw.println(prefix + "supportsPictureInPicture=" + info.supportsPictureInPicture()); 609 pw.println(prefix + "supportsEnterPipOnTaskSwitch: " 610 + supportsEnterPipOnTaskSwitch); 611 } 612 if (info.maxAspectRatio != 0) { 613 pw.println(prefix + "maxAspectRatio=" + info.maxAspectRatio); 614 } 615 if (info.minAspectRatio != 0) { 616 pw.println(prefix + "minAspectRatio=" + info.minAspectRatio); 617 } 618 } 619 } 620 updateApplicationInfo(ApplicationInfo aInfo)621 void updateApplicationInfo(ApplicationInfo aInfo) { 622 appInfo = aInfo; 623 info.applicationInfo = aInfo; 624 } 625 crossesHorizontalSizeThreshold(int firstDp, int secondDp)626 private boolean crossesHorizontalSizeThreshold(int firstDp, int secondDp) { 627 return crossesSizeThreshold(mHorizontalSizeConfigurations, firstDp, secondDp); 628 } 629 crossesVerticalSizeThreshold(int firstDp, int secondDp)630 private boolean crossesVerticalSizeThreshold(int firstDp, int secondDp) { 631 return crossesSizeThreshold(mVerticalSizeConfigurations, firstDp, secondDp); 632 } 633 crossesSmallestSizeThreshold(int firstDp, int secondDp)634 private boolean crossesSmallestSizeThreshold(int firstDp, int secondDp) { 635 return crossesSizeThreshold(mSmallestSizeConfigurations, firstDp, secondDp); 636 } 637 638 /** 639 * The purpose of this method is to decide whether the activity needs to be relaunched upon 640 * changing its size. In most cases the activities don't need to be relaunched, if the resize 641 * is small, all the activity content has to do is relayout itself within new bounds. There are 642 * cases however, where the activity's content would be completely changed in the new size and 643 * the full relaunch is required. 644 * 645 * The activity will report to us vertical and horizontal thresholds after which a relaunch is 646 * required. These thresholds are collected from the application resource qualifiers. For 647 * example, if application has layout-w600dp resource directory, then it needs a relaunch when 648 * we resize from width of 650dp to 550dp, as it crosses the 600dp threshold. However, if 649 * it resizes width from 620dp to 700dp, it won't be relaunched as it stays on the same side 650 * of the threshold. 651 */ crossesSizeThreshold(int[] thresholds, int firstDp, int secondDp)652 private static boolean crossesSizeThreshold(int[] thresholds, int firstDp, 653 int secondDp) { 654 if (thresholds == null) { 655 return false; 656 } 657 for (int i = thresholds.length - 1; i >= 0; i--) { 658 final int threshold = thresholds[i]; 659 if ((firstDp < threshold && secondDp >= threshold) 660 || (firstDp >= threshold && secondDp < threshold)) { 661 return true; 662 } 663 } 664 return false; 665 } 666 setSizeConfigurations(int[] horizontalSizeConfiguration, int[] verticalSizeConfigurations, int[] smallestSizeConfigurations)667 void setSizeConfigurations(int[] horizontalSizeConfiguration, 668 int[] verticalSizeConfigurations, int[] smallestSizeConfigurations) { 669 mHorizontalSizeConfigurations = horizontalSizeConfiguration; 670 mVerticalSizeConfigurations = verticalSizeConfigurations; 671 mSmallestSizeConfigurations = smallestSizeConfigurations; 672 } 673 scheduleActivityMovedToDisplay(int displayId, Configuration config)674 private void scheduleActivityMovedToDisplay(int displayId, Configuration config) { 675 if (!attachedToProcess()) { 676 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.w(TAG, 677 "Can't report activity moved to display - client not running, activityRecord=" 678 + this + ", displayId=" + displayId); 679 return; 680 } 681 try { 682 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG, 683 "Reporting activity moved to display" + ", activityRecord=" + this 684 + ", displayId=" + displayId + ", config=" + config); 685 686 mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, 687 MoveToDisplayItem.obtain(displayId, config)); 688 } catch (RemoteException e) { 689 // If process died, whatever. 690 } 691 } 692 scheduleConfigurationChanged(Configuration config)693 private void scheduleConfigurationChanged(Configuration config) { 694 if (!attachedToProcess()) { 695 if (DEBUG_CONFIGURATION) Slog.w(TAG, 696 "Can't report activity configuration update - client not running" 697 + ", activityRecord=" + this); 698 return; 699 } 700 try { 701 if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + this + ", config: " 702 + config); 703 704 mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, 705 ActivityConfigurationChangeItem.obtain(config)); 706 } catch (RemoteException e) { 707 // If process died, whatever. 708 } 709 } 710 scheduleTopResumedActivityChanged(boolean onTop)711 boolean scheduleTopResumedActivityChanged(boolean onTop) { 712 if (!attachedToProcess()) { 713 if (DEBUG_STATES) { 714 Slog.w(TAG, "Can't report activity position update - client not running" 715 + ", activityRecord=" + this); 716 } 717 return false; 718 } 719 try { 720 if (DEBUG_STATES) { 721 Slog.v(TAG, "Sending position change to " + this + ", onTop: " + onTop); 722 } 723 724 mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, 725 TopResumedActivityChangeItem.obtain(onTop)); 726 } catch (RemoteException e) { 727 // If process died, whatever. 728 return false; 729 } 730 return true; 731 } 732 updateMultiWindowMode()733 void updateMultiWindowMode() { 734 if (task == null || task.getStack() == null || !attachedToProcess()) { 735 return; 736 } 737 738 if (task.getStack().deferScheduleMultiWindowModeChanged()) { 739 // Don't do anything if we are currently deferring multi-window mode change. 740 return; 741 } 742 743 // An activity is considered to be in multi-window mode if its task isn't fullscreen. 744 final boolean inMultiWindowMode = inMultiWindowMode(); 745 if (inMultiWindowMode != mLastReportedMultiWindowMode) { 746 mLastReportedMultiWindowMode = inMultiWindowMode; 747 scheduleMultiWindowModeChanged(getConfiguration()); 748 } 749 } 750 scheduleMultiWindowModeChanged(Configuration overrideConfig)751 private void scheduleMultiWindowModeChanged(Configuration overrideConfig) { 752 try { 753 mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, 754 MultiWindowModeChangeItem.obtain(mLastReportedMultiWindowMode, overrideConfig)); 755 } catch (Exception e) { 756 // If process died, I don't care. 757 } 758 } 759 updatePictureInPictureMode(Rect targetStackBounds, boolean forceUpdate)760 void updatePictureInPictureMode(Rect targetStackBounds, boolean forceUpdate) { 761 if (task == null || task.getStack() == null || !attachedToProcess()) { 762 return; 763 } 764 765 final boolean inPictureInPictureMode = inPinnedWindowingMode() && targetStackBounds != null; 766 if (inPictureInPictureMode != mLastReportedPictureInPictureMode || forceUpdate) { 767 // Picture-in-picture mode changes also trigger a multi-window mode change as well, so 768 // update that here in order. Set the last reported MW state to the same as the PiP 769 // state since we haven't yet actually resized the task (these callbacks need to 770 // preceed the configuration change from the resiez. 771 // TODO(110009072): Once we move these callbacks to the client, remove all logic related 772 // to forcing the update of the picture-in-picture mode as a part of the PiP animation. 773 mLastReportedPictureInPictureMode = inPictureInPictureMode; 774 mLastReportedMultiWindowMode = inPictureInPictureMode; 775 final Configuration newConfig = new Configuration(); 776 if (targetStackBounds != null && !targetStackBounds.isEmpty()) { 777 newConfig.setTo(task.getRequestedOverrideConfiguration()); 778 Rect outBounds = newConfig.windowConfiguration.getBounds(); 779 task.adjustForMinimalTaskDimensions(outBounds, outBounds); 780 task.computeConfigResourceOverrides(newConfig, task.getParent().getConfiguration()); 781 } 782 schedulePictureInPictureModeChanged(newConfig); 783 scheduleMultiWindowModeChanged(newConfig); 784 } 785 } 786 schedulePictureInPictureModeChanged(Configuration overrideConfig)787 private void schedulePictureInPictureModeChanged(Configuration overrideConfig) { 788 try { 789 mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, 790 PipModeChangeItem.obtain(mLastReportedPictureInPictureMode, 791 overrideConfig)); 792 } catch (Exception e) { 793 // If process died, no one cares. 794 } 795 } 796 797 @Override getChildCount()798 protected int getChildCount() { 799 // {@link ActivityRecord} is a leaf node and has no children. 800 return 0; 801 } 802 803 @Override getChildAt(int index)804 protected ConfigurationContainer getChildAt(int index) { 805 return null; 806 } 807 808 @Override getParent()809 protected ConfigurationContainer getParent() { 810 return getTaskRecord(); 811 } 812 getTaskRecord()813 TaskRecord getTaskRecord() { 814 return task; 815 } 816 817 /** 818 * Sets reference to the {@link TaskRecord} the {@link ActivityRecord} will treat as its parent. 819 * Note that this does not actually add the {@link ActivityRecord} as a {@link TaskRecord} 820 * children. However, this method will clean up references to this {@link ActivityRecord} in 821 * {@link ActivityStack}. 822 * @param task The new parent {@link TaskRecord}. 823 */ setTask(TaskRecord task)824 void setTask(TaskRecord task) { 825 setTask(task /* task */, false /* reparenting */); 826 } 827 828 /** 829 * This method should only be called by {@link TaskRecord#removeActivity(ActivityRecord)}. 830 * @param task The new parent task. 831 * @param reparenting Whether we're in the middle of reparenting. 832 */ setTask(TaskRecord task, boolean reparenting)833 void setTask(TaskRecord task, boolean reparenting) { 834 // Do nothing if the {@link TaskRecord} is the same as the current {@link getTaskRecord}. 835 if (task != null && task == getTaskRecord()) { 836 return; 837 } 838 839 final ActivityStack oldStack = getActivityStack(); 840 final ActivityStack newStack = task != null ? task.getStack() : null; 841 842 // Inform old stack (if present) of activity removal and new stack (if set) of activity 843 // addition. 844 if (oldStack != newStack) { 845 if (!reparenting && oldStack != null) { 846 oldStack.onActivityRemovedFromStack(this); 847 } 848 849 if (newStack != null) { 850 newStack.onActivityAddedToStack(this); 851 } 852 } 853 854 this.task = task; 855 856 if (!reparenting) { 857 onParentChanged(); 858 } 859 } 860 861 /** 862 * Notifies AWT that this app is waiting to pause in order to determine if it will enter PIP. 863 * This information helps AWT know that the app is in the process of pausing before it gets the 864 * signal on the WM side. 865 */ setWillCloseOrEnterPip(boolean willCloseOrEnterPip)866 void setWillCloseOrEnterPip(boolean willCloseOrEnterPip) { 867 if (mAppWindowToken == null) { 868 return; 869 } 870 871 mAppWindowToken.setWillCloseOrEnterPip(willCloseOrEnterPip); 872 } 873 874 static class Token extends IApplicationToken.Stub { 875 private final WeakReference<ActivityRecord> weakActivity; 876 private final String name; 877 Token(ActivityRecord activity, Intent intent)878 Token(ActivityRecord activity, Intent intent) { 879 weakActivity = new WeakReference<>(activity); 880 name = intent.getComponent().flattenToShortString(); 881 } 882 tokenToActivityRecordLocked(Token token)883 private static @Nullable ActivityRecord tokenToActivityRecordLocked(Token token) { 884 if (token == null) { 885 return null; 886 } 887 ActivityRecord r = token.weakActivity.get(); 888 if (r == null || r.getActivityStack() == null) { 889 return null; 890 } 891 return r; 892 } 893 894 @Override toString()895 public String toString() { 896 StringBuilder sb = new StringBuilder(128); 897 sb.append("Token{"); 898 sb.append(Integer.toHexString(System.identityHashCode(this))); 899 sb.append(' '); 900 sb.append(weakActivity.get()); 901 sb.append('}'); 902 return sb.toString(); 903 } 904 905 @Override getName()906 public String getName() { 907 return name; 908 } 909 } 910 forTokenLocked(IBinder token)911 static @Nullable ActivityRecord forTokenLocked(IBinder token) { 912 try { 913 return Token.tokenToActivityRecordLocked((Token)token); 914 } catch (ClassCastException e) { 915 Slog.w(TAG, "Bad activity token: " + token, e); 916 return null; 917 } 918 } 919 isResolverActivity(String className)920 static boolean isResolverActivity(String className) { 921 return ResolverActivity.class.getName().equals(className); 922 } 923 isResolverActivity()924 boolean isResolverActivity() { 925 return isResolverActivity(mActivityComponent.getClassName()); 926 } 927 isResolverOrChildActivity()928 boolean isResolverOrChildActivity() { 929 if (!"android".equals(packageName)) { 930 return false; 931 } 932 try { 933 return ResolverActivity.class.isAssignableFrom( 934 Object.class.getClassLoader().loadClass(mActivityComponent.getClassName())); 935 } catch (ClassNotFoundException e) { 936 return false; 937 } 938 } 939 ActivityRecord(ActivityTaskManagerService _service, WindowProcessController _caller, int _launchedFromPid, int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType, ActivityInfo aInfo, Configuration _configuration, ActivityRecord _resultTo, String _resultWho, int _reqCode, boolean _componentSpecified, boolean _rootVoiceInteraction, ActivityStackSupervisor supervisor, ActivityOptions options, ActivityRecord sourceRecord)940 ActivityRecord(ActivityTaskManagerService _service, WindowProcessController _caller, 941 int _launchedFromPid, int _launchedFromUid, String _launchedFromPackage, Intent _intent, 942 String _resolvedType, ActivityInfo aInfo, Configuration _configuration, 943 ActivityRecord _resultTo, String _resultWho, int _reqCode, boolean _componentSpecified, 944 boolean _rootVoiceInteraction, ActivityStackSupervisor supervisor, 945 ActivityOptions options, ActivityRecord sourceRecord) { 946 mAtmService = _service; 947 mRootActivityContainer = _service.mRootActivityContainer; 948 appToken = new Token(this, _intent); 949 info = aInfo; 950 launchedFromPid = _launchedFromPid; 951 launchedFromUid = _launchedFromUid; 952 launchedFromPackage = _launchedFromPackage; 953 mUserId = UserHandle.getUserId(aInfo.applicationInfo.uid); 954 intent = _intent; 955 shortComponentName = _intent.getComponent().flattenToShortString(); 956 resolvedType = _resolvedType; 957 componentSpecified = _componentSpecified; 958 rootVoiceInteraction = _rootVoiceInteraction; 959 mLastReportedConfiguration = new MergedConfiguration(_configuration); 960 resultTo = _resultTo; 961 resultWho = _resultWho; 962 requestCode = _reqCode; 963 setState(INITIALIZING, "ActivityRecord ctor"); 964 frontOfTask = false; 965 launchFailed = false; 966 stopped = false; 967 delayedResume = false; 968 finishing = false; 969 deferRelaunchUntilPaused = false; 970 keysPaused = false; 971 inHistory = false; 972 visible = false; 973 nowVisible = false; 974 mDrawn = false; 975 idle = false; 976 hasBeenLaunched = false; 977 mStackSupervisor = supervisor; 978 979 // This starts out true, since the initial state of an activity is that we have everything, 980 // and we shouldn't never consider it lacking in state to be removed if it dies. 981 haveState = true; 982 983 // If the class name in the intent doesn't match that of the target, this is 984 // probably an alias. We have to create a new ComponentName object to keep track 985 // of the real activity name, so that FLAG_ACTIVITY_CLEAR_TOP is handled properly. 986 if (aInfo.targetActivity == null 987 || (aInfo.targetActivity.equals(_intent.getComponent().getClassName()) 988 && (aInfo.launchMode == LAUNCH_MULTIPLE 989 || aInfo.launchMode == LAUNCH_SINGLE_TOP))) { 990 mActivityComponent = _intent.getComponent(); 991 } else { 992 mActivityComponent = new ComponentName(aInfo.packageName, aInfo.targetActivity); 993 } 994 taskAffinity = aInfo.taskAffinity; 995 stateNotNeeded = (aInfo.flags & FLAG_STATE_NOT_NEEDED) != 0; 996 appInfo = aInfo.applicationInfo; 997 nonLocalizedLabel = aInfo.nonLocalizedLabel; 998 labelRes = aInfo.labelRes; 999 if (nonLocalizedLabel == null && labelRes == 0) { 1000 ApplicationInfo app = aInfo.applicationInfo; 1001 nonLocalizedLabel = app.nonLocalizedLabel; 1002 labelRes = app.labelRes; 1003 } 1004 icon = aInfo.getIconResource(); 1005 logo = aInfo.getLogoResource(); 1006 theme = aInfo.getThemeResource(); 1007 realTheme = theme; 1008 if (realTheme == 0) { 1009 realTheme = aInfo.applicationInfo.targetSdkVersion < HONEYCOMB 1010 ? android.R.style.Theme : android.R.style.Theme_Holo; 1011 } 1012 if ((aInfo.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0) { 1013 windowFlags |= LayoutParams.FLAG_HARDWARE_ACCELERATED; 1014 } 1015 if ((aInfo.flags & FLAG_MULTIPROCESS) != 0 && _caller != null 1016 && (aInfo.applicationInfo.uid == SYSTEM_UID 1017 || aInfo.applicationInfo.uid == _caller.mInfo.uid)) { 1018 processName = _caller.mName; 1019 } else { 1020 processName = aInfo.processName; 1021 } 1022 1023 if ((aInfo.flags & FLAG_EXCLUDE_FROM_RECENTS) != 0) { 1024 intent.addFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); 1025 } 1026 1027 packageName = aInfo.applicationInfo.packageName; 1028 launchMode = aInfo.launchMode; 1029 1030 Entry ent = AttributeCache.instance().get(packageName, 1031 realTheme, com.android.internal.R.styleable.Window, mUserId); 1032 1033 if (ent != null) { 1034 fullscreen = !ActivityInfo.isTranslucentOrFloating(ent.array); 1035 hasWallpaper = ent.array.getBoolean(R.styleable.Window_windowShowWallpaper, false); 1036 noDisplay = ent.array.getBoolean(R.styleable.Window_windowNoDisplay, false); 1037 } else { 1038 hasWallpaper = false; 1039 noDisplay = false; 1040 } 1041 1042 setActivityType(_componentSpecified, _launchedFromUid, _intent, options, sourceRecord); 1043 1044 immersive = (aInfo.flags & FLAG_IMMERSIVE) != 0; 1045 1046 requestedVrComponent = (aInfo.requestedVrComponent == null) ? 1047 null : ComponentName.unflattenFromString(aInfo.requestedVrComponent); 1048 1049 mShowWhenLocked = (aInfo.flags & FLAG_SHOW_WHEN_LOCKED) != 0; 1050 mInheritShownWhenLocked = (aInfo.privateFlags & FLAG_INHERIT_SHOW_WHEN_LOCKED) != 0; 1051 mTurnScreenOn = (aInfo.flags & FLAG_TURN_SCREEN_ON) != 0; 1052 1053 mRotationAnimationHint = aInfo.rotationAnimation; 1054 lockTaskLaunchMode = aInfo.lockTaskLaunchMode; 1055 if (appInfo.isPrivilegedApp() && (lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_ALWAYS 1056 || lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_NEVER)) { 1057 lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_DEFAULT; 1058 } 1059 1060 if (options != null) { 1061 pendingOptions = options; 1062 mLaunchTaskBehind = options.getLaunchTaskBehind(); 1063 1064 final int rotationAnimation = pendingOptions.getRotationAnimationHint(); 1065 // Only override manifest supplied option if set. 1066 if (rotationAnimation >= 0) { 1067 mRotationAnimationHint = rotationAnimation; 1068 } 1069 final PendingIntent usageReport = pendingOptions.getUsageTimeReport(); 1070 if (usageReport != null) { 1071 appTimeTracker = new AppTimeTracker(usageReport); 1072 } 1073 final boolean useLockTask = pendingOptions.getLockTaskMode(); 1074 if (useLockTask && lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_DEFAULT) { 1075 lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED; 1076 } 1077 // Gets launch display id from options. It returns INVALID_DISPLAY if not set. 1078 mHandoverLaunchDisplayId = options.getLaunchDisplayId(); 1079 } 1080 } 1081 setProcess(WindowProcessController proc)1082 void setProcess(WindowProcessController proc) { 1083 app = proc; 1084 final ActivityRecord root = task != null ? task.getRootActivity() : null; 1085 if (root == this) { 1086 task.setRootProcess(proc); 1087 } 1088 } 1089 hasProcess()1090 boolean hasProcess() { 1091 return app != null; 1092 } 1093 attachedToProcess()1094 boolean attachedToProcess() { 1095 return hasProcess() && app.hasThread(); 1096 } 1097 createAppWindowToken()1098 void createAppWindowToken() { 1099 if (mAppWindowToken != null) { 1100 throw new IllegalArgumentException("App Window Token=" + mAppWindowToken 1101 + " already created for r=" + this); 1102 } 1103 1104 inHistory = true; 1105 1106 // TODO(b/36505427): Maybe this call should be moved inside updateOverrideConfiguration() 1107 task.updateOverrideConfigurationFromLaunchBounds(); 1108 // Make sure override configuration is up-to-date before using to create window controller. 1109 updateOverrideConfiguration(); 1110 1111 // TODO: remove after unification 1112 mAppWindowToken = mAtmService.mWindowManager.mRoot.getAppWindowToken(appToken.asBinder()); 1113 if (mAppWindowToken != null) { 1114 // TODO: Should this throw an exception instead? 1115 Slog.w(TAG, "Attempted to add existing app token: " + appToken); 1116 } else { 1117 final Task container = task.getTask(); 1118 if (container == null) { 1119 throw new IllegalArgumentException("createAppWindowToken: invalid task =" + task); 1120 } 1121 mAppWindowToken = createAppWindow(mAtmService.mWindowManager, appToken, 1122 task.voiceSession != null, container.getDisplayContent(), 1123 ActivityTaskManagerService.getInputDispatchingTimeoutLocked(this) 1124 * 1000000L, fullscreen, 1125 (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, appInfo.targetSdkVersion, 1126 info.screenOrientation, mRotationAnimationHint, 1127 mLaunchTaskBehind, isAlwaysFocusable()); 1128 if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) { 1129 Slog.v(TAG, "addAppToken: " 1130 + mAppWindowToken + " task=" + container + " at " 1131 + Integer.MAX_VALUE); 1132 } 1133 container.addChild(mAppWindowToken, Integer.MAX_VALUE /* add on top */); 1134 } 1135 1136 task.addActivityToTop(this); 1137 1138 // When an activity is started directly into a split-screen fullscreen stack, we need to 1139 // update the initial multi-window modes so that the callbacks are scheduled correctly when 1140 // the user leaves that mode. 1141 mLastReportedMultiWindowMode = inMultiWindowMode(); 1142 mLastReportedPictureInPictureMode = inPinnedWindowingMode(); 1143 } 1144 addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags, IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning, boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents)1145 boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo, 1146 CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags, 1147 IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning, 1148 boolean allowTaskSnapshot, boolean activityCreated, boolean fromRecents) { 1149 if (DEBUG_STARTING_WINDOW) { 1150 Slog.v(TAG, "setAppStartingWindow: token=" + appToken 1151 + " pkg=" + pkg + " transferFrom=" + transferFrom + " newTask=" + newTask 1152 + " taskSwitch=" + taskSwitch + " processRunning=" + processRunning 1153 + " allowTaskSnapshot=" + allowTaskSnapshot); 1154 } 1155 if (mAppWindowToken == null) { 1156 Slog.w(TAG_WM, "Attempted to set icon of non-existing app token: " + appToken); 1157 return false; 1158 } 1159 if (mAppWindowToken.getTask() == null) { 1160 // Can be removed after unification of Task and TaskRecord. 1161 Slog.w(TAG_WM, "Attempted to start a window to an app token not having attached to any" 1162 + " task: " + appToken); 1163 return false; 1164 } 1165 return mAppWindowToken.addStartingWindow(pkg, theme, compatInfo, nonLocalizedLabel, 1166 labelRes, icon, logo, windowFlags, transferFrom, newTask, taskSwitch, 1167 processRunning, allowTaskSnapshot, activityCreated, fromRecents); 1168 } 1169 1170 // TODO: Remove after unification 1171 @VisibleForTesting createAppWindow(WindowManagerService service, IApplicationToken token, boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos, boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation, int rotationAnimationHint, boolean launchTaskBehind, boolean alwaysFocusable)1172 AppWindowToken createAppWindow(WindowManagerService service, IApplicationToken token, 1173 boolean voiceInteraction, DisplayContent dc, long inputDispatchingTimeoutNanos, 1174 boolean fullscreen, boolean showForAllUsers, int targetSdk, int orientation, 1175 int rotationAnimationHint, boolean launchTaskBehind, 1176 boolean alwaysFocusable) { 1177 return new AppWindowToken(service, token, mActivityComponent, voiceInteraction, dc, 1178 inputDispatchingTimeoutNanos, fullscreen, showForAllUsers, targetSdk, orientation, 1179 rotationAnimationHint, launchTaskBehind, alwaysFocusable, 1180 this); 1181 } 1182 removeWindowContainer()1183 void removeWindowContainer() { 1184 if (mAtmService.mWindowManager.mRoot == null) return; 1185 1186 final DisplayContent dc = mAtmService.mWindowManager.mRoot.getDisplayContent( 1187 getDisplayId()); 1188 if (dc == null) { 1189 Slog.w(TAG, "removeWindowContainer: Attempted to remove token: " 1190 + appToken + " from non-existing displayId=" + getDisplayId()); 1191 return; 1192 } 1193 // Resume key dispatching if it is currently paused before we remove the container. 1194 resumeKeyDispatchingLocked(); 1195 dc.removeAppToken(appToken.asBinder()); 1196 } 1197 1198 /** 1199 * Reparents this activity into {@param newTask} at the provided {@param position}. The caller 1200 * should ensure that the {@param newTask} is not already the parent of this activity. 1201 */ reparent(TaskRecord newTask, int position, String reason)1202 void reparent(TaskRecord newTask, int position, String reason) { 1203 if (mAppWindowToken == null) { 1204 Slog.w(TAG, "reparent: Attempted to reparent non-existing app token: " + appToken); 1205 return; 1206 } 1207 final TaskRecord prevTask = task; 1208 if (prevTask == newTask) { 1209 throw new IllegalArgumentException(reason + ": task=" + newTask 1210 + " is already the parent of r=" + this); 1211 } 1212 1213 // TODO: Ensure that we do not directly reparent activities across stacks, as that may leave 1214 // the stacks in strange states. For now, we should use Task.reparent() to ensure that 1215 // the stack is left in an OK state. 1216 if (prevTask != null && newTask != null && prevTask.getStack() != newTask.getStack()) { 1217 throw new IllegalArgumentException(reason + ": task=" + newTask 1218 + " is in a different stack (" + newTask.getStackId() + ") than the parent of" 1219 + " r=" + this + " (" + prevTask.getStackId() + ")"); 1220 } 1221 1222 mAppWindowToken.reparent(newTask.getTask(), position); 1223 1224 // Reparenting prevents informing the parent stack of activity removal in the case that 1225 // the new stack has the same parent. we must manually signal here if this is not the case. 1226 final ActivityStack prevStack = prevTask.getStack(); 1227 1228 if (prevStack != newTask.getStack()) { 1229 prevStack.onActivityRemovedFromStack(this); 1230 } 1231 // Remove the activity from the old task and add it to the new task. 1232 prevTask.removeActivity(this, true /* reparenting */); 1233 1234 newTask.addActivityAtIndex(position, this); 1235 } 1236 isHomeIntent(Intent intent)1237 private boolean isHomeIntent(Intent intent) { 1238 return ACTION_MAIN.equals(intent.getAction()) 1239 && (intent.hasCategory(CATEGORY_HOME) 1240 || intent.hasCategory(CATEGORY_SECONDARY_HOME)) 1241 && intent.getCategories().size() == 1 1242 && intent.getData() == null 1243 && intent.getType() == null; 1244 } 1245 isMainIntent(Intent intent)1246 static boolean isMainIntent(Intent intent) { 1247 return ACTION_MAIN.equals(intent.getAction()) 1248 && intent.hasCategory(CATEGORY_LAUNCHER) 1249 && intent.getCategories().size() == 1 1250 && intent.getData() == null 1251 && intent.getType() == null; 1252 } 1253 canLaunchHomeActivity(int uid, ActivityRecord sourceRecord)1254 private boolean canLaunchHomeActivity(int uid, ActivityRecord sourceRecord) { 1255 if (uid == Process.myUid() || uid == 0) { 1256 // System process can launch home activity. 1257 return true; 1258 } 1259 // Allow the recents component to launch the home activity. 1260 final RecentTasks recentTasks = mStackSupervisor.mService.getRecentTasks(); 1261 if (recentTasks != null && recentTasks.isCallerRecents(uid)) { 1262 return true; 1263 } 1264 // Resolver activity can launch home activity. 1265 return sourceRecord != null && sourceRecord.isResolverActivity(); 1266 } 1267 1268 /** 1269 * @return whether the given package name can launch an assist activity. 1270 */ canLaunchAssistActivity(String packageName)1271 private boolean canLaunchAssistActivity(String packageName) { 1272 final ComponentName assistComponent = 1273 mAtmService.mActiveVoiceInteractionServiceComponent; 1274 if (assistComponent != null) { 1275 return assistComponent.getPackageName().equals(packageName); 1276 } 1277 return false; 1278 } 1279 setActivityType(boolean componentSpecified, int launchedFromUid, Intent intent, ActivityOptions options, ActivityRecord sourceRecord)1280 private void setActivityType(boolean componentSpecified, int launchedFromUid, Intent intent, 1281 ActivityOptions options, ActivityRecord sourceRecord) { 1282 int activityType = ACTIVITY_TYPE_UNDEFINED; 1283 if ((!componentSpecified || canLaunchHomeActivity(launchedFromUid, sourceRecord)) 1284 && isHomeIntent(intent) && !isResolverActivity()) { 1285 // This sure looks like a home activity! 1286 activityType = ACTIVITY_TYPE_HOME; 1287 1288 if (info.resizeMode == RESIZE_MODE_FORCE_RESIZEABLE 1289 || info.resizeMode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) { 1290 // We only allow home activities to be resizeable if they explicitly requested it. 1291 info.resizeMode = RESIZE_MODE_UNRESIZEABLE; 1292 } 1293 } else if (mActivityComponent.getClassName().contains(LEGACY_RECENTS_PACKAGE_NAME) 1294 || mAtmService.getRecentTasks().isRecentsComponent(mActivityComponent, appInfo.uid)) { 1295 activityType = ACTIVITY_TYPE_RECENTS; 1296 } else if (options != null && options.getLaunchActivityType() == ACTIVITY_TYPE_ASSISTANT 1297 && canLaunchAssistActivity(launchedFromPackage)) { 1298 activityType = ACTIVITY_TYPE_ASSISTANT; 1299 } 1300 setActivityType(activityType); 1301 } 1302 setTaskToAffiliateWith(TaskRecord taskToAffiliateWith)1303 void setTaskToAffiliateWith(TaskRecord taskToAffiliateWith) { 1304 if (launchMode != LAUNCH_SINGLE_INSTANCE && launchMode != LAUNCH_SINGLE_TASK) { 1305 task.setTaskToAffiliateWith(taskToAffiliateWith); 1306 } 1307 } 1308 1309 /** 1310 * @return Stack value from current task, null if there is no task. 1311 */ getActivityStack()1312 <T extends ActivityStack> T getActivityStack() { 1313 return task != null ? (T) task.getStack() : null; 1314 } 1315 getStackId()1316 int getStackId() { 1317 return getActivityStack() != null ? getActivityStack().mStackId : INVALID_STACK_ID; 1318 } 1319 getDisplay()1320 ActivityDisplay getDisplay() { 1321 final ActivityStack stack = getActivityStack(); 1322 return stack != null ? stack.getDisplay() : null; 1323 } 1324 changeWindowTranslucency(boolean toOpaque)1325 boolean changeWindowTranslucency(boolean toOpaque) { 1326 if (fullscreen == toOpaque) { 1327 return false; 1328 } 1329 1330 // Keep track of the number of fullscreen activities in this task. 1331 task.numFullscreen += toOpaque ? +1 : -1; 1332 1333 fullscreen = toOpaque; 1334 return true; 1335 } 1336 takeFromHistory()1337 void takeFromHistory() { 1338 if (inHistory) { 1339 inHistory = false; 1340 if (task != null && !finishing) { 1341 task = null; 1342 } 1343 clearOptionsLocked(); 1344 } 1345 } 1346 isInHistory()1347 boolean isInHistory() { 1348 return inHistory; 1349 } 1350 isInStackLocked()1351 boolean isInStackLocked() { 1352 final ActivityStack stack = getActivityStack(); 1353 return stack != null && stack.isInStackLocked(this) != null; 1354 } 1355 isPersistable()1356 boolean isPersistable() { 1357 return (info.persistableMode == PERSIST_ROOT_ONLY || 1358 info.persistableMode == PERSIST_ACROSS_REBOOTS) && 1359 (intent == null || (intent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0); 1360 } 1361 isFocusable()1362 boolean isFocusable() { 1363 return mRootActivityContainer.isFocusable(this, isAlwaysFocusable()); 1364 } 1365 isResizeable()1366 boolean isResizeable() { 1367 return ActivityInfo.isResizeableMode(info.resizeMode) || info.supportsPictureInPicture(); 1368 } 1369 1370 /** 1371 * @return whether this activity is non-resizeable or forced to be resizeable 1372 */ isNonResizableOrForcedResizable()1373 boolean isNonResizableOrForcedResizable() { 1374 return info.resizeMode != RESIZE_MODE_RESIZEABLE 1375 && info.resizeMode != RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; 1376 } 1377 1378 /** 1379 * @return whether this activity supports PiP multi-window and can be put in the pinned stack. 1380 */ supportsPictureInPicture()1381 boolean supportsPictureInPicture() { 1382 return mAtmService.mSupportsPictureInPicture && isActivityTypeStandardOrUndefined() 1383 && info.supportsPictureInPicture(); 1384 } 1385 1386 /** 1387 * @return whether this activity supports split-screen multi-window and can be put in the docked 1388 * stack. 1389 */ 1390 @Override supportsSplitScreenWindowingMode()1391 public boolean supportsSplitScreenWindowingMode() { 1392 // An activity can not be docked even if it is considered resizeable because it only 1393 // supports picture-in-picture mode but has a non-resizeable resizeMode 1394 return super.supportsSplitScreenWindowingMode() 1395 && mAtmService.mSupportsSplitScreenMultiWindow && supportsResizeableMultiWindow(); 1396 } 1397 1398 /** 1399 * @return whether this activity supports freeform multi-window and can be put in the freeform 1400 * stack. 1401 */ supportsFreeform()1402 boolean supportsFreeform() { 1403 return mAtmService.mSupportsFreeformWindowManagement && supportsResizeableMultiWindow(); 1404 } 1405 1406 /** 1407 * @return whether this activity supports non-PiP multi-window. 1408 */ supportsResizeableMultiWindow()1409 private boolean supportsResizeableMultiWindow() { 1410 return mAtmService.mSupportsMultiWindow && !isActivityTypeHome() 1411 && (ActivityInfo.isResizeableMode(info.resizeMode) 1412 || mAtmService.mForceResizableActivities); 1413 } 1414 1415 /** 1416 * Check whether this activity can be launched on the specified display. 1417 * 1418 * @param displayId Target display id. 1419 * @return {@code true} if either it is the default display or this activity can be put on a 1420 * secondary screen. 1421 */ canBeLaunchedOnDisplay(int displayId)1422 boolean canBeLaunchedOnDisplay(int displayId) { 1423 return mAtmService.mStackSupervisor.canPlaceEntityOnDisplay(displayId, launchedFromPid, 1424 launchedFromUid, info); 1425 } 1426 1427 /** 1428 * @param beforeStopping Whether this check is for an auto-enter-pip operation, that is to say 1429 * the activity has requested to enter PiP when it would otherwise be stopped. 1430 * 1431 * @return whether this activity is currently allowed to enter PIP. 1432 */ checkEnterPictureInPictureState(String caller, boolean beforeStopping)1433 boolean checkEnterPictureInPictureState(String caller, boolean beforeStopping) { 1434 if (!supportsPictureInPicture()) { 1435 return false; 1436 } 1437 1438 // Check app-ops and see if PiP is supported for this package 1439 if (!checkEnterPictureInPictureAppOpsState()) { 1440 return false; 1441 } 1442 1443 // Check to see if we are in VR mode, and disallow PiP if so 1444 if (mAtmService.shouldDisableNonVrUiLocked()) { 1445 return false; 1446 } 1447 1448 boolean isKeyguardLocked = mAtmService.isKeyguardLocked(); 1449 boolean isCurrentAppLocked = 1450 mAtmService.getLockTaskModeState() != LOCK_TASK_MODE_NONE; 1451 final ActivityDisplay display = getDisplay(); 1452 boolean hasPinnedStack = display != null && display.hasPinnedStack(); 1453 // Don't return early if !isNotLocked, since we want to throw an exception if the activity 1454 // is in an incorrect state 1455 boolean isNotLockedOrOnKeyguard = !isKeyguardLocked && !isCurrentAppLocked; 1456 1457 // We don't allow auto-PiP when something else is already pipped. 1458 if (beforeStopping && hasPinnedStack) { 1459 return false; 1460 } 1461 1462 switch (mState) { 1463 case RESUMED: 1464 // When visible, allow entering PiP if the app is not locked. If it is over the 1465 // keyguard, then we will prompt to unlock in the caller before entering PiP. 1466 return !isCurrentAppLocked && 1467 (supportsEnterPipOnTaskSwitch || !beforeStopping); 1468 case PAUSING: 1469 case PAUSED: 1470 // When pausing, then only allow enter PiP as in the resume state, and in addition, 1471 // require that there is not an existing PiP activity and that the current system 1472 // state supports entering PiP 1473 return isNotLockedOrOnKeyguard && !hasPinnedStack 1474 && supportsEnterPipOnTaskSwitch; 1475 case STOPPING: 1476 // When stopping in a valid state, then only allow enter PiP as in the pause state. 1477 // Otherwise, fall through to throw an exception if the caller is trying to enter 1478 // PiP in an invalid stopping state. 1479 if (supportsEnterPipOnTaskSwitch) { 1480 return isNotLockedOrOnKeyguard && !hasPinnedStack; 1481 } 1482 default: 1483 return false; 1484 } 1485 } 1486 1487 /** 1488 * @return Whether AppOps allows this package to enter picture-in-picture. 1489 */ checkEnterPictureInPictureAppOpsState()1490 private boolean checkEnterPictureInPictureAppOpsState() { 1491 return mAtmService.getAppOpsService().checkOperation( 1492 OP_PICTURE_IN_PICTURE, appInfo.uid, packageName) == MODE_ALLOWED; 1493 } 1494 isAlwaysFocusable()1495 boolean isAlwaysFocusable() { 1496 return (info.flags & FLAG_ALWAYS_FOCUSABLE) != 0; 1497 } 1498 1499 /** Move activity with its stack to front and make the stack focused. */ moveFocusableActivityToTop(String reason)1500 boolean moveFocusableActivityToTop(String reason) { 1501 if (!isFocusable()) { 1502 if (DEBUG_FOCUS) { 1503 Slog.d(TAG_FOCUS, "moveActivityStackToFront: unfocusable activity=" + this); 1504 } 1505 return false; 1506 } 1507 1508 final TaskRecord task = getTaskRecord(); 1509 final ActivityStack stack = getActivityStack(); 1510 if (stack == null) { 1511 Slog.w(TAG, "moveActivityStackToFront: invalid task or stack: activity=" 1512 + this + " task=" + task); 1513 return false; 1514 } 1515 1516 if (mRootActivityContainer.getTopResumedActivity() == this) { 1517 if (DEBUG_FOCUS) { 1518 Slog.d(TAG_FOCUS, "moveActivityStackToFront: already on top, activity=" + this); 1519 } 1520 return false; 1521 } 1522 1523 if (DEBUG_FOCUS) { 1524 Slog.d(TAG_FOCUS, "moveActivityStackToFront: activity=" + this); 1525 } 1526 1527 stack.moveToFront(reason, task); 1528 // Report top activity change to tracking services and WM 1529 if (mRootActivityContainer.getTopResumedActivity() == this) { 1530 // TODO(b/111361570): Support multiple focused apps in WM 1531 mAtmService.setResumedActivityUncheckLocked(this, reason); 1532 } 1533 return true; 1534 } 1535 makeFinishingLocked()1536 void makeFinishingLocked() { 1537 if (finishing) { 1538 return; 1539 } 1540 finishing = true; 1541 if (stopped) { 1542 clearOptionsLocked(); 1543 } 1544 1545 if (mAtmService != null) { 1546 mAtmService.getTaskChangeNotificationController().notifyTaskStackChanged(); 1547 } 1548 } 1549 getUriPermissionsLocked()1550 UriPermissionOwner getUriPermissionsLocked() { 1551 if (uriPermissions == null) { 1552 uriPermissions = new UriPermissionOwner(mAtmService.mUgmInternal, this); 1553 } 1554 return uriPermissions; 1555 } 1556 addResultLocked(ActivityRecord from, String resultWho, int requestCode, int resultCode, Intent resultData)1557 void addResultLocked(ActivityRecord from, String resultWho, 1558 int requestCode, int resultCode, 1559 Intent resultData) { 1560 ActivityResult r = new ActivityResult(from, resultWho, 1561 requestCode, resultCode, resultData); 1562 if (results == null) { 1563 results = new ArrayList<ResultInfo>(); 1564 } 1565 results.add(r); 1566 } 1567 removeResultsLocked(ActivityRecord from, String resultWho, int requestCode)1568 void removeResultsLocked(ActivityRecord from, String resultWho, 1569 int requestCode) { 1570 if (results != null) { 1571 for (int i=results.size()-1; i>=0; i--) { 1572 ActivityResult r = (ActivityResult)results.get(i); 1573 if (r.mFrom != from) continue; 1574 if (r.mResultWho == null) { 1575 if (resultWho != null) continue; 1576 } else { 1577 if (!r.mResultWho.equals(resultWho)) continue; 1578 } 1579 if (r.mRequestCode != requestCode) continue; 1580 1581 results.remove(i); 1582 } 1583 } 1584 } 1585 addNewIntentLocked(ReferrerIntent intent)1586 private void addNewIntentLocked(ReferrerIntent intent) { 1587 if (newIntents == null) { 1588 newIntents = new ArrayList<>(); 1589 } 1590 newIntents.add(intent); 1591 } 1592 isSleeping()1593 final boolean isSleeping() { 1594 final ActivityStack stack = getActivityStack(); 1595 return stack != null ? stack.shouldSleepActivities() : mAtmService.isSleepingLocked(); 1596 } 1597 1598 /** 1599 * Deliver a new Intent to an existing activity, so that its onNewIntent() 1600 * method will be called at the proper time. 1601 */ deliverNewIntentLocked(int callingUid, Intent intent, String referrer)1602 final void deliverNewIntentLocked(int callingUid, Intent intent, String referrer) { 1603 // The activity now gets access to the data associated with this Intent. 1604 mAtmService.mUgmInternal.grantUriPermissionFromIntent(callingUid, packageName, 1605 intent, getUriPermissionsLocked(), mUserId); 1606 final ReferrerIntent rintent = new ReferrerIntent(intent, referrer); 1607 boolean unsent = true; 1608 final boolean isTopActivityWhileSleeping = isTopRunningActivity() && isSleeping(); 1609 1610 // We want to immediately deliver the intent to the activity if: 1611 // - It is currently resumed or paused. i.e. it is currently visible to the user and we want 1612 // the user to see the visual effects caused by the intent delivery now. 1613 // - The device is sleeping and it is the top activity behind the lock screen (b/6700897). 1614 if ((mState == RESUMED || mState == PAUSED || isTopActivityWhileSleeping) 1615 && attachedToProcess()) { 1616 try { 1617 ArrayList<ReferrerIntent> ar = new ArrayList<>(1); 1618 ar.add(rintent); 1619 // Making sure the client state is RESUMED after transaction completed and doing 1620 // so only if activity is currently RESUMED. Otherwise, client may have extra 1621 // life-cycle calls to RESUMED (and PAUSED later). 1622 mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, 1623 NewIntentItem.obtain(ar, mState == RESUMED)); 1624 unsent = false; 1625 } catch (RemoteException e) { 1626 Slog.w(TAG, "Exception thrown sending new intent to " + this, e); 1627 } catch (NullPointerException e) { 1628 Slog.w(TAG, "Exception thrown sending new intent to " + this, e); 1629 } 1630 } 1631 if (unsent) { 1632 addNewIntentLocked(rintent); 1633 } 1634 } 1635 updateOptionsLocked(ActivityOptions options)1636 void updateOptionsLocked(ActivityOptions options) { 1637 if (options != null) { 1638 if (DEBUG_TRANSITION) Slog.i(TAG, "Update options for " + this); 1639 if (pendingOptions != null) { 1640 pendingOptions.abort(); 1641 } 1642 pendingOptions = options; 1643 } 1644 } 1645 applyOptionsLocked()1646 void applyOptionsLocked() { 1647 if (pendingOptions != null 1648 && pendingOptions.getAnimationType() != ANIM_SCENE_TRANSITION) { 1649 if (DEBUG_TRANSITION) Slog.i(TAG, "Applying options for " + this); 1650 applyOptionsLocked(pendingOptions, intent); 1651 if (task == null) { 1652 clearOptionsLocked(false /* withAbort */); 1653 } else { 1654 // This will clear the options for all the ActivityRecords for this Task. 1655 task.clearAllPendingOptions(); 1656 } 1657 } 1658 } 1659 1660 /** 1661 * Apply override app transition base on options & animation type. 1662 */ applyOptionsLocked(ActivityOptions pendingOptions, Intent intent)1663 void applyOptionsLocked(ActivityOptions pendingOptions, Intent intent) { 1664 final int animationType = pendingOptions.getAnimationType(); 1665 final DisplayContent displayContent = mAppWindowToken.getDisplayContent(); 1666 switch (animationType) { 1667 case ANIM_CUSTOM: 1668 displayContent.mAppTransition.overridePendingAppTransition( 1669 pendingOptions.getPackageName(), 1670 pendingOptions.getCustomEnterResId(), 1671 pendingOptions.getCustomExitResId(), 1672 pendingOptions.getOnAnimationStartListener()); 1673 break; 1674 case ANIM_CLIP_REVEAL: 1675 displayContent.mAppTransition.overridePendingAppTransitionClipReveal( 1676 pendingOptions.getStartX(), pendingOptions.getStartY(), 1677 pendingOptions.getWidth(), pendingOptions.getHeight()); 1678 if (intent.getSourceBounds() == null) { 1679 intent.setSourceBounds(new Rect(pendingOptions.getStartX(), 1680 pendingOptions.getStartY(), 1681 pendingOptions.getStartX() + pendingOptions.getWidth(), 1682 pendingOptions.getStartY() + pendingOptions.getHeight())); 1683 } 1684 break; 1685 case ANIM_SCALE_UP: 1686 displayContent.mAppTransition.overridePendingAppTransitionScaleUp( 1687 pendingOptions.getStartX(), pendingOptions.getStartY(), 1688 pendingOptions.getWidth(), pendingOptions.getHeight()); 1689 if (intent.getSourceBounds() == null) { 1690 intent.setSourceBounds(new Rect(pendingOptions.getStartX(), 1691 pendingOptions.getStartY(), 1692 pendingOptions.getStartX() + pendingOptions.getWidth(), 1693 pendingOptions.getStartY() + pendingOptions.getHeight())); 1694 } 1695 break; 1696 case ANIM_THUMBNAIL_SCALE_UP: 1697 case ANIM_THUMBNAIL_SCALE_DOWN: 1698 final boolean scaleUp = (animationType == ANIM_THUMBNAIL_SCALE_UP); 1699 final GraphicBuffer buffer = pendingOptions.getThumbnail(); 1700 displayContent.mAppTransition.overridePendingAppTransitionThumb(buffer, 1701 pendingOptions.getStartX(), pendingOptions.getStartY(), 1702 pendingOptions.getOnAnimationStartListener(), 1703 scaleUp); 1704 if (intent.getSourceBounds() == null && buffer != null) { 1705 intent.setSourceBounds(new Rect(pendingOptions.getStartX(), 1706 pendingOptions.getStartY(), 1707 pendingOptions.getStartX() + buffer.getWidth(), 1708 pendingOptions.getStartY() + buffer.getHeight())); 1709 } 1710 break; 1711 case ANIM_THUMBNAIL_ASPECT_SCALE_UP: 1712 case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN: 1713 final AppTransitionAnimationSpec[] specs = pendingOptions.getAnimSpecs(); 1714 final IAppTransitionAnimationSpecsFuture specsFuture = 1715 pendingOptions.getSpecsFuture(); 1716 if (specsFuture != null) { 1717 displayContent.mAppTransition.overridePendingAppTransitionMultiThumbFuture( 1718 specsFuture, pendingOptions.getOnAnimationStartListener(), 1719 animationType == ANIM_THUMBNAIL_ASPECT_SCALE_UP); 1720 } else if (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_DOWN 1721 && specs != null) { 1722 displayContent.mAppTransition.overridePendingAppTransitionMultiThumb( 1723 specs, pendingOptions.getOnAnimationStartListener(), 1724 pendingOptions.getAnimationFinishedListener(), false); 1725 } else { 1726 displayContent.mAppTransition.overridePendingAppTransitionAspectScaledThumb( 1727 pendingOptions.getThumbnail(), 1728 pendingOptions.getStartX(), pendingOptions.getStartY(), 1729 pendingOptions.getWidth(), pendingOptions.getHeight(), 1730 pendingOptions.getOnAnimationStartListener(), 1731 (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_UP)); 1732 if (intent.getSourceBounds() == null) { 1733 intent.setSourceBounds(new Rect(pendingOptions.getStartX(), 1734 pendingOptions.getStartY(), 1735 pendingOptions.getStartX() + pendingOptions.getWidth(), 1736 pendingOptions.getStartY() + pendingOptions.getHeight())); 1737 } 1738 } 1739 break; 1740 case ANIM_OPEN_CROSS_PROFILE_APPS: 1741 displayContent.mAppTransition 1742 .overridePendingAppTransitionStartCrossProfileApps(); 1743 break; 1744 case ANIM_REMOTE_ANIMATION: 1745 displayContent.mAppTransition.overridePendingAppTransitionRemote( 1746 pendingOptions.getRemoteAnimationAdapter()); 1747 break; 1748 case ANIM_NONE: 1749 break; 1750 default: 1751 Slog.e(TAG_WM, "applyOptionsLocked: Unknown animationType=" + animationType); 1752 break; 1753 } 1754 } 1755 getOptionsForTargetActivityLocked()1756 ActivityOptions getOptionsForTargetActivityLocked() { 1757 return pendingOptions != null ? pendingOptions.forTargetActivity() : null; 1758 } 1759 clearOptionsLocked()1760 void clearOptionsLocked() { 1761 clearOptionsLocked(true /* withAbort */); 1762 } 1763 clearOptionsLocked(boolean withAbort)1764 void clearOptionsLocked(boolean withAbort) { 1765 if (withAbort && pendingOptions != null) { 1766 pendingOptions.abort(); 1767 } 1768 pendingOptions = null; 1769 } 1770 takeOptionsLocked(boolean fromClient)1771 ActivityOptions takeOptionsLocked(boolean fromClient) { 1772 if (DEBUG_TRANSITION) Slog.i(TAG, "Taking options for " + this + " callers=" 1773 + Debug.getCallers(6)); 1774 ActivityOptions opts = pendingOptions; 1775 1776 // If we are trying to take activity options from the client, do not null it out if it's a 1777 // remote animation as the client doesn't need it ever. This is a workaround when client is 1778 // faster to take the options than we are to resume the next activity. 1779 // TODO (b/132432864): Fix the root cause of these transition preparing/applying options 1780 // timing somehow 1781 if (!fromClient || opts == null || opts.getRemoteAnimationAdapter() == null) { 1782 pendingOptions = null; 1783 } 1784 return opts; 1785 } 1786 removeUriPermissionsLocked()1787 void removeUriPermissionsLocked() { 1788 if (uriPermissions != null) { 1789 uriPermissions.removeUriPermissions(); 1790 uriPermissions = null; 1791 } 1792 } 1793 pauseKeyDispatchingLocked()1794 void pauseKeyDispatchingLocked() { 1795 if (!keysPaused) { 1796 keysPaused = true; 1797 1798 // TODO: remove the check after unification with AppWindowToken. The DC check is not 1799 // needed after no mock mAppWindowToken in tests. 1800 if (mAppWindowToken != null && mAppWindowToken.getDisplayContent() != null) { 1801 mAppWindowToken.getDisplayContent().getInputMonitor().pauseDispatchingLw( 1802 mAppWindowToken); 1803 } 1804 } 1805 } 1806 resumeKeyDispatchingLocked()1807 void resumeKeyDispatchingLocked() { 1808 if (keysPaused) { 1809 keysPaused = false; 1810 1811 // TODO: remove the check after unification with AppWindowToken. The DC check is not 1812 // needed after no mock mAppWindowToken in tests. 1813 if (mAppWindowToken != null && mAppWindowToken.getDisplayContent() != null) { 1814 mAppWindowToken.getDisplayContent().getInputMonitor().resumeDispatchingLw( 1815 mAppWindowToken); 1816 } 1817 } 1818 } 1819 updateTaskDescription(CharSequence description)1820 private void updateTaskDescription(CharSequence description) { 1821 task.lastDescription = description; 1822 } 1823 setDeferHidingClient(boolean deferHidingClient)1824 void setDeferHidingClient(boolean deferHidingClient) { 1825 if (mDeferHidingClient == deferHidingClient) { 1826 return; 1827 } 1828 mDeferHidingClient = deferHidingClient; 1829 if (!mDeferHidingClient && !visible) { 1830 // Hiding the client is no longer deferred and the app isn't visible still, go ahead and 1831 // update the visibility. 1832 setVisibility(false); 1833 } 1834 } 1835 setVisibility(boolean visible)1836 void setVisibility(boolean visible) { 1837 if (mAppWindowToken == null) { 1838 Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: " 1839 + appToken); 1840 return; 1841 } 1842 mAppWindowToken.setVisibility(visible, mDeferHidingClient); 1843 mStackSupervisor.getActivityMetricsLogger().notifyVisibilityChanged(this); 1844 } 1845 1846 // TODO: Look into merging with #commitVisibility() setVisible(boolean newVisible)1847 void setVisible(boolean newVisible) { 1848 visible = newVisible; 1849 mDeferHidingClient = !visible && mDeferHidingClient; 1850 setVisibility(visible); 1851 mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true; 1852 } 1853 setState(ActivityState state, String reason)1854 void setState(ActivityState state, String reason) { 1855 if (DEBUG_STATES) Slog.v(TAG_STATES, "State movement: " + this + " from:" + getState() 1856 + " to:" + state + " reason:" + reason); 1857 1858 if (state == mState) { 1859 // No need to do anything if state doesn't change. 1860 if (DEBUG_STATES) Slog.v(TAG_STATES, "State unchanged from:" + state); 1861 return; 1862 } 1863 1864 mState = state; 1865 1866 final TaskRecord parent = getTaskRecord(); 1867 1868 if (parent != null) { 1869 parent.onActivityStateChanged(this, state, reason); 1870 } 1871 1872 // The WindowManager interprets the app stopping signal as 1873 // an indication that the Surface will eventually be destroyed. 1874 // This however isn't necessarily true if we are going to sleep. 1875 if (state == STOPPING && !isSleeping()) { 1876 if (mAppWindowToken == null) { 1877 Slog.w(TAG_WM, "Attempted to notify stopping on non-existing app token: " 1878 + appToken); 1879 return; 1880 } 1881 mAppWindowToken.detachChildren(); 1882 } 1883 1884 if (state == RESUMED) { 1885 mAtmService.updateBatteryStats(this, true); 1886 mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_RESUMED); 1887 } else if (state == PAUSED) { 1888 mAtmService.updateBatteryStats(this, false); 1889 mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_PAUSED); 1890 } else if (state == STOPPED) { 1891 mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_STOPPED); 1892 } else if (state == DESTROYED) { 1893 mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_DESTROYED); 1894 } 1895 } 1896 getState()1897 ActivityState getState() { 1898 return mState; 1899 } 1900 1901 /** 1902 * Returns {@code true} if the Activity is in the specified state. 1903 */ isState(ActivityState state)1904 boolean isState(ActivityState state) { 1905 return state == mState; 1906 } 1907 1908 /** 1909 * Returns {@code true} if the Activity is in one of the specified states. 1910 */ isState(ActivityState state1, ActivityState state2)1911 boolean isState(ActivityState state1, ActivityState state2) { 1912 return state1 == mState || state2 == mState; 1913 } 1914 1915 /** 1916 * Returns {@code true} if the Activity is in one of the specified states. 1917 */ isState(ActivityState state1, ActivityState state2, ActivityState state3)1918 boolean isState(ActivityState state1, ActivityState state2, ActivityState state3) { 1919 return state1 == mState || state2 == mState || state3 == mState; 1920 } 1921 1922 /** 1923 * Returns {@code true} if the Activity is in one of the specified states. 1924 */ isState(ActivityState state1, ActivityState state2, ActivityState state3, ActivityState state4)1925 boolean isState(ActivityState state1, ActivityState state2, ActivityState state3, 1926 ActivityState state4) { 1927 return state1 == mState || state2 == mState || state3 == mState || state4 == mState; 1928 } 1929 notifyAppResumed(boolean wasStopped)1930 void notifyAppResumed(boolean wasStopped) { 1931 if (mAppWindowToken == null) { 1932 Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " 1933 + appToken); 1934 return; 1935 } 1936 mAppWindowToken.notifyAppResumed(wasStopped); 1937 } 1938 notifyUnknownVisibilityLaunched()1939 void notifyUnknownVisibilityLaunched() { 1940 1941 // No display activities never add a window, so there is no point in waiting them for 1942 // relayout. 1943 if (!noDisplay) { 1944 if (mAppWindowToken != null) { 1945 mAppWindowToken.getDisplayContent().mUnknownAppVisibilityController 1946 .notifyLaunched(mAppWindowToken); 1947 } 1948 } 1949 } 1950 1951 /** 1952 * @return true if the input activity should be made visible, ignoring any effect Keyguard 1953 * might have on the visibility 1954 * 1955 * TODO(b/123540470): Combine this method and {@link #shouldBeVisible(boolean)}. 1956 * 1957 * @see {@link ActivityStack#checkKeyguardVisibility} 1958 */ shouldBeVisibleIgnoringKeyguard(boolean behindFullscreenActivity)1959 boolean shouldBeVisibleIgnoringKeyguard(boolean behindFullscreenActivity) { 1960 if (!okToShowLocked()) { 1961 return false; 1962 } 1963 1964 return !behindFullscreenActivity || mLaunchTaskBehind; 1965 } 1966 shouldBeVisible(boolean behindFullscreenActivity)1967 boolean shouldBeVisible(boolean behindFullscreenActivity) { 1968 // Check whether activity should be visible without Keyguard influence 1969 visibleIgnoringKeyguard = shouldBeVisibleIgnoringKeyguard(behindFullscreenActivity); 1970 1971 final ActivityStack stack = getActivityStack(); 1972 if (stack == null) { 1973 return false; 1974 } 1975 1976 // Whether the activity is on the sleeping display. 1977 // TODO(b/129750406): This should be applied for the default display, too. 1978 final boolean isDisplaySleeping = getDisplay().isSleeping() 1979 && getDisplayId() != DEFAULT_DISPLAY; 1980 // Whether this activity is the top activity of this stack. 1981 final boolean isTop = this == stack.getTopActivity(); 1982 // Exclude the case where this is the top activity in a pinned stack. 1983 final boolean isTopNotPinnedStack = stack.isAttached() 1984 && stack.getDisplay().isTopNotPinnedStack(stack); 1985 // Now check whether it's really visible depending on Keyguard state, and update 1986 // {@link ActivityStack} internal states. 1987 final boolean visibleIgnoringDisplayStatus = stack.checkKeyguardVisibility(this, 1988 visibleIgnoringKeyguard, isTop && isTopNotPinnedStack); 1989 return visibleIgnoringDisplayStatus && !isDisplaySleeping; 1990 } 1991 shouldBeVisible()1992 boolean shouldBeVisible() { 1993 final ActivityStack stack = getActivityStack(); 1994 if (stack == null) { 1995 return false; 1996 } 1997 1998 // TODO: Use real value of behindFullscreenActivity calculated using the same logic in 1999 // ActivityStack#ensureActivitiesVisibleLocked(). 2000 return shouldBeVisible(!stack.shouldBeVisible(null /* starting */)); 2001 } 2002 makeVisibleIfNeeded(ActivityRecord starting, boolean reportToClient)2003 void makeVisibleIfNeeded(ActivityRecord starting, boolean reportToClient) { 2004 // This activity is not currently visible, but is running. Tell it to become visible. 2005 if (mState == RESUMED || this == starting) { 2006 if (DEBUG_VISIBILITY) Slog.d(TAG_VISIBILITY, 2007 "Not making visible, r=" + this + " state=" + mState + " starting=" + starting); 2008 return; 2009 } 2010 2011 // If this activity is paused, tell it to now show its window. 2012 if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, 2013 "Making visible and scheduling visibility: " + this); 2014 final ActivityStack stack = getActivityStack(); 2015 try { 2016 if (stack.mTranslucentActivityWaiting != null) { 2017 updateOptionsLocked(returningOptions); 2018 stack.mUndrawnActivitiesBelowTopTranslucent.add(this); 2019 } 2020 setVisible(true); 2021 sleeping = false; 2022 app.postPendingUiCleanMsg(true); 2023 if (reportToClient) { 2024 makeClientVisible(); 2025 } else { 2026 mClientVisibilityDeferred = true; 2027 } 2028 // The activity may be waiting for stop, but that is no longer appropriate for it. 2029 mStackSupervisor.mStoppingActivities.remove(this); 2030 mStackSupervisor.mGoingToSleepActivities.remove(this); 2031 } catch (Exception e) { 2032 // Just skip on any failure; we'll make it visible when it next restarts. 2033 Slog.w(TAG, "Exception thrown making visible: " + intent.getComponent(), e); 2034 } 2035 handleAlreadyVisible(); 2036 } 2037 2038 /** Send visibility change message to the client and pause if needed. */ makeClientVisible()2039 void makeClientVisible() { 2040 mClientVisibilityDeferred = false; 2041 try { 2042 mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, 2043 WindowVisibilityItem.obtain(true /* showWindow */)); 2044 makeActiveIfNeeded(null /* activeActivity*/); 2045 if (isState(STOPPING, STOPPED) && isFocusable()) { 2046 // #shouldMakeActive() only evaluates the topmost activities in task, so 2047 // activities that are not the topmost in task are not being resumed or paused. 2048 // For activities that are still in STOPPING or STOPPED state, updates the state 2049 // to PAUSE at least when making it visible. 2050 setState(PAUSED, "makeClientVisible"); 2051 } 2052 } catch (Exception e) { 2053 Slog.w(TAG, "Exception thrown sending visibility update: " + intent.getComponent(), e); 2054 } 2055 } 2056 2057 /** 2058 * Make activity resumed or paused if needed. 2059 * @param activeActivity an activity that is resumed or just completed pause action. 2060 * We won't change the state of this activity. 2061 */ makeActiveIfNeeded(ActivityRecord activeActivity)2062 boolean makeActiveIfNeeded(ActivityRecord activeActivity) { 2063 if (shouldResumeActivity(activeActivity)) { 2064 if (DEBUG_VISIBILITY) { 2065 Slog.v("TAG_VISIBILITY", "Resume visible activity, " + this); 2066 } 2067 return getActivityStack().resumeTopActivityUncheckedLocked(activeActivity /* prev */, 2068 null /* options */); 2069 } else if (shouldPauseActivity(activeActivity)) { 2070 if (DEBUG_VISIBILITY) { 2071 Slog.v("TAG_VISIBILITY", "Pause visible activity, " + this); 2072 } 2073 // An activity must be in the {@link PAUSING} state for the system to validate 2074 // the move to {@link PAUSED}. 2075 setState(PAUSING, "makeVisibleIfNeeded"); 2076 try { 2077 mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, 2078 PauseActivityItem.obtain(finishing, false /* userLeaving */, 2079 configChangeFlags, false /* dontReport */)); 2080 } catch (Exception e) { 2081 Slog.w(TAG, "Exception thrown sending pause: " + intent.getComponent(), e); 2082 } 2083 } 2084 return false; 2085 } 2086 2087 /** 2088 * Check if activity should be moved to PAUSED state. The activity: 2089 * - should be eligible to be made active (see {@link #shouldMakeActive(ActivityRecord)}) 2090 * - should be non-focusable 2091 * - should not be currently pausing or paused 2092 * @param activeActivity the activity that is active or just completed pause action. We won't 2093 * resume if this activity is active. 2094 */ shouldPauseActivity(ActivityRecord activeActivity)2095 private boolean shouldPauseActivity(ActivityRecord activeActivity) { 2096 return shouldMakeActive(activeActivity) && !isFocusable() && !isState(PAUSING, PAUSED); 2097 } 2098 2099 /** 2100 * Check if activity should be moved to RESUMED state. The activity: 2101 * - should be eligible to be made active (see {@link #shouldMakeActive(ActivityRecord)}) 2102 * - should be focusable 2103 * @param activeActivity the activity that is active or just completed pause action. We won't 2104 * resume if this activity is active. 2105 */ 2106 @VisibleForTesting shouldResumeActivity(ActivityRecord activeActivity)2107 boolean shouldResumeActivity(ActivityRecord activeActivity) { 2108 return shouldMakeActive(activeActivity) && isFocusable() && !isState(RESUMED) 2109 && getActivityStack().getVisibility(activeActivity) == STACK_VISIBILITY_VISIBLE; 2110 } 2111 2112 /** 2113 * Check if activity is eligible to be made active (resumed of paused). The activity: 2114 * - should be paused, stopped or stopping 2115 * - should not be the currently active one or launching behind other tasks 2116 * - should be either the topmost in task, or right below the top activity that is finishing 2117 * If all of these conditions are not met at the same time, the activity cannot be made active. 2118 */ 2119 @VisibleForTesting shouldMakeActive(ActivityRecord activeActivity)2120 boolean shouldMakeActive(ActivityRecord activeActivity) { 2121 // If the activity is stopped, stopping, cycle to an active state. We avoid doing 2122 // this when there is an activity waiting to become translucent as the extra binder 2123 // calls will lead to noticeable jank. A later call to 2124 // ActivityStack#ensureActivitiesVisibleLocked will bring the activity to a proper 2125 // active state. 2126 if (!isState(RESUMED, PAUSED, STOPPED, STOPPING) 2127 || getActivityStack().mTranslucentActivityWaiting != null) { 2128 return false; 2129 } 2130 2131 if (this == activeActivity) { 2132 return false; 2133 } 2134 2135 if (!mStackSupervisor.readyToResume()) { 2136 // Making active is currently deferred (e.g. because an activity launch is in progress). 2137 return false; 2138 } 2139 2140 if (this.mLaunchTaskBehind) { 2141 // This activity is being launched from behind, which means that it's not intended to be 2142 // presented to user right now, even if it's set to be visible. 2143 return false; 2144 } 2145 2146 // Check if position in task allows to become paused 2147 final int positionInTask = task.mActivities.indexOf(this); 2148 if (positionInTask == -1) { 2149 throw new IllegalStateException("Activity not found in its task"); 2150 } 2151 if (positionInTask == task.mActivities.size() - 1) { 2152 // It's the topmost activity in the task - should become resumed now 2153 return true; 2154 } 2155 // Check if activity above is finishing now and this one becomes the topmost in task. 2156 final ActivityRecord activityAbove = task.mActivities.get(positionInTask + 1); 2157 if (activityAbove.finishing && results == null) { 2158 // We will only allow making active if activity above wasn't launched for result. 2159 // Otherwise it will cause this activity to resume before getting result. 2160 return true; 2161 } 2162 return false; 2163 } 2164 handleAlreadyVisible()2165 boolean handleAlreadyVisible() { 2166 stopFreezingScreenLocked(false); 2167 try { 2168 if (returningOptions != null) { 2169 app.getThread().scheduleOnNewActivityOptions(appToken, returningOptions.toBundle()); 2170 } 2171 } catch(RemoteException e) { 2172 } 2173 return mState == RESUMED; 2174 } 2175 activityResumedLocked(IBinder token)2176 static void activityResumedLocked(IBinder token) { 2177 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 2178 if (DEBUG_SAVED_STATE) Slog.i(TAG_STATES, "Resumed activity; dropping state of: " + r); 2179 if (r == null) { 2180 // If an app reports resumed after a long delay, the record on server side might have 2181 // been removed (e.g. destroy timeout), so the token could be null. 2182 return; 2183 } 2184 r.icicle = null; 2185 r.haveState = false; 2186 2187 final ActivityDisplay display = r.getDisplay(); 2188 if (display != null) { 2189 display.handleActivitySizeCompatModeIfNeeded(r); 2190 } 2191 } 2192 2193 /** 2194 * Once we know that we have asked an application to put an activity in the resumed state 2195 * (either by launching it or explicitly telling it), this function updates the rest of our 2196 * state to match that fact. 2197 */ completeResumeLocked()2198 void completeResumeLocked() { 2199 final boolean wasVisible = visible; 2200 setVisible(true); 2201 if (!wasVisible) { 2202 // Visibility has changed, so take a note of it so we call the TaskStackChangedListener 2203 mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true; 2204 } 2205 idle = false; 2206 results = null; 2207 newIntents = null; 2208 stopped = false; 2209 2210 if (isActivityTypeHome()) { 2211 mStackSupervisor.updateHomeProcess(task.mActivities.get(0).app); 2212 } 2213 2214 if (nowVisible) { 2215 mStackSupervisor.stopWaitingForActivityVisible(this); 2216 } 2217 2218 // Schedule an idle timeout in case the app doesn't do it for us. 2219 mStackSupervisor.scheduleIdleTimeoutLocked(this); 2220 2221 mStackSupervisor.reportResumedActivityLocked(this); 2222 2223 resumeKeyDispatchingLocked(); 2224 final ActivityStack stack = getActivityStack(); 2225 mStackSupervisor.mNoAnimActivities.clear(); 2226 2227 // Mark the point when the activity is resuming 2228 // TODO: To be more accurate, the mark should be before the onCreate, 2229 // not after the onResume. But for subsequent starts, onResume is fine. 2230 if (hasProcess()) { 2231 cpuTimeAtResume = app.getCpuTime(); 2232 } else { 2233 cpuTimeAtResume = 0; // Couldn't get the cpu time of process 2234 } 2235 2236 returningOptions = null; 2237 2238 if (canTurnScreenOn()) { 2239 mStackSupervisor.wakeUp("turnScreenOnFlag"); 2240 } else { 2241 // If the screen is going to turn on because the caller explicitly requested it and 2242 // the keyguard is not showing don't attempt to sleep. Otherwise the Activity will 2243 // pause and then resume again later, which will result in a double life-cycle event. 2244 stack.checkReadyForSleep(); 2245 } 2246 } 2247 activityStoppedLocked(Bundle newIcicle, PersistableBundle newPersistentState, CharSequence description)2248 final void activityStoppedLocked(Bundle newIcicle, PersistableBundle newPersistentState, 2249 CharSequence description) { 2250 final ActivityStack stack = getActivityStack(); 2251 final boolean isStopping = mState == STOPPING; 2252 if (!isStopping && mState != RESTARTING_PROCESS) { 2253 Slog.i(TAG, "Activity reported stop, but no longer stopping: " + this); 2254 stack.mHandler.removeMessages(STOP_TIMEOUT_MSG, this); 2255 return; 2256 } 2257 if (newPersistentState != null) { 2258 persistentState = newPersistentState; 2259 mAtmService.notifyTaskPersisterLocked(task, false); 2260 } 2261 if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE, "Saving icicle of " + this + ": " + icicle); 2262 2263 if (newIcicle != null) { 2264 // If icicle is null, this is happening due to a timeout, so we haven't really saved 2265 // the state. 2266 icicle = newIcicle; 2267 haveState = true; 2268 launchCount = 0; 2269 updateTaskDescription(description); 2270 } 2271 if (!stopped) { 2272 if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to STOPPED: " + this + " (stop complete)"); 2273 stack.mHandler.removeMessages(STOP_TIMEOUT_MSG, this); 2274 stopped = true; 2275 if (isStopping) { 2276 setState(STOPPED, "activityStoppedLocked"); 2277 } 2278 2279 if (mAppWindowToken != null) { 2280 mAppWindowToken.notifyAppStopped(); 2281 } 2282 2283 if (finishing) { 2284 clearOptionsLocked(); 2285 } else { 2286 if (deferRelaunchUntilPaused) { 2287 stack.destroyActivityLocked(this, true /* removeFromApp */, "stop-config"); 2288 mRootActivityContainer.resumeFocusedStacksTopActivities(); 2289 } else { 2290 mRootActivityContainer.updatePreviousProcess(this); 2291 } 2292 } 2293 } 2294 } 2295 startLaunchTickingLocked()2296 void startLaunchTickingLocked() { 2297 if (Build.IS_USER) { 2298 return; 2299 } 2300 if (launchTickTime == 0) { 2301 launchTickTime = SystemClock.uptimeMillis(); 2302 continueLaunchTickingLocked(); 2303 } 2304 } 2305 continueLaunchTickingLocked()2306 boolean continueLaunchTickingLocked() { 2307 if (launchTickTime == 0) { 2308 return false; 2309 } 2310 2311 final ActivityStack stack = getActivityStack(); 2312 if (stack == null) { 2313 return false; 2314 } 2315 2316 Message msg = stack.mHandler.obtainMessage(LAUNCH_TICK_MSG, this); 2317 stack.mHandler.removeMessages(LAUNCH_TICK_MSG); 2318 stack.mHandler.sendMessageDelayed(msg, LAUNCH_TICK); 2319 return true; 2320 } 2321 finishLaunchTickingLocked()2322 void finishLaunchTickingLocked() { 2323 launchTickTime = 0; 2324 final ActivityStack stack = getActivityStack(); 2325 if (stack != null) { 2326 stack.mHandler.removeMessages(LAUNCH_TICK_MSG); 2327 } 2328 } 2329 2330 // IApplicationToken 2331 mayFreezeScreenLocked(WindowProcessController app)2332 public boolean mayFreezeScreenLocked(WindowProcessController app) { 2333 // Only freeze the screen if this activity is currently attached to 2334 // an application, and that application is not blocked or unresponding. 2335 // In any other case, we can't count on getting the screen unfrozen, 2336 // so it is best to leave as-is. 2337 return hasProcess() && !app.isCrashing() && !app.isNotResponding(); 2338 } 2339 startFreezingScreenLocked(WindowProcessController app, int configChanges)2340 public void startFreezingScreenLocked(WindowProcessController app, int configChanges) { 2341 if (mayFreezeScreenLocked(app)) { 2342 if (mAppWindowToken == null) { 2343 Slog.w(TAG_WM, 2344 "Attempted to freeze screen with non-existing app token: " + appToken); 2345 return; 2346 } 2347 2348 // Window configuration changes only effect windows, so don't require a screen freeze. 2349 int freezableConfigChanges = configChanges & ~(CONFIG_WINDOW_CONFIGURATION); 2350 if (freezableConfigChanges == 0 && mAppWindowToken.okToDisplay()) { 2351 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Skipping set freeze of " + appToken); 2352 return; 2353 } 2354 2355 mAppWindowToken.startFreezingScreen(); 2356 } 2357 } 2358 stopFreezingScreenLocked(boolean force)2359 public void stopFreezingScreenLocked(boolean force) { 2360 if (force || frozenBeforeDestroy) { 2361 frozenBeforeDestroy = false; 2362 if (mAppWindowToken == null) { 2363 return; 2364 } 2365 if (DEBUG_ORIENTATION) { 2366 Slog.v(TAG_WM, "Clear freezing of " + appToken + ": hidden=" 2367 + mAppWindowToken.isHidden() + " freezing=" 2368 + mAppWindowToken.isFreezingScreen()); 2369 } 2370 mAppWindowToken.stopFreezingScreen(true, force); 2371 } 2372 } 2373 reportFullyDrawnLocked(boolean restoredFromBundle)2374 public void reportFullyDrawnLocked(boolean restoredFromBundle) { 2375 final WindowingModeTransitionInfoSnapshot info = mStackSupervisor 2376 .getActivityMetricsLogger().logAppTransitionReportedDrawn(this, restoredFromBundle); 2377 if (info != null) { 2378 mStackSupervisor.reportActivityLaunchedLocked(false /* timeout */, this, 2379 info.windowsFullyDrawnDelayMs, info.getLaunchState()); 2380 } 2381 } 2382 2383 /** 2384 * Called when the starting window for this container is drawn. 2385 */ onStartingWindowDrawn(long timestamp)2386 public void onStartingWindowDrawn(long timestamp) { 2387 synchronized (mAtmService.mGlobalLock) { 2388 mStackSupervisor.getActivityMetricsLogger().notifyStartingWindowDrawn( 2389 getWindowingMode(), timestamp); 2390 } 2391 } 2392 2393 /** Called when the windows associated app window container are drawn. */ onWindowsDrawn(boolean drawn, long timestamp)2394 public void onWindowsDrawn(boolean drawn, long timestamp) { 2395 synchronized (mAtmService.mGlobalLock) { 2396 mDrawn = drawn; 2397 if (!drawn) { 2398 return; 2399 } 2400 final WindowingModeTransitionInfoSnapshot info = mStackSupervisor 2401 .getActivityMetricsLogger().notifyWindowsDrawn(getWindowingMode(), timestamp); 2402 final int windowsDrawnDelayMs = info != null ? info.windowsDrawnDelayMs : INVALID_DELAY; 2403 final @LaunchState int launchState = info != null ? info.getLaunchState() : -1; 2404 mStackSupervisor.reportActivityLaunchedLocked(false /* timeout */, this, 2405 windowsDrawnDelayMs, launchState); 2406 mStackSupervisor.stopWaitingForActivityVisible(this); 2407 finishLaunchTickingLocked(); 2408 if (task != null) { 2409 task.hasBeenVisible = true; 2410 } 2411 } 2412 } 2413 2414 /** Called when the windows associated app window container are visible. */ onWindowsVisible()2415 public void onWindowsVisible() { 2416 synchronized (mAtmService.mGlobalLock) { 2417 mStackSupervisor.stopWaitingForActivityVisible(this); 2418 if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsVisibleLocked(): " + this); 2419 if (!nowVisible) { 2420 nowVisible = true; 2421 lastVisibleTime = SystemClock.uptimeMillis(); 2422 mAtmService.scheduleAppGcsLocked(); 2423 } 2424 } 2425 } 2426 2427 /** Called when the windows associated app window container are no longer visible. */ onWindowsGone()2428 public void onWindowsGone() { 2429 synchronized (mAtmService.mGlobalLock) { 2430 if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsGone(): " + this); 2431 nowVisible = false; 2432 } 2433 } 2434 onAnimationFinished()2435 void onAnimationFinished() { 2436 if (mRootActivityContainer.allResumedActivitiesIdle() 2437 || mStackSupervisor.isStoppingNoHistoryActivity()) { 2438 // If all activities are already idle or there is an activity that must be 2439 // stopped immediately after visible, then we now need to make sure we perform 2440 // the full stop of this activity. This is because we won't do that while they are still 2441 // waiting for the animation to finish. 2442 if (mStackSupervisor.mStoppingActivities.contains(this)) { 2443 mStackSupervisor.scheduleIdleLocked(); 2444 } 2445 } else { 2446 // Instead of doing the full stop routine here, let's just hide any activities 2447 // we now can, and let them stop when the normal idle happens. 2448 mStackSupervisor.processStoppingActivitiesLocked(null /* idleActivity */, 2449 false /* remove */, true /* processPausingActivities */); 2450 } 2451 } 2452 2453 /** 2454 * Called when the key dispatching to a window associated with the app window container 2455 * timed-out. 2456 * 2457 * @param reason The reason for the key dispatching time out. 2458 * @param windowPid The pid of the window key dispatching timed out on. 2459 * @return True if input dispatching should be aborted. 2460 */ keyDispatchingTimedOut(String reason, int windowPid)2461 public boolean keyDispatchingTimedOut(String reason, int windowPid) { 2462 ActivityRecord anrActivity; 2463 WindowProcessController anrApp; 2464 boolean windowFromSameProcessAsActivity; 2465 synchronized (mAtmService.mGlobalLock) { 2466 anrActivity = getWaitingHistoryRecordLocked(); 2467 anrApp = app; 2468 windowFromSameProcessAsActivity = 2469 !hasProcess() || app.getPid() == windowPid || windowPid == -1; 2470 } 2471 2472 if (windowFromSameProcessAsActivity) { 2473 return mAtmService.mAmInternal.inputDispatchingTimedOut(anrApp.mOwner, 2474 anrActivity.shortComponentName, anrActivity.appInfo, shortComponentName, 2475 app, false, reason); 2476 } else { 2477 // In this case another process added windows using this activity token. So, we call the 2478 // generic service input dispatch timed out method so that the right process is blamed. 2479 return mAtmService.mAmInternal.inputDispatchingTimedOut( 2480 windowPid, false /* aboveSystem */, reason) < 0; 2481 } 2482 } 2483 getWaitingHistoryRecordLocked()2484 private ActivityRecord getWaitingHistoryRecordLocked() { 2485 // First find the real culprit... if this activity has stopped, then the key dispatching 2486 // timeout should not be caused by this. 2487 if (stopped) { 2488 final ActivityStack stack = mRootActivityContainer.getTopDisplayFocusedStack(); 2489 // Try to use the one which is closest to top. 2490 ActivityRecord r = stack.getResumedActivity(); 2491 if (r == null) { 2492 r = stack.mPausingActivity; 2493 } 2494 if (r != null) { 2495 return r; 2496 } 2497 } 2498 return this; 2499 } 2500 2501 /** Checks whether the activity should be shown for current user. */ okToShowLocked()2502 public boolean okToShowLocked() { 2503 // We cannot show activities when the device is locked and the application is not 2504 // encryption aware. 2505 if (!StorageManager.isUserKeyUnlocked(mUserId) 2506 && !info.applicationInfo.isEncryptionAware()) { 2507 return false; 2508 } 2509 2510 return (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0 2511 || (mStackSupervisor.isCurrentProfileLocked(mUserId) 2512 && mAtmService.mAmInternal.isUserRunning(mUserId, 0 /* flags */)); 2513 } 2514 2515 /** 2516 * This method will return true if the activity is either visible, is becoming visible, is 2517 * currently pausing, or is resumed. 2518 */ isInterestingToUserLocked()2519 public boolean isInterestingToUserLocked() { 2520 return visible || nowVisible || mState == PAUSING || mState == RESUMED; 2521 } 2522 setSleeping(boolean _sleeping)2523 void setSleeping(boolean _sleeping) { 2524 setSleeping(_sleeping, false); 2525 } 2526 setSleeping(boolean _sleeping, boolean force)2527 void setSleeping(boolean _sleeping, boolean force) { 2528 if (!force && sleeping == _sleeping) { 2529 return; 2530 } 2531 if (attachedToProcess()) { 2532 try { 2533 app.getThread().scheduleSleeping(appToken, _sleeping); 2534 if (_sleeping && !mStackSupervisor.mGoingToSleepActivities.contains(this)) { 2535 mStackSupervisor.mGoingToSleepActivities.add(this); 2536 } 2537 sleeping = _sleeping; 2538 } catch (RemoteException e) { 2539 Slog.w(TAG, "Exception thrown when sleeping: " + intent.getComponent(), e); 2540 } 2541 } 2542 } 2543 getTaskForActivityLocked(IBinder token, boolean onlyRoot)2544 static int getTaskForActivityLocked(IBinder token, boolean onlyRoot) { 2545 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 2546 if (r == null) { 2547 return INVALID_TASK_ID; 2548 } 2549 final TaskRecord task = r.task; 2550 final int activityNdx = task.mActivities.indexOf(r); 2551 if (activityNdx < 0 || (onlyRoot && activityNdx > task.findEffectiveRootIndex())) { 2552 return INVALID_TASK_ID; 2553 } 2554 return task.taskId; 2555 } 2556 isInStackLocked(IBinder token)2557 static ActivityRecord isInStackLocked(IBinder token) { 2558 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 2559 return (r != null) ? r.getActivityStack().isInStackLocked(r) : null; 2560 } 2561 getStackLocked(IBinder token)2562 static ActivityStack getStackLocked(IBinder token) { 2563 final ActivityRecord r = ActivityRecord.isInStackLocked(token); 2564 if (r != null) { 2565 return r.getActivityStack(); 2566 } 2567 return null; 2568 } 2569 2570 /** 2571 * @return display id to which this record is attached, 2572 * {@link android.view.Display#INVALID_DISPLAY} if not attached. 2573 */ getDisplayId()2574 int getDisplayId() { 2575 final ActivityStack stack = getActivityStack(); 2576 if (stack == null) { 2577 return INVALID_DISPLAY; 2578 } 2579 return stack.mDisplayId; 2580 } 2581 isDestroyable()2582 final boolean isDestroyable() { 2583 if (finishing || !hasProcess()) { 2584 // This would be redundant. 2585 return false; 2586 } 2587 final ActivityStack stack = getActivityStack(); 2588 if (stack == null || this == stack.getResumedActivity() || this == stack.mPausingActivity 2589 || !haveState || !stopped) { 2590 // We're not ready for this kind of thing. 2591 return false; 2592 } 2593 if (visible) { 2594 // The user would notice this! 2595 return false; 2596 } 2597 return true; 2598 } 2599 createImageFilename(long createTime, int taskId)2600 private static String createImageFilename(long createTime, int taskId) { 2601 return String.valueOf(taskId) + ACTIVITY_ICON_SUFFIX + createTime + 2602 IMAGE_EXTENSION; 2603 } 2604 setTaskDescription(TaskDescription _taskDescription)2605 void setTaskDescription(TaskDescription _taskDescription) { 2606 Bitmap icon; 2607 if (_taskDescription.getIconFilename() == null && 2608 (icon = _taskDescription.getIcon()) != null) { 2609 final String iconFilename = createImageFilename(createTime, task.taskId); 2610 final File iconFile = new File(TaskPersister.getUserImagesDir(task.userId), 2611 iconFilename); 2612 final String iconFilePath = iconFile.getAbsolutePath(); 2613 mAtmService.getRecentTasks().saveImage(icon, iconFilePath); 2614 _taskDescription.setIconFilename(iconFilePath); 2615 } 2616 taskDescription = _taskDescription; 2617 } 2618 setVoiceSessionLocked(IVoiceInteractionSession session)2619 void setVoiceSessionLocked(IVoiceInteractionSession session) { 2620 voiceSession = session; 2621 pendingVoiceInteractionStart = false; 2622 } 2623 clearVoiceSessionLocked()2624 void clearVoiceSessionLocked() { 2625 voiceSession = null; 2626 pendingVoiceInteractionStart = false; 2627 } 2628 showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch)2629 void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch) { 2630 showStartingWindow(prev, newTask, taskSwitch, false /* fromRecents */); 2631 } 2632 showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch, boolean fromRecents)2633 void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch, 2634 boolean fromRecents) { 2635 if (mAppWindowToken == null) { 2636 return; 2637 } 2638 if (mTaskOverlay) { 2639 // We don't show starting window for overlay activities. 2640 return; 2641 } 2642 if (pendingOptions != null 2643 && pendingOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) { 2644 // Don't show starting window when using shared element transition. 2645 return; 2646 } 2647 2648 final CompatibilityInfo compatInfo = 2649 mAtmService.compatibilityInfoForPackageLocked(info.applicationInfo); 2650 final boolean shown = addStartingWindow(packageName, theme, 2651 compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags, 2652 prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning(), 2653 allowTaskSnapshot(), 2654 mState.ordinal() >= RESUMED.ordinal() && mState.ordinal() <= STOPPED.ordinal(), 2655 fromRecents); 2656 if (shown) { 2657 mStartingWindowState = STARTING_WINDOW_SHOWN; 2658 } 2659 } 2660 removeOrphanedStartingWindow(boolean behindFullscreenActivity)2661 void removeOrphanedStartingWindow(boolean behindFullscreenActivity) { 2662 if (mStartingWindowState == STARTING_WINDOW_SHOWN && behindFullscreenActivity) { 2663 if (DEBUG_VISIBILITY) Slog.w(TAG_VISIBILITY, "Found orphaned starting window " + this); 2664 mStartingWindowState = STARTING_WINDOW_REMOVED; 2665 mAppWindowToken.removeStartingWindow(); 2666 } 2667 } 2668 setRequestedOrientation(int requestedOrientation)2669 void setRequestedOrientation(int requestedOrientation) { 2670 setOrientation(requestedOrientation, mayFreezeScreenLocked(app)); 2671 mAtmService.getTaskChangeNotificationController().notifyActivityRequestedOrientationChanged( 2672 task.taskId, requestedOrientation); 2673 } 2674 setOrientation(int requestedOrientation, boolean freezeScreenIfNeeded)2675 private void setOrientation(int requestedOrientation, boolean freezeScreenIfNeeded) { 2676 if (mAppWindowToken == null) { 2677 Slog.w(TAG_WM, 2678 "Attempted to set orientation of non-existing app token: " + appToken); 2679 return; 2680 } 2681 2682 final IBinder binder = 2683 (freezeScreenIfNeeded && appToken != null) ? appToken.asBinder() : null; 2684 mAppWindowToken.setOrientation(requestedOrientation, binder, this); 2685 2686 // Push the new configuration to the requested app in case where it's not pushed, e.g. when 2687 // the request is handled at task level with letterbox. 2688 if (!getMergedOverrideConfiguration().equals( 2689 mLastReportedConfiguration.getMergedConfiguration())) { 2690 ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */); 2691 } 2692 } 2693 getOrientation()2694 int getOrientation() { 2695 if (mAppWindowToken == null) { 2696 return info.screenOrientation; 2697 } 2698 2699 return mAppWindowToken.getOrientationIgnoreVisibility(); 2700 } 2701 setDisablePreviewScreenshots(boolean disable)2702 void setDisablePreviewScreenshots(boolean disable) { 2703 if (mAppWindowToken == null) { 2704 Slog.w(TAG_WM, "Attempted to set disable screenshots of non-existing app" 2705 + " token: " + appToken); 2706 return; 2707 } 2708 mAppWindowToken.setDisablePreviewScreenshots(disable); 2709 } 2710 2711 /** 2712 * Set the last reported global configuration to the client. Should be called whenever a new 2713 * global configuration is sent to the client for this activity. 2714 */ setLastReportedGlobalConfiguration(@onNull Configuration config)2715 void setLastReportedGlobalConfiguration(@NonNull Configuration config) { 2716 mLastReportedConfiguration.setGlobalConfiguration(config); 2717 } 2718 2719 /** 2720 * Set the last reported configuration to the client. Should be called whenever 2721 * a new merged configuration is sent to the client for this activity. 2722 */ setLastReportedConfiguration(@onNull MergedConfiguration config)2723 void setLastReportedConfiguration(@NonNull MergedConfiguration config) { 2724 setLastReportedConfiguration(config.getGlobalConfiguration(), 2725 config.getOverrideConfiguration()); 2726 } 2727 setLastReportedConfiguration(Configuration global, Configuration override)2728 private void setLastReportedConfiguration(Configuration global, Configuration override) { 2729 mLastReportedConfiguration.setConfiguration(global, override); 2730 } 2731 2732 /** 2733 * Get the configuration orientation by the requested screen orientation 2734 * ({@link ActivityInfo.ScreenOrientation}) of this activity. 2735 * 2736 * @return orientation in ({@link Configuration#ORIENTATION_LANDSCAPE}, 2737 * {@link Configuration#ORIENTATION_PORTRAIT}, 2738 * {@link Configuration#ORIENTATION_UNDEFINED}). 2739 */ getRequestedConfigurationOrientation()2740 int getRequestedConfigurationOrientation() { 2741 final int screenOrientation = getOrientation(); 2742 if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_NOSENSOR) { 2743 // NOSENSOR means the display's "natural" orientation, so return that. 2744 final ActivityDisplay display = getDisplay(); 2745 if (display != null && display.mDisplayContent != null) { 2746 return display.mDisplayContent.getNaturalOrientation(); 2747 } 2748 } else if (screenOrientation == ActivityInfo.SCREEN_ORIENTATION_LOCKED) { 2749 // LOCKED means the activity's orientation remains unchanged, so return existing value. 2750 return getConfiguration().orientation; 2751 } else if (isFixedOrientationLandscape(screenOrientation)) { 2752 return ORIENTATION_LANDSCAPE; 2753 } else if (isFixedOrientationPortrait(screenOrientation)) { 2754 return ORIENTATION_PORTRAIT; 2755 } 2756 return ORIENTATION_UNDEFINED; 2757 } 2758 2759 /** 2760 * @return {@code true} if this activity is in size compatibility mode that uses the different 2761 * density or bounds from its parent. 2762 */ inSizeCompatMode()2763 boolean inSizeCompatMode() { 2764 if (!shouldUseSizeCompatMode()) { 2765 return false; 2766 } 2767 final Configuration resolvedConfig = getResolvedOverrideConfiguration(); 2768 final Rect resolvedAppBounds = resolvedConfig.windowConfiguration.getAppBounds(); 2769 if (resolvedAppBounds == null) { 2770 // The override configuration has not been resolved yet. 2771 return false; 2772 } 2773 2774 final Configuration parentConfig = getParent().getConfiguration(); 2775 // Although colorMode, screenLayout, smallestScreenWidthDp are also fixed, generally these 2776 // fields should be changed with density and bounds, so here only compares the most 2777 // significant field. 2778 if (parentConfig.densityDpi != resolvedConfig.densityDpi) { 2779 return true; 2780 } 2781 2782 final Rect parentAppBounds = parentConfig.windowConfiguration.getAppBounds(); 2783 final int appWidth = resolvedAppBounds.width(); 2784 final int appHeight = resolvedAppBounds.height(); 2785 final int parentAppWidth = parentAppBounds.width(); 2786 final int parentAppHeight = parentAppBounds.height(); 2787 if (parentAppWidth == appWidth && parentAppHeight == appHeight) { 2788 // Matched the parent bounds. 2789 return false; 2790 } 2791 if (parentAppWidth > appWidth && parentAppHeight > appHeight) { 2792 // Both sides are smaller than the parent. 2793 return true; 2794 } 2795 if (parentAppWidth < appWidth || parentAppHeight < appHeight) { 2796 // One side is larger than the parent. 2797 return true; 2798 } 2799 2800 // The rest of the condition is that only one side is smaller than the parent, but it still 2801 // needs to exclude the cases where the size is limited by the fixed aspect ratio. 2802 if (info.maxAspectRatio > 0) { 2803 final float aspectRatio = (0.5f + Math.max(appWidth, appHeight)) 2804 / Math.min(appWidth, appHeight); 2805 if (aspectRatio >= info.maxAspectRatio) { 2806 // The current size has reached the max aspect ratio. 2807 return false; 2808 } 2809 } 2810 if (info.minAspectRatio > 0) { 2811 // The activity should have at least the min aspect ratio, so this checks if the parent 2812 // still has available space to provide larger aspect ratio. 2813 final float parentAspectRatio = (0.5f + Math.max(parentAppWidth, parentAppHeight)) 2814 / Math.min(parentAppWidth, parentAppHeight); 2815 if (parentAspectRatio <= info.minAspectRatio) { 2816 // The long side has reached the parent. 2817 return false; 2818 } 2819 } 2820 return true; 2821 } 2822 2823 /** 2824 * Indicates the activity will keep the bounds and screen configuration when it was first 2825 * launched, no matter how its parent changes. 2826 * 2827 * @return {@code true} if this activity is declared as non-resizable and fixed orientation or 2828 * aspect ratio. 2829 */ shouldUseSizeCompatMode()2830 boolean shouldUseSizeCompatMode() { 2831 return !isResizeable() && (info.isFixedOrientation() || info.hasFixedAspectRatio()) 2832 // The configuration of non-standard type should be enforced by system. 2833 && isActivityTypeStandard() 2834 && !mAtmService.mForceResizableActivities; 2835 } 2836 2837 // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer. updateOverrideConfiguration()2838 private void updateOverrideConfiguration() { 2839 final Configuration overrideConfig = mTmpConfig; 2840 if (shouldUseSizeCompatMode()) { 2841 if (mCompatDisplayInsets != null) { 2842 // The override configuration is set only once in size compatibility mode. 2843 return; 2844 } 2845 final Configuration parentConfig = getParent().getConfiguration(); 2846 if (!hasProcess() && !isConfigurationCompatible(parentConfig)) { 2847 // Don't compute when launching in fullscreen and the fixed orientation is not the 2848 // current orientation. It is more accurately to compute the override bounds from 2849 // the updated configuration after the fixed orientation is applied. 2850 return; 2851 } 2852 2853 // Ensure the screen related fields are set. It is used to prevent activity relaunch 2854 // when moving between displays. For screenWidthDp and screenWidthDp, because they 2855 // are relative to bounds and density, they will be calculated in 2856 // {@link TaskRecord#computeConfigResourceOverrides} and the result will also be 2857 // relatively fixed. 2858 overrideConfig.unset(); 2859 overrideConfig.colorMode = parentConfig.colorMode; 2860 overrideConfig.densityDpi = parentConfig.densityDpi; 2861 overrideConfig.screenLayout = parentConfig.screenLayout 2862 & (Configuration.SCREENLAYOUT_LONG_MASK 2863 | Configuration.SCREENLAYOUT_SIZE_MASK); 2864 // The smallest screen width is the short side of screen bounds. Because the bounds 2865 // and density won't be changed, smallestScreenWidthDp is also fixed. 2866 overrideConfig.smallestScreenWidthDp = parentConfig.smallestScreenWidthDp; 2867 2868 // The role of CompatDisplayInsets is like the override bounds. 2869 final ActivityDisplay display = getDisplay(); 2870 if (display != null && display.mDisplayContent != null) { 2871 mCompatDisplayInsets = new CompatDisplayInsets(display.mDisplayContent); 2872 } 2873 } else { 2874 // We must base this on the parent configuration, because we set our override 2875 // configuration's appBounds based on the result of this method. If we used our own 2876 // configuration, it would be influenced by past invocations. 2877 computeBounds(mTmpBounds, getParent().getWindowConfiguration().getAppBounds()); 2878 2879 if (mTmpBounds.equals(getRequestedOverrideBounds())) { 2880 // The bounds is not changed or the activity is resizable (both the 2 bounds are 2881 // empty). 2882 return; 2883 } 2884 2885 overrideConfig.unset(); 2886 overrideConfig.windowConfiguration.setBounds(mTmpBounds); 2887 } 2888 2889 onRequestedOverrideConfigurationChanged(overrideConfig); 2890 } 2891 2892 @Override resolveOverrideConfiguration(Configuration newParentConfiguration)2893 void resolveOverrideConfiguration(Configuration newParentConfiguration) { 2894 if (mCompatDisplayInsets != null) { 2895 resolveSizeCompatModeConfiguration(newParentConfiguration); 2896 } else { 2897 super.resolveOverrideConfiguration(newParentConfiguration); 2898 // If the activity has override bounds, the relative configuration (e.g. screen size, 2899 // layout) needs to be resolved according to the bounds. 2900 if (!matchParentBounds()) { 2901 task.computeConfigResourceOverrides(getResolvedOverrideConfiguration(), 2902 newParentConfiguration); 2903 } 2904 } 2905 2906 // Assign configuration sequence number into hierarchy because there is a different way than 2907 // ensureActivityConfiguration() in this class that uses configuration in WindowState during 2908 // layout traversals. 2909 mConfigurationSeq = Math.max(++mConfigurationSeq, 1); 2910 getResolvedOverrideConfiguration().seq = mConfigurationSeq; 2911 } 2912 2913 /** 2914 * Resolves consistent screen configuration for orientation and rotation changes without 2915 * inheriting the parent bounds. 2916 */ resolveSizeCompatModeConfiguration(Configuration newParentConfiguration)2917 private void resolveSizeCompatModeConfiguration(Configuration newParentConfiguration) { 2918 final Configuration resolvedConfig = getResolvedOverrideConfiguration(); 2919 final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds(); 2920 2921 final int parentRotation = newParentConfiguration.windowConfiguration.getRotation(); 2922 final int parentOrientation = newParentConfiguration.orientation; 2923 int orientation = getConfiguration().orientation; 2924 if (orientation != parentOrientation && isConfigurationCompatible(newParentConfiguration)) { 2925 // The activity is compatible to apply the orientation change or it requests different 2926 // fixed orientation. 2927 orientation = parentOrientation; 2928 } else { 2929 if (!resolvedBounds.isEmpty() 2930 // The decor insets may be different according to the rotation. 2931 && getWindowConfiguration().getRotation() == parentRotation) { 2932 // Keep the computed resolved override configuration. 2933 return; 2934 } 2935 final int requestedOrientation = getRequestedConfigurationOrientation(); 2936 if (requestedOrientation != ORIENTATION_UNDEFINED) { 2937 orientation = requestedOrientation; 2938 } 2939 } 2940 2941 super.resolveOverrideConfiguration(newParentConfiguration); 2942 2943 boolean useParentOverrideBounds = false; 2944 final Rect displayBounds = mTmpBounds; 2945 final Rect containingAppBounds = new Rect(); 2946 if (task.handlesOrientationChangeFromDescendant()) { 2947 // Prefer to use the orientation which is determined by this activity to calculate 2948 // bounds because the parent will follow the requested orientation. 2949 mCompatDisplayInsets.getDisplayBoundsByOrientation(displayBounds, orientation); 2950 } else { 2951 // The parent hierarchy doesn't handle the orientation changes. This is usually because 2952 // the aspect ratio of display is close to square or the display rotation is fixed. 2953 // In this case, task will compute override bounds to fit the app with respect to the 2954 // requested orientation. So here we perform similar calculation to have consistent 2955 // bounds even the original parent hierarchies were changed. 2956 final int baseOrientation = task.getParent().getConfiguration().orientation; 2957 mCompatDisplayInsets.getDisplayBoundsByOrientation(displayBounds, baseOrientation); 2958 task.computeFullscreenBounds(containingAppBounds, this, displayBounds, baseOrientation); 2959 useParentOverrideBounds = !containingAppBounds.isEmpty(); 2960 } 2961 2962 // The offsets will be non-zero if the parent has override bounds. 2963 final int containingOffsetX = containingAppBounds.left; 2964 final int containingOffsetY = containingAppBounds.top; 2965 if (!useParentOverrideBounds) { 2966 containingAppBounds.set(displayBounds); 2967 } 2968 if (parentRotation != ROTATION_UNDEFINED) { 2969 // Ensure the container bounds won't overlap with the decors. 2970 TaskRecord.intersectWithInsetsIfFits(containingAppBounds, displayBounds, 2971 mCompatDisplayInsets.mNonDecorInsets[parentRotation]); 2972 } 2973 2974 computeBounds(resolvedBounds, containingAppBounds); 2975 if (resolvedBounds.isEmpty()) { 2976 // Use the entire available bounds because there is no restriction. 2977 resolvedBounds.set(useParentOverrideBounds ? containingAppBounds : displayBounds); 2978 } else { 2979 // The offsets are included in width and height by {@link #computeBounds}, so we have to 2980 // restore it. 2981 resolvedBounds.left += containingOffsetX; 2982 resolvedBounds.top += containingOffsetY; 2983 } 2984 task.computeConfigResourceOverrides(resolvedConfig, newParentConfiguration, 2985 mCompatDisplayInsets); 2986 2987 // The horizontal inset included in width is not needed if the activity cannot fill the 2988 // parent, because the offset will be applied by {@link AppWindowToken#mSizeCompatBounds}. 2989 final Rect resolvedAppBounds = resolvedConfig.windowConfiguration.getAppBounds(); 2990 final Rect parentAppBounds = newParentConfiguration.windowConfiguration.getAppBounds(); 2991 if (resolvedBounds.width() < parentAppBounds.width()) { 2992 resolvedBounds.right -= resolvedAppBounds.left; 2993 } 2994 // Use parent orientation if it cannot be decided by bounds, so the activity can fit inside 2995 // the parent bounds appropriately. 2996 if (resolvedConfig.screenWidthDp == resolvedConfig.screenHeightDp) { 2997 resolvedConfig.orientation = newParentConfiguration.orientation; 2998 } 2999 } 3000 3001 @Override onConfigurationChanged(Configuration newParentConfig)3002 public void onConfigurationChanged(Configuration newParentConfig) { 3003 super.onConfigurationChanged(newParentConfig); 3004 3005 // Configuration's equality doesn't consider seq so if only seq number changes in resolved 3006 // override configuration. Therefore ConfigurationContainer doesn't change merged override 3007 // configuration, but it's used to push configuration changes so explicitly update that. 3008 if (getMergedOverrideConfiguration().seq != getResolvedOverrideConfiguration().seq) { 3009 onMergedOverrideConfigurationChanged(); 3010 } 3011 3012 // TODO(b/80414790): Remove code below after unification. 3013 // Same as above it doesn't notify configuration listeners, and consequently AppWindowToken 3014 // can't get updated seq number. However WindowState's merged override configuration needs 3015 // to have this seq number because that's also used for activity config pushes during layout 3016 // traversal. Therefore explicitly update them here. 3017 if (mAppWindowToken == null) { 3018 return; 3019 } 3020 final Configuration appWindowTokenRequestedOverrideConfig = 3021 mAppWindowToken.getRequestedOverrideConfiguration(); 3022 if (appWindowTokenRequestedOverrideConfig.seq != getResolvedOverrideConfiguration().seq) { 3023 appWindowTokenRequestedOverrideConfig.seq = 3024 getResolvedOverrideConfiguration().seq; 3025 mAppWindowToken.onMergedOverrideConfigurationChanged(); 3026 } 3027 3028 final ActivityDisplay display = getDisplay(); 3029 if (display == null) { 3030 return; 3031 } 3032 if (visible) { 3033 // It may toggle the UI for user to restart the size compatibility mode activity. 3034 display.handleActivitySizeCompatModeIfNeeded(this); 3035 } else if (shouldUseSizeCompatMode()) { 3036 // The override changes can only be obtained from display, because we don't have the 3037 // difference of full configuration in each hierarchy. 3038 final int displayChanges = display.getLastOverrideConfigurationChanges(); 3039 final int orientationChanges = CONFIG_WINDOW_CONFIGURATION 3040 | CONFIG_SCREEN_SIZE | CONFIG_ORIENTATION; 3041 final boolean hasNonOrienSizeChanged = hasResizeChange(displayChanges) 3042 // Filter out the case of simple orientation change. 3043 && (displayChanges & orientationChanges) != orientationChanges; 3044 // For background activity that uses size compatibility mode, if the size or density of 3045 // the display is changed, then reset the override configuration and kill the activity's 3046 // process if its process state is not important to user. 3047 if (hasNonOrienSizeChanged || (displayChanges & ActivityInfo.CONFIG_DENSITY) != 0) { 3048 restartProcessIfVisible(); 3049 } 3050 } 3051 } 3052 3053 /** Returns true if the configuration is compatible with this activity. */ isConfigurationCompatible(Configuration config)3054 boolean isConfigurationCompatible(Configuration config) { 3055 final int orientation = getOrientation(); 3056 if (isFixedOrientationPortrait(orientation) 3057 && config.orientation != ORIENTATION_PORTRAIT) { 3058 return false; 3059 } 3060 if (isFixedOrientationLandscape(orientation) 3061 && config.orientation != ORIENTATION_LANDSCAPE) { 3062 return false; 3063 } 3064 return true; 3065 } 3066 3067 /** 3068 * Computes the bounds to fit the Activity within the bounds of the {@link Configuration}. 3069 */ 3070 // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer. computeBounds(Rect outBounds, Rect containingAppBounds)3071 private void computeBounds(Rect outBounds, Rect containingAppBounds) { 3072 outBounds.setEmpty(); 3073 final float maxAspectRatio = info.maxAspectRatio; 3074 final ActivityStack stack = getActivityStack(); 3075 final float minAspectRatio = info.minAspectRatio; 3076 3077 if (task == null || stack == null || task.inMultiWindowMode() 3078 || (maxAspectRatio == 0 && minAspectRatio == 0) 3079 || isInVrUiMode(getConfiguration())) { 3080 // We don't set override configuration if that activity task isn't fullscreen. I.e. the 3081 // activity is in multi-window mode. Or, there isn't a max aspect ratio specified for 3082 // the activity. This is indicated by an empty {@link outBounds}. We also don't set it 3083 // if we are in VR mode. 3084 return; 3085 } 3086 3087 final int containingAppWidth = containingAppBounds.width(); 3088 final int containingAppHeight = containingAppBounds.height(); 3089 final float containingRatio = Math.max(containingAppWidth, containingAppHeight) 3090 / (float) Math.min(containingAppWidth, containingAppHeight); 3091 3092 int activityWidth = containingAppWidth; 3093 int activityHeight = containingAppHeight; 3094 3095 if (containingRatio > maxAspectRatio && maxAspectRatio != 0) { 3096 if (containingAppWidth < containingAppHeight) { 3097 // Width is the shorter side, so we use that to figure-out what the max. height 3098 // should be given the aspect ratio. 3099 activityHeight = (int) ((activityWidth * maxAspectRatio) + 0.5f); 3100 } else { 3101 // Height is the shorter side, so we use that to figure-out what the max. width 3102 // should be given the aspect ratio. 3103 activityWidth = (int) ((activityHeight * maxAspectRatio) + 0.5f); 3104 } 3105 } else if (containingRatio < minAspectRatio) { 3106 boolean adjustWidth; 3107 switch (getRequestedConfigurationOrientation()) { 3108 case ORIENTATION_LANDSCAPE: 3109 // Width should be the longer side for this landscape app, so we use the width 3110 // to figure-out what the max. height should be given the aspect ratio. 3111 adjustWidth = false; 3112 break; 3113 case ORIENTATION_PORTRAIT: 3114 // Height should be the longer side for this portrait app, so we use the height 3115 // to figure-out what the max. width should be given the aspect ratio. 3116 adjustWidth = true; 3117 break; 3118 default: 3119 // This app doesn't have a preferred orientation, so we keep the length of the 3120 // longer side, and use it to figure-out the length of the shorter side. 3121 if (containingAppWidth < containingAppHeight) { 3122 // Width is the shorter side, so we use the height to figure-out what the 3123 // max. width should be given the aspect ratio. 3124 adjustWidth = true; 3125 } else { 3126 // Height is the shorter side, so we use the width to figure-out what the 3127 // max. height should be given the aspect ratio. 3128 adjustWidth = false; 3129 } 3130 break; 3131 } 3132 if (adjustWidth) { 3133 activityWidth = (int) ((activityHeight / minAspectRatio) + 0.5f); 3134 } else { 3135 activityHeight = (int) ((activityWidth / minAspectRatio) + 0.5f); 3136 } 3137 } 3138 3139 if (containingAppWidth <= activityWidth && containingAppHeight <= activityHeight) { 3140 // The display matches or is less than the activity aspect ratio, so nothing else to do. 3141 // Return the existing bounds. If this method is running for the first time, 3142 // {@link #getRequestedOverrideBounds()} will be empty (representing no override). If 3143 // the method has run before, then effect of {@link #getRequestedOverrideBounds()} will 3144 // already have been applied to the value returned from {@link getConfiguration}. Refer 3145 // to {@link TaskRecord#computeConfigResourceOverrides()}. 3146 outBounds.set(getRequestedOverrideBounds()); 3147 return; 3148 } 3149 3150 // Compute configuration based on max supported width and height. 3151 // Also account for the left / top insets (e.g. from display cutouts), which will be clipped 3152 // away later in {@link TaskRecord#computeConfigResourceOverrides()}. Otherwise, the app 3153 // bounds would end up too small. 3154 outBounds.set(0, 0, activityWidth + containingAppBounds.left, 3155 activityHeight + containingAppBounds.top); 3156 } 3157 3158 /** 3159 * @return {@code true} if this activity was reparented to another display but 3160 * {@link #ensureActivityConfiguration} is not called. 3161 */ shouldUpdateConfigForDisplayChanged()3162 boolean shouldUpdateConfigForDisplayChanged() { 3163 return mLastReportedDisplayId != getDisplayId(); 3164 } 3165 ensureActivityConfiguration(int globalChanges, boolean preserveWindow)3166 boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow) { 3167 return ensureActivityConfiguration(globalChanges, preserveWindow, 3168 false /* ignoreStopState */); 3169 } 3170 3171 /** 3172 * Make sure the given activity matches the current configuration. Ensures the HistoryRecord 3173 * is updated with the correct configuration and all other bookkeeping is handled. 3174 * 3175 * @param globalChanges The changes to the global configuration. 3176 * @param preserveWindow If the activity window should be preserved on screen if the activity 3177 * is relaunched. 3178 * @param ignoreStopState If we should try to relaunch the activity even if it is in the stopped 3179 * state. This is useful for the case where we know the activity will be 3180 * visible soon and we want to ensure its configuration before we make it 3181 * visible. 3182 * @return False if the activity was relaunched and true if it wasn't relaunched because we 3183 * can't or the app handles the specific configuration that is changing. 3184 */ ensureActivityConfiguration(int globalChanges, boolean preserveWindow, boolean ignoreStopState)3185 boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow, 3186 boolean ignoreStopState) { 3187 final ActivityStack stack = getActivityStack(); 3188 if (stack.mConfigWillChange) { 3189 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, 3190 "Skipping config check (will change): " + this); 3191 return true; 3192 } 3193 3194 // We don't worry about activities that are finishing. 3195 if (finishing) { 3196 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, 3197 "Configuration doesn't matter in finishing " + this); 3198 stopFreezingScreenLocked(false); 3199 return true; 3200 } 3201 3202 if (!ignoreStopState && (mState == STOPPING || mState == STOPPED)) { 3203 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, 3204 "Skipping config check stopped or stopping: " + this); 3205 return true; 3206 } 3207 3208 if (!shouldBeVisible()) { 3209 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, 3210 "Skipping config check invisible stack: " + this); 3211 return true; 3212 } 3213 3214 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, 3215 "Ensuring correct configuration: " + this); 3216 3217 final int newDisplayId = getDisplayId(); 3218 final boolean displayChanged = mLastReportedDisplayId != newDisplayId; 3219 if (displayChanged) { 3220 mLastReportedDisplayId = newDisplayId; 3221 } 3222 // TODO(b/36505427): Is there a better place to do this? 3223 updateOverrideConfiguration(); 3224 3225 // Short circuit: if the two full configurations are equal (the common case), then there is 3226 // nothing to do. We test the full configuration instead of the global and merged override 3227 // configurations because there are cases (like moving a task to the pinned stack) where 3228 // the combine configurations are equal, but would otherwise differ in the override config 3229 mTmpConfig.setTo(mLastReportedConfiguration.getMergedConfiguration()); 3230 if (getConfiguration().equals(mTmpConfig) && !forceNewConfig && !displayChanged) { 3231 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, 3232 "Configuration & display unchanged in " + this); 3233 return true; 3234 } 3235 3236 // Okay we now are going to make this activity have the new config. 3237 // But then we need to figure out how it needs to deal with that. 3238 3239 // Find changes between last reported merged configuration and the current one. This is used 3240 // to decide whether to relaunch an activity or just report a configuration change. 3241 final int changes = getConfigurationChanges(mTmpConfig); 3242 3243 // Update last reported values. 3244 final Configuration newMergedOverrideConfig = getMergedOverrideConfiguration(); 3245 3246 setLastReportedConfiguration(mAtmService.getGlobalConfiguration(), newMergedOverrideConfig); 3247 3248 if (mState == INITIALIZING) { 3249 // No need to relaunch or schedule new config for activity that hasn't been launched 3250 // yet. We do, however, return after applying the config to activity record, so that 3251 // it will use it for launch transaction. 3252 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, 3253 "Skipping config check for initializing activity: " + this); 3254 return true; 3255 } 3256 3257 if (changes == 0 && !forceNewConfig) { 3258 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, 3259 "Configuration no differences in " + this); 3260 // There are no significant differences, so we won't relaunch but should still deliver 3261 // the new configuration to the client process. 3262 if (displayChanged) { 3263 scheduleActivityMovedToDisplay(newDisplayId, newMergedOverrideConfig); 3264 } else { 3265 scheduleConfigurationChanged(newMergedOverrideConfig); 3266 } 3267 return true; 3268 } 3269 3270 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, 3271 "Configuration changes for " + this + ", allChanges=" 3272 + Configuration.configurationDiffToString(changes)); 3273 3274 // If the activity isn't currently running, just leave the new configuration and it will 3275 // pick that up next time it starts. 3276 if (!attachedToProcess()) { 3277 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, 3278 "Configuration doesn't matter not running " + this); 3279 stopFreezingScreenLocked(false); 3280 forceNewConfig = false; 3281 return true; 3282 } 3283 3284 // Figure out how to handle the changes between the configurations. 3285 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, 3286 "Checking to restart " + info.name + ": changed=0x" 3287 + Integer.toHexString(changes) + ", handles=0x" 3288 + Integer.toHexString(info.getRealConfigChanged()) 3289 + ", mLastReportedConfiguration=" + mLastReportedConfiguration); 3290 3291 if (shouldRelaunchLocked(changes, mTmpConfig) || forceNewConfig) { 3292 // Aha, the activity isn't handling the change, so DIE DIE DIE. 3293 configChangeFlags |= changes; 3294 startFreezingScreenLocked(app, globalChanges); 3295 forceNewConfig = false; 3296 preserveWindow &= isResizeOnlyChange(changes); 3297 final boolean hasResizeChange = hasResizeChange(changes & ~info.getRealConfigChanged()); 3298 if (hasResizeChange) { 3299 final boolean isDragResizing = 3300 getTaskRecord().getTask().isDragResizing(); 3301 mRelaunchReason = isDragResizing ? RELAUNCH_REASON_FREE_RESIZE 3302 : RELAUNCH_REASON_WINDOWING_MODE_RESIZE; 3303 } else { 3304 mRelaunchReason = RELAUNCH_REASON_NONE; 3305 } 3306 if (!attachedToProcess()) { 3307 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, 3308 "Config is destroying non-running " + this); 3309 stack.destroyActivityLocked(this, true, "config"); 3310 } else if (mState == PAUSING) { 3311 // A little annoying: we are waiting for this activity to finish pausing. Let's not 3312 // do anything now, but just flag that it needs to be restarted when done pausing. 3313 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, 3314 "Config is skipping already pausing " + this); 3315 deferRelaunchUntilPaused = true; 3316 preserveWindowOnDeferredRelaunch = preserveWindow; 3317 return true; 3318 } else if (mState == RESUMED) { 3319 // Try to optimize this case: the configuration is changing and we need to restart 3320 // the top, resumed activity. Instead of doing the normal handshaking, just say 3321 // "restart!". 3322 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, 3323 "Config is relaunching resumed " + this); 3324 3325 if (DEBUG_STATES && !visible) { 3326 Slog.v(TAG_STATES, "Config is relaunching resumed invisible activity " + this 3327 + " called by " + Debug.getCallers(4)); 3328 } 3329 3330 relaunchActivityLocked(true /* andResume */, preserveWindow); 3331 } else { 3332 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, 3333 "Config is relaunching non-resumed " + this); 3334 relaunchActivityLocked(false /* andResume */, preserveWindow); 3335 } 3336 3337 // All done... tell the caller we weren't able to keep this activity around. 3338 return false; 3339 } 3340 3341 // Default case: the activity can handle this new configuration, so hand it over. 3342 // NOTE: We only forward the override configuration as the system level configuration 3343 // changes is always sent to all processes when they happen so it can just use whatever 3344 // system level configuration it last got. 3345 if (displayChanged) { 3346 scheduleActivityMovedToDisplay(newDisplayId, newMergedOverrideConfig); 3347 } else { 3348 scheduleConfigurationChanged(newMergedOverrideConfig); 3349 } 3350 stopFreezingScreenLocked(false); 3351 3352 return true; 3353 } 3354 3355 /** 3356 * When assessing a configuration change, decide if the changes flags and the new configurations 3357 * should cause the Activity to relaunch. 3358 * 3359 * @param changes the changes due to the given configuration. 3360 * @param changesConfig the configuration that was used to calculate the given changes via a 3361 * call to getConfigurationChanges. 3362 */ shouldRelaunchLocked(int changes, Configuration changesConfig)3363 private boolean shouldRelaunchLocked(int changes, Configuration changesConfig) { 3364 int configChanged = info.getRealConfigChanged(); 3365 boolean onlyVrUiModeChanged = onlyVrUiModeChanged(changes, changesConfig); 3366 3367 // Override for apps targeting pre-O sdks 3368 // If a device is in VR mode, and we're transitioning into VR ui mode, add ignore ui mode 3369 // to the config change. 3370 // For O and later, apps will be required to add configChanges="uimode" to their manifest. 3371 if (appInfo.targetSdkVersion < O 3372 && requestedVrComponent != null 3373 && onlyVrUiModeChanged) { 3374 configChanged |= CONFIG_UI_MODE; 3375 } 3376 3377 return (changes&(~configChanged)) != 0; 3378 } 3379 3380 /** 3381 * Returns true if the configuration change is solely due to the UI mode switching into or out 3382 * of UI_MODE_TYPE_VR_HEADSET. 3383 */ onlyVrUiModeChanged(int changes, Configuration lastReportedConfig)3384 private boolean onlyVrUiModeChanged(int changes, Configuration lastReportedConfig) { 3385 final Configuration currentConfig = getConfiguration(); 3386 return changes == CONFIG_UI_MODE && (isInVrUiMode(currentConfig) 3387 != isInVrUiMode(lastReportedConfig)); 3388 } 3389 getConfigurationChanges(Configuration lastReportedConfig)3390 private int getConfigurationChanges(Configuration lastReportedConfig) { 3391 // Determine what has changed. May be nothing, if this is a config that has come back from 3392 // the app after going idle. In that case we just want to leave the official config object 3393 // now in the activity and do nothing else. 3394 final Configuration currentConfig = getConfiguration(); 3395 int changes = lastReportedConfig.diff(currentConfig); 3396 // We don't want to use size changes if they don't cross boundaries that are important to 3397 // the app. 3398 if ((changes & CONFIG_SCREEN_SIZE) != 0) { 3399 final boolean crosses = crossesHorizontalSizeThreshold(lastReportedConfig.screenWidthDp, 3400 currentConfig.screenWidthDp) 3401 || crossesVerticalSizeThreshold(lastReportedConfig.screenHeightDp, 3402 currentConfig.screenHeightDp); 3403 if (!crosses) { 3404 changes &= ~CONFIG_SCREEN_SIZE; 3405 } 3406 } 3407 if ((changes & CONFIG_SMALLEST_SCREEN_SIZE) != 0) { 3408 final int oldSmallest = lastReportedConfig.smallestScreenWidthDp; 3409 final int newSmallest = currentConfig.smallestScreenWidthDp; 3410 if (!crossesSmallestSizeThreshold(oldSmallest, newSmallest)) { 3411 changes &= ~CONFIG_SMALLEST_SCREEN_SIZE; 3412 } 3413 } 3414 // We don't want window configuration to cause relaunches. 3415 if ((changes & CONFIG_WINDOW_CONFIGURATION) != 0) { 3416 changes &= ~CONFIG_WINDOW_CONFIGURATION; 3417 } 3418 3419 return changes; 3420 } 3421 isResizeOnlyChange(int change)3422 private static boolean isResizeOnlyChange(int change) { 3423 return (change & ~(CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE | CONFIG_ORIENTATION 3424 | CONFIG_SCREEN_LAYOUT)) == 0; 3425 } 3426 hasResizeChange(int change)3427 private static boolean hasResizeChange(int change) { 3428 return (change & (CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE | CONFIG_ORIENTATION 3429 | CONFIG_SCREEN_LAYOUT)) != 0; 3430 } 3431 relaunchActivityLocked(boolean andResume, boolean preserveWindow)3432 void relaunchActivityLocked(boolean andResume, boolean preserveWindow) { 3433 if (mAtmService.mSuppressResizeConfigChanges && preserveWindow) { 3434 configChangeFlags = 0; 3435 return; 3436 } 3437 3438 List<ResultInfo> pendingResults = null; 3439 List<ReferrerIntent> pendingNewIntents = null; 3440 if (andResume) { 3441 pendingResults = results; 3442 pendingNewIntents = newIntents; 3443 } 3444 if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, 3445 "Relaunching: " + this + " with results=" + pendingResults 3446 + " newIntents=" + pendingNewIntents + " andResume=" + andResume 3447 + " preserveWindow=" + preserveWindow); 3448 EventLog.writeEvent(andResume ? AM_RELAUNCH_RESUME_ACTIVITY 3449 : AM_RELAUNCH_ACTIVITY, mUserId, System.identityHashCode(this), 3450 task.taskId, shortComponentName); 3451 3452 startFreezingScreenLocked(app, 0); 3453 3454 try { 3455 if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH, 3456 "Moving to " + (andResume ? "RESUMED" : "PAUSED") + " Relaunching " + this 3457 + " callers=" + Debug.getCallers(6)); 3458 forceNewConfig = false; 3459 mStackSupervisor.activityRelaunchingLocked(this); 3460 final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(pendingResults, 3461 pendingNewIntents, configChangeFlags, 3462 new MergedConfiguration(mAtmService.getGlobalConfiguration(), 3463 getMergedOverrideConfiguration()), 3464 preserveWindow); 3465 final ActivityLifecycleItem lifecycleItem; 3466 if (andResume) { 3467 lifecycleItem = ResumeActivityItem.obtain( 3468 getDisplay().mDisplayContent.isNextTransitionForward()); 3469 } else { 3470 lifecycleItem = PauseActivityItem.obtain(); 3471 } 3472 final ClientTransaction transaction = ClientTransaction.obtain(app.getThread(), appToken); 3473 transaction.addCallback(callbackItem); 3474 transaction.setLifecycleStateRequest(lifecycleItem); 3475 mAtmService.getLifecycleManager().scheduleTransaction(transaction); 3476 // Note: don't need to call pauseIfSleepingLocked() here, because the caller will only 3477 // request resume if this activity is currently resumed, which implies we aren't 3478 // sleeping. 3479 } catch (RemoteException e) { 3480 if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH, "Relaunch failed", e); 3481 } 3482 3483 if (andResume) { 3484 if (DEBUG_STATES) { 3485 Slog.d(TAG_STATES, "Resumed after relaunch " + this); 3486 } 3487 results = null; 3488 newIntents = null; 3489 mAtmService.getAppWarningsLocked().onResumeActivity(this); 3490 } else { 3491 final ActivityStack stack = getActivityStack(); 3492 if (stack != null) { 3493 stack.mHandler.removeMessages(PAUSE_TIMEOUT_MSG, this); 3494 } 3495 setState(PAUSED, "relaunchActivityLocked"); 3496 } 3497 3498 configChangeFlags = 0; 3499 deferRelaunchUntilPaused = false; 3500 preserveWindowOnDeferredRelaunch = false; 3501 } 3502 3503 /** 3504 * Request the process of the activity to restart with its saved state (from 3505 * {@link android.app.Activity#onSaveInstanceState}) if possible. It also forces to recompute 3506 * the override configuration. Note if the activity is in background, the process will be killed 3507 * directly with keeping its record. 3508 */ restartProcessIfVisible()3509 void restartProcessIfVisible() { 3510 Slog.i(TAG, "Request to restart process of " + this); 3511 3512 // Reset the existing override configuration so it can be updated according to the latest 3513 // configuration. 3514 getRequestedOverrideConfiguration().unset(); 3515 getResolvedOverrideConfiguration().unset(); 3516 mCompatDisplayInsets = null; 3517 if (visible) { 3518 // Configuration will be ensured when becoming visible, so if it is already visible, 3519 // then the manual update is needed. 3520 updateOverrideConfiguration(); 3521 } 3522 3523 if (!attachedToProcess()) { 3524 return; 3525 } 3526 3527 // The restarting state avoids removing this record when process is died. 3528 setState(RESTARTING_PROCESS, "restartActivityProcess"); 3529 3530 if (!visible || haveState) { 3531 // Kill its process immediately because the activity should be in background. 3532 // The activity state will be update to {@link #DESTROYED} in 3533 // {@link ActivityStack#cleanUpActivityLocked} when handling process died. 3534 mAtmService.mH.post(() -> { 3535 final WindowProcessController wpc; 3536 synchronized (mAtmService.mGlobalLock) { 3537 if (!hasProcess() 3538 || app.getReportedProcState() <= PROCESS_STATE_IMPORTANT_FOREGROUND) { 3539 return; 3540 } 3541 wpc = app; 3542 } 3543 mAtmService.mAmInternal.killProcess(wpc.mName, wpc.mUid, "resetConfig"); 3544 }); 3545 return; 3546 } 3547 3548 if (mAppWindowToken != null) { 3549 mAppWindowToken.startFreezingScreen(); 3550 } 3551 // The process will be killed until the activity reports stopped with saved state (see 3552 // {@link ActivityTaskManagerService.activityStopped}). 3553 try { 3554 mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, 3555 StopActivityItem.obtain(false /* showWindow */, 0 /* configChanges */)); 3556 } catch (RemoteException e) { 3557 Slog.w(TAG, "Exception thrown during restart " + this, e); 3558 } 3559 mStackSupervisor.scheduleRestartTimeout(this); 3560 } 3561 isProcessRunning()3562 private boolean isProcessRunning() { 3563 WindowProcessController proc = app; 3564 if (proc == null) { 3565 proc = mAtmService.mProcessNames.get(processName, info.applicationInfo.uid); 3566 } 3567 return proc != null && proc.hasThread(); 3568 } 3569 3570 /** 3571 * @return Whether a task snapshot starting window may be shown. 3572 */ allowTaskSnapshot()3573 private boolean allowTaskSnapshot() { 3574 if (newIntents == null) { 3575 return true; 3576 } 3577 3578 // Restrict task snapshot starting window to launcher start, or there is no intent at all 3579 // (eg. task being brought to front). If the intent is something else, likely the app is 3580 // going to show some specific page or view, instead of what's left last time. 3581 for (int i = newIntents.size() - 1; i >= 0; i--) { 3582 final Intent intent = newIntents.get(i); 3583 if (intent != null && !ActivityRecord.isMainIntent(intent)) { 3584 return false; 3585 } 3586 } 3587 return true; 3588 } 3589 3590 /** 3591 * Returns {@code true} if the associated activity has the no history flag set on it. 3592 * {@code false} otherwise. 3593 */ isNoHistory()3594 boolean isNoHistory() { 3595 return (intent.getFlags() & FLAG_ACTIVITY_NO_HISTORY) != 0 3596 || (info.flags & FLAG_NO_HISTORY) != 0; 3597 } 3598 saveToXml(XmlSerializer out)3599 void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException { 3600 out.attribute(null, ATTR_ID, String.valueOf(createTime)); 3601 out.attribute(null, ATTR_LAUNCHEDFROMUID, String.valueOf(launchedFromUid)); 3602 if (launchedFromPackage != null) { 3603 out.attribute(null, ATTR_LAUNCHEDFROMPACKAGE, launchedFromPackage); 3604 } 3605 if (resolvedType != null) { 3606 out.attribute(null, ATTR_RESOLVEDTYPE, resolvedType); 3607 } 3608 out.attribute(null, ATTR_COMPONENTSPECIFIED, String.valueOf(componentSpecified)); 3609 out.attribute(null, ATTR_USERID, String.valueOf(mUserId)); 3610 3611 if (taskDescription != null) { 3612 taskDescription.saveToXml(out); 3613 } 3614 3615 out.startTag(null, TAG_INTENT); 3616 intent.saveToXml(out); 3617 out.endTag(null, TAG_INTENT); 3618 3619 if (isPersistable() && persistentState != null) { 3620 out.startTag(null, TAG_PERSISTABLEBUNDLE); 3621 persistentState.saveToXml(out); 3622 out.endTag(null, TAG_PERSISTABLEBUNDLE); 3623 } 3624 } 3625 restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)3626 static ActivityRecord restoreFromXml(XmlPullParser in, 3627 ActivityStackSupervisor stackSupervisor) throws IOException, XmlPullParserException { 3628 Intent intent = null; 3629 PersistableBundle persistentState = null; 3630 int launchedFromUid = 0; 3631 String launchedFromPackage = null; 3632 String resolvedType = null; 3633 boolean componentSpecified = false; 3634 int userId = 0; 3635 long createTime = -1; 3636 final int outerDepth = in.getDepth(); 3637 TaskDescription taskDescription = new TaskDescription(); 3638 3639 for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) { 3640 final String attrName = in.getAttributeName(attrNdx); 3641 final String attrValue = in.getAttributeValue(attrNdx); 3642 if (DEBUG) Slog.d(TaskPersister.TAG, 3643 "ActivityRecord: attribute name=" + attrName + " value=" + attrValue); 3644 if (ATTR_ID.equals(attrName)) { 3645 createTime = Long.parseLong(attrValue); 3646 } else if (ATTR_LAUNCHEDFROMUID.equals(attrName)) { 3647 launchedFromUid = Integer.parseInt(attrValue); 3648 } else if (ATTR_LAUNCHEDFROMPACKAGE.equals(attrName)) { 3649 launchedFromPackage = attrValue; 3650 } else if (ATTR_RESOLVEDTYPE.equals(attrName)) { 3651 resolvedType = attrValue; 3652 } else if (ATTR_COMPONENTSPECIFIED.equals(attrName)) { 3653 componentSpecified = Boolean.parseBoolean(attrValue); 3654 } else if (ATTR_USERID.equals(attrName)) { 3655 userId = Integer.parseInt(attrValue); 3656 } else if (attrName.startsWith(ATTR_TASKDESCRIPTION_PREFIX)) { 3657 taskDescription.restoreFromXml(attrName, attrValue); 3658 } else { 3659 Log.d(TAG, "Unknown ActivityRecord attribute=" + attrName); 3660 } 3661 } 3662 3663 int event; 3664 while (((event = in.next()) != END_DOCUMENT) && 3665 (event != END_TAG || in.getDepth() >= outerDepth)) { 3666 if (event == START_TAG) { 3667 final String name = in.getName(); 3668 if (DEBUG) 3669 Slog.d(TaskPersister.TAG, "ActivityRecord: START_TAG name=" + name); 3670 if (TAG_INTENT.equals(name)) { 3671 intent = Intent.restoreFromXml(in); 3672 if (DEBUG) 3673 Slog.d(TaskPersister.TAG, "ActivityRecord: intent=" + intent); 3674 } else if (TAG_PERSISTABLEBUNDLE.equals(name)) { 3675 persistentState = PersistableBundle.restoreFromXml(in); 3676 if (DEBUG) Slog.d(TaskPersister.TAG, 3677 "ActivityRecord: persistentState=" + persistentState); 3678 } else { 3679 Slog.w(TAG, "restoreActivity: unexpected name=" + name); 3680 XmlUtils.skipCurrentTag(in); 3681 } 3682 } 3683 } 3684 3685 if (intent == null) { 3686 throw new XmlPullParserException("restoreActivity error intent=" + intent); 3687 } 3688 3689 final ActivityTaskManagerService service = stackSupervisor.mService; 3690 final ActivityInfo aInfo = stackSupervisor.resolveActivity(intent, resolvedType, 0, null, 3691 userId, Binder.getCallingUid()); 3692 if (aInfo == null) { 3693 throw new XmlPullParserException("restoreActivity resolver error. Intent=" + intent + 3694 " resolvedType=" + resolvedType); 3695 } 3696 final ActivityRecord r = new ActivityRecord(service, null /* caller */, 3697 0 /* launchedFromPid */, launchedFromUid, launchedFromPackage, intent, resolvedType, 3698 aInfo, service.getConfiguration(), null /* resultTo */, null /* resultWho */, 3699 0 /* reqCode */, componentSpecified, false /* rootVoiceInteraction */, 3700 stackSupervisor, null /* options */, null /* sourceRecord */); 3701 3702 r.persistentState = persistentState; 3703 r.taskDescription = taskDescription; 3704 r.createTime = createTime; 3705 3706 return r; 3707 } 3708 isInVrUiMode(Configuration config)3709 private static boolean isInVrUiMode(Configuration config) { 3710 return (config.uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_VR_HEADSET; 3711 } 3712 getUid()3713 int getUid() { 3714 return info.applicationInfo.uid; 3715 } 3716 setShowWhenLocked(boolean showWhenLocked)3717 void setShowWhenLocked(boolean showWhenLocked) { 3718 mShowWhenLocked = showWhenLocked; 3719 mRootActivityContainer.ensureActivitiesVisible(null, 0 /* configChanges */, 3720 false /* preserveWindows */); 3721 } 3722 setInheritShowWhenLocked(boolean inheritShowWhenLocked)3723 void setInheritShowWhenLocked(boolean inheritShowWhenLocked) { 3724 mInheritShownWhenLocked = inheritShowWhenLocked; 3725 mRootActivityContainer.ensureActivitiesVisible(null, 0, false); 3726 } 3727 3728 /** 3729 * @return true if the activity windowing mode is not 3730 * {@link android.app.WindowConfiguration#WINDOWING_MODE_PINNED} and a) activity 3731 * contains windows that have {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} set or if the 3732 * activity has set {@link #mShowWhenLocked}, or b) if the activity has set 3733 * {@link #mInheritShownWhenLocked} and the activity behind this satisfies the 3734 * conditions a) above. 3735 * Multi-windowing mode will be exited if true is returned. 3736 */ canShowWhenLocked()3737 boolean canShowWhenLocked() { 3738 if (!inPinnedWindowingMode() && (mShowWhenLocked 3739 || (mAppWindowToken != null && mAppWindowToken.containsShowWhenLockedWindow()))) { 3740 return true; 3741 } else if (mInheritShownWhenLocked) { 3742 ActivityRecord r = getActivityBelow(); 3743 return r != null && !r.inPinnedWindowingMode() && (r.mShowWhenLocked 3744 || (r.mAppWindowToken != null 3745 && r.mAppWindowToken.containsShowWhenLockedWindow())); 3746 } else { 3747 return false; 3748 } 3749 } 3750 3751 /** 3752 * @return an {@link ActivityRecord} of the activity below this activity, or {@code null} if no 3753 * such activity exists. 3754 */ 3755 @Nullable getActivityBelow()3756 private ActivityRecord getActivityBelow() { 3757 final int pos = task.mActivities.indexOf(this); 3758 if (pos == -1) { 3759 throw new IllegalStateException("Activity not found in its task"); 3760 } 3761 return pos == 0 ? null : task.getChildAt(pos - 1); 3762 } 3763 setTurnScreenOn(boolean turnScreenOn)3764 void setTurnScreenOn(boolean turnScreenOn) { 3765 mTurnScreenOn = turnScreenOn; 3766 } 3767 3768 /** 3769 * Determines whether this ActivityRecord can turn the screen on. It checks whether the flag 3770 * {@link #mTurnScreenOn} is set and checks whether the ActivityRecord should be visible 3771 * depending on Keyguard state 3772 * 3773 * @return true if the screen can be turned on, false otherwise. 3774 */ canTurnScreenOn()3775 boolean canTurnScreenOn() { 3776 final ActivityStack stack = getActivityStack(); 3777 return mTurnScreenOn && stack != null && 3778 stack.checkKeyguardVisibility(this, true /* shouldBeVisible */, true /* isTop */); 3779 } 3780 3781 /** 3782 * Check if this activity is able to resume. For pre-Q apps, only the topmost activities of each 3783 * process are allowed to be resumed. 3784 * 3785 * @return true if this activity can be resumed. 3786 */ canResumeByCompat()3787 boolean canResumeByCompat() { 3788 return app == null || app.updateTopResumingActivityInProcessIfNeeded(this); 3789 } 3790 getTurnScreenOnFlag()3791 boolean getTurnScreenOnFlag() { 3792 return mTurnScreenOn; 3793 } 3794 isTopRunningActivity()3795 boolean isTopRunningActivity() { 3796 return mRootActivityContainer.topRunningActivity() == this; 3797 } 3798 3799 /** 3800 * @return {@code true} if this is the resumed activity on its current display, {@code false} 3801 * otherwise. 3802 */ isResumedActivityOnDisplay()3803 boolean isResumedActivityOnDisplay() { 3804 final ActivityDisplay display = getDisplay(); 3805 return display != null && this == display.getResumedActivity(); 3806 } 3807 registerRemoteAnimations(RemoteAnimationDefinition definition)3808 void registerRemoteAnimations(RemoteAnimationDefinition definition) { 3809 if (mAppWindowToken == null) { 3810 Slog.w(TAG_WM, "Attempted to register remote animations with non-existing app" 3811 + " token: " + appToken); 3812 return; 3813 } 3814 mAppWindowToken.registerRemoteAnimations(definition); 3815 } 3816 3817 @Override toString()3818 public String toString() { 3819 if (stringName != null) { 3820 return stringName + " t" + (task == null ? INVALID_TASK_ID : task.taskId) + 3821 (finishing ? " f}" : "}"); 3822 } 3823 StringBuilder sb = new StringBuilder(128); 3824 sb.append("ActivityRecord{"); 3825 sb.append(Integer.toHexString(System.identityHashCode(this))); 3826 sb.append(" u"); 3827 sb.append(mUserId); 3828 sb.append(' '); 3829 sb.append(intent.getComponent().flattenToShortString()); 3830 stringName = sb.toString(); 3831 return toString(); 3832 } 3833 writeIdentifierToProto(ProtoOutputStream proto, long fieldId)3834 void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) { 3835 final long token = proto.start(fieldId); 3836 proto.write(HASH_CODE, System.identityHashCode(this)); 3837 proto.write(USER_ID, mUserId); 3838 proto.write(TITLE, intent.getComponent().flattenToShortString()); 3839 proto.end(token); 3840 } 3841 3842 /** 3843 * Write all fields to an {@code ActivityRecordProto}. This assumes the 3844 * {@code ActivityRecordProto} is the outer-most proto data. 3845 */ writeToProto(ProtoOutputStream proto)3846 void writeToProto(ProtoOutputStream proto) { 3847 super.writeToProto(proto, CONFIGURATION_CONTAINER, WindowTraceLogLevel.ALL); 3848 writeIdentifierToProto(proto, IDENTIFIER); 3849 proto.write(STATE, mState.toString()); 3850 proto.write(VISIBLE, visible); 3851 proto.write(FRONT_OF_TASK, frontOfTask); 3852 if (hasProcess()) { 3853 proto.write(PROC_ID, app.getPid()); 3854 } 3855 proto.write(TRANSLUCENT, !fullscreen); 3856 } 3857 writeToProto(ProtoOutputStream proto, long fieldId)3858 public void writeToProto(ProtoOutputStream proto, long fieldId) { 3859 final long token = proto.start(fieldId); 3860 writeToProto(proto); 3861 proto.end(token); 3862 } 3863 3864 /** 3865 * The precomputed insets of the display in each rotation. This is used to make the size 3866 * compatibility mode activity compute the configuration without relying on its current display. 3867 */ 3868 static class CompatDisplayInsets { 3869 final int mDisplayWidth; 3870 final int mDisplayHeight; 3871 3872 /** 3873 * The nonDecorInsets for each rotation. Includes the navigation bar and cutout insets. It 3874 * is used to compute the appBounds. 3875 */ 3876 final Rect[] mNonDecorInsets = new Rect[4]; 3877 /** 3878 * The stableInsets for each rotation. Includes the status bar inset and the 3879 * nonDecorInsets. It is used to compute {@link Configuration#screenWidthDp} and 3880 * {@link Configuration#screenHeightDp}. 3881 */ 3882 final Rect[] mStableInsets = new Rect[4]; 3883 CompatDisplayInsets(DisplayContent display)3884 CompatDisplayInsets(DisplayContent display) { 3885 mDisplayWidth = display.mBaseDisplayWidth; 3886 mDisplayHeight = display.mBaseDisplayHeight; 3887 final DisplayPolicy policy = display.getDisplayPolicy(); 3888 for (int rotation = 0; rotation < 4; rotation++) { 3889 mNonDecorInsets[rotation] = new Rect(); 3890 mStableInsets[rotation] = new Rect(); 3891 final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270); 3892 final int dw = rotated ? mDisplayHeight : mDisplayWidth; 3893 final int dh = rotated ? mDisplayWidth : mDisplayHeight; 3894 final DisplayCutout cutout = display.calculateDisplayCutoutForRotation(rotation) 3895 .getDisplayCutout(); 3896 policy.getNonDecorInsetsLw(rotation, dw, dh, cutout, mNonDecorInsets[rotation]); 3897 mStableInsets[rotation].set(mNonDecorInsets[rotation]); 3898 policy.convertNonDecorInsetsToStableInsets(mStableInsets[rotation], rotation); 3899 } 3900 } 3901 getDisplayBoundsByRotation(Rect outBounds, int rotation)3902 void getDisplayBoundsByRotation(Rect outBounds, int rotation) { 3903 final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270); 3904 final int dw = rotated ? mDisplayHeight : mDisplayWidth; 3905 final int dh = rotated ? mDisplayWidth : mDisplayHeight; 3906 outBounds.set(0, 0, dw, dh); 3907 } 3908 getDisplayBoundsByOrientation(Rect outBounds, int orientation)3909 void getDisplayBoundsByOrientation(Rect outBounds, int orientation) { 3910 final int longSide = Math.max(mDisplayWidth, mDisplayHeight); 3911 final int shortSide = Math.min(mDisplayWidth, mDisplayHeight); 3912 final boolean isLandscape = orientation == ORIENTATION_LANDSCAPE; 3913 outBounds.set(0, 0, isLandscape ? longSide : shortSide, 3914 isLandscape ? shortSide : longSide); 3915 } 3916 } 3917 } 3918