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