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.ActivityOptions.ANIM_UNDEFINED; 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_DREAM; 40 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME; 41 import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; 42 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; 43 import static android.app.WindowConfiguration.ROTATION_UNDEFINED; 44 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; 45 import static android.app.WindowConfiguration.activityTypeToString; 46 import static android.content.Intent.ACTION_MAIN; 47 import static android.content.Intent.CATEGORY_HOME; 48 import static android.content.Intent.CATEGORY_LAUNCHER; 49 import static android.content.Intent.CATEGORY_SECONDARY_HOME; 50 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; 51 import static android.content.Intent.FLAG_ACTIVITY_NO_HISTORY; 52 import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION; 53 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT; 54 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE; 55 import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; 56 import static android.content.pm.ActivityInfo.CONFIG_UI_MODE; 57 import static android.content.pm.ActivityInfo.CONFIG_WINDOW_CONFIGURATION; 58 import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; 59 import static android.content.pm.ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS; 60 import static android.content.pm.ActivityInfo.FLAG_IMMERSIVE; 61 import static android.content.pm.ActivityInfo.FLAG_INHERIT_SHOW_WHEN_LOCKED; 62 import static android.content.pm.ActivityInfo.FLAG_MULTIPROCESS; 63 import static android.content.pm.ActivityInfo.FLAG_NO_HISTORY; 64 import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; 65 import static android.content.pm.ActivityInfo.FLAG_STATE_NOT_NEEDED; 66 import static android.content.pm.ActivityInfo.FLAG_TURN_SCREEN_ON; 67 import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE; 68 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE; 69 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK; 70 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP; 71 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS; 72 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT; 73 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED; 74 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER; 75 import static android.content.pm.ActivityInfo.PERSIST_ACROSS_REBOOTS; 76 import static android.content.pm.ActivityInfo.PERSIST_ROOT_ONLY; 77 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE; 78 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; 79 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; 80 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; 81 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND; 82 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET; 83 import static android.content.pm.ActivityInfo.isFixedOrientationLandscape; 84 import static android.content.pm.ActivityInfo.isFixedOrientationPortrait; 85 import static android.content.res.Configuration.EMPTY; 86 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE; 87 import static android.content.res.Configuration.ORIENTATION_PORTRAIT; 88 import static android.content.res.Configuration.ORIENTATION_UNDEFINED; 89 import static android.content.res.Configuration.UI_MODE_TYPE_MASK; 90 import static android.content.res.Configuration.UI_MODE_TYPE_VR_HEADSET; 91 import static android.os.Build.VERSION_CODES.HONEYCOMB; 92 import static android.os.Build.VERSION_CODES.O; 93 import static android.os.Process.SYSTEM_UID; 94 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; 95 import static android.view.Display.COLOR_MODE_DEFAULT; 96 import static android.view.Display.INVALID_DISPLAY; 97 import static android.view.Surface.ROTATION_270; 98 import static android.view.Surface.ROTATION_90; 99 import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; 100 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; 101 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; 102 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; 103 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; 104 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION; 105 import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE; 106 import static android.view.WindowManager.TRANSIT_TASK_CLOSE; 107 import static android.view.WindowManager.TRANSIT_TASK_OPEN_BEHIND; 108 import static android.view.WindowManager.TRANSIT_UNSET; 109 110 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; 111 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; 112 import static com.android.server.wm.ActivityRecordProto.ALL_DRAWN; 113 import static com.android.server.wm.ActivityRecordProto.APP_STOPPED; 114 import static com.android.server.wm.ActivityRecordProto.CLIENT_VISIBLE; 115 import static com.android.server.wm.ActivityRecordProto.DEFER_HIDING_CLIENT; 116 import static com.android.server.wm.ActivityRecordProto.FILLS_PARENT; 117 import static com.android.server.wm.ActivityRecordProto.FRONT_OF_TASK; 118 import static com.android.server.wm.ActivityRecordProto.FROZEN_BOUNDS; 119 import static com.android.server.wm.ActivityRecordProto.IDENTIFIER; 120 import static com.android.server.wm.ActivityRecordProto.IS_ANIMATING; 121 import static com.android.server.wm.ActivityRecordProto.IS_WAITING_FOR_TRANSITION_START; 122 import static com.android.server.wm.ActivityRecordProto.LAST_ALL_DRAWN; 123 import static com.android.server.wm.ActivityRecordProto.LAST_SURFACE_SHOWING; 124 import static com.android.server.wm.ActivityRecordProto.NAME; 125 import static com.android.server.wm.ActivityRecordProto.NUM_DRAWN_WINDOWS; 126 import static com.android.server.wm.ActivityRecordProto.NUM_INTERESTING_WINDOWS; 127 import static com.android.server.wm.ActivityRecordProto.PROC_ID; 128 import static com.android.server.wm.ActivityRecordProto.REPORTED_DRAWN; 129 import static com.android.server.wm.ActivityRecordProto.REPORTED_VISIBLE; 130 import static com.android.server.wm.ActivityRecordProto.STARTING_DISPLAYED; 131 import static com.android.server.wm.ActivityRecordProto.STARTING_MOVED; 132 import static com.android.server.wm.ActivityRecordProto.STARTING_WINDOW; 133 import static com.android.server.wm.ActivityRecordProto.STATE; 134 import static com.android.server.wm.ActivityRecordProto.THUMBNAIL; 135 import static com.android.server.wm.ActivityRecordProto.TRANSLUCENT; 136 import static com.android.server.wm.ActivityRecordProto.VISIBLE; 137 import static com.android.server.wm.ActivityRecordProto.VISIBLE_REQUESTED; 138 import static com.android.server.wm.ActivityRecordProto.VISIBLE_SET_FROM_TRANSFERRED_STARTING_WINDOW; 139 import static com.android.server.wm.ActivityRecordProto.WINDOW_TOKEN; 140 import static com.android.server.wm.ActivityStack.ActivityState.DESTROYED; 141 import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING; 142 import static com.android.server.wm.ActivityStack.ActivityState.FINISHING; 143 import static com.android.server.wm.ActivityStack.ActivityState.INITIALIZING; 144 import static com.android.server.wm.ActivityStack.ActivityState.PAUSED; 145 import static com.android.server.wm.ActivityStack.ActivityState.PAUSING; 146 import static com.android.server.wm.ActivityStack.ActivityState.RESTARTING_PROCESS; 147 import static com.android.server.wm.ActivityStack.ActivityState.RESUMED; 148 import static com.android.server.wm.ActivityStack.ActivityState.STARTED; 149 import static com.android.server.wm.ActivityStack.ActivityState.STOPPED; 150 import static com.android.server.wm.ActivityStack.ActivityState.STOPPING; 151 import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE; 152 import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS; 153 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_APP; 154 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CLEANUP; 155 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION; 156 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONTAINERS; 157 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_FOCUS; 158 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_PAUSE; 159 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RESULTS; 160 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SAVED_STATE; 161 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES; 162 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH; 163 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TRANSITION; 164 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_USER_LEAVING; 165 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_VISIBILITY; 166 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_ADD_REMOVE; 167 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_APP; 168 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION; 169 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONTAINERS; 170 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_FOCUS; 171 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_PAUSE; 172 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RESULTS; 173 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SAVED_STATE; 174 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STATES; 175 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_SWITCH; 176 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_TRANSITION; 177 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_USER_LEAVING; 178 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_VISIBILITY; 179 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; 180 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; 181 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE; 182 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE; 183 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE; 184 import static com.android.server.wm.ActivityTaskManagerService.getInputDispatchingTimeoutLocked; 185 import static com.android.server.wm.IdentifierProto.HASH_CODE; 186 import static com.android.server.wm.IdentifierProto.TITLE; 187 import static com.android.server.wm.IdentifierProto.USER_ID; 188 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; 189 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; 190 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM; 191 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; 192 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; 193 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; 194 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; 195 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_SCREEN_ROTATION; 196 import static com.android.server.wm.TaskPersister.DEBUG; 197 import static com.android.server.wm.TaskPersister.IMAGE_EXTENSION; 198 import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN; 199 import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS; 200 import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION; 201 import static com.android.server.wm.WindowContainerChildProto.ACTIVITY; 202 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM; 203 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS; 204 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW_VERBOSE; 205 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; 206 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL; 207 import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES; 208 import static com.android.server.wm.WindowState.LEGACY_POLICY_VISIBILITY; 209 import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN; 210 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM; 211 212 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; 213 import static org.xmlpull.v1.XmlPullParser.END_TAG; 214 import static org.xmlpull.v1.XmlPullParser.START_TAG; 215 216 import android.annotation.IntDef; 217 import android.annotation.NonNull; 218 import android.annotation.Nullable; 219 import android.annotation.Size; 220 import android.app.Activity; 221 import android.app.ActivityManager; 222 import android.app.ActivityManager.TaskDescription; 223 import android.app.ActivityOptions; 224 import android.app.PendingIntent; 225 import android.app.PictureInPictureParams; 226 import android.app.ResultInfo; 227 import android.app.WaitResult.LaunchState; 228 import android.app.servertransaction.ActivityConfigurationChangeItem; 229 import android.app.servertransaction.ActivityLifecycleItem; 230 import android.app.servertransaction.ActivityRelaunchItem; 231 import android.app.servertransaction.ActivityResultItem; 232 import android.app.servertransaction.ClientTransaction; 233 import android.app.servertransaction.ClientTransactionItem; 234 import android.app.servertransaction.DestroyActivityItem; 235 import android.app.servertransaction.MoveToDisplayItem; 236 import android.app.servertransaction.NewIntentItem; 237 import android.app.servertransaction.PauseActivityItem; 238 import android.app.servertransaction.ResumeActivityItem; 239 import android.app.servertransaction.StartActivityItem; 240 import android.app.servertransaction.StopActivityItem; 241 import android.app.servertransaction.TopResumedActivityChangeItem; 242 import android.app.usage.UsageEvents.Event; 243 import android.content.ComponentName; 244 import android.content.Intent; 245 import android.content.pm.ActivityInfo; 246 import android.content.pm.ApplicationInfo; 247 import android.content.res.CompatibilityInfo; 248 import android.content.res.Configuration; 249 import android.content.res.Resources; 250 import android.graphics.Bitmap; 251 import android.graphics.GraphicBuffer; 252 import android.graphics.PixelFormat; 253 import android.graphics.Point; 254 import android.graphics.Rect; 255 import android.net.Uri; 256 import android.os.Binder; 257 import android.os.Build; 258 import android.os.Bundle; 259 import android.os.Debug; 260 import android.os.IBinder; 261 import android.os.PersistableBundle; 262 import android.os.Process; 263 import android.os.RemoteException; 264 import android.os.SystemClock; 265 import android.os.Trace; 266 import android.os.UserHandle; 267 import android.os.storage.StorageManager; 268 import android.service.dreams.DreamActivity; 269 import android.service.dreams.DreamManagerInternal; 270 import android.service.voice.IVoiceInteractionSession; 271 import android.text.TextUtils; 272 import android.util.ArraySet; 273 import android.util.EventLog; 274 import android.util.Log; 275 import android.util.MergedConfiguration; 276 import android.util.Slog; 277 import android.util.TimeUtils; 278 import android.util.proto.ProtoOutputStream; 279 import android.view.AppTransitionAnimationSpec; 280 import android.view.DisplayCutout; 281 import android.view.DisplayInfo; 282 import android.view.IAppTransitionAnimationSpecsFuture; 283 import android.view.IApplicationToken; 284 import android.view.InputApplicationHandle; 285 import android.view.RemoteAnimationDefinition; 286 import android.view.RemoteAnimationTarget; 287 import android.view.SurfaceControl; 288 import android.view.SurfaceControl.Transaction; 289 import android.view.WindowManager; 290 import android.view.WindowManager.LayoutParams; 291 import android.view.animation.Animation; 292 import android.window.WindowContainerToken; 293 294 import com.android.internal.R; 295 import com.android.internal.annotations.VisibleForTesting; 296 import com.android.internal.app.ResolverActivity; 297 import com.android.internal.content.ReferrerIntent; 298 import com.android.internal.util.ToBooleanFunction; 299 import com.android.internal.util.XmlUtils; 300 import com.android.internal.util.function.pooled.PooledConsumer; 301 import com.android.internal.util.function.pooled.PooledFunction; 302 import com.android.internal.util.function.pooled.PooledLambda; 303 import com.android.server.AttributeCache; 304 import com.android.server.LocalServices; 305 import com.android.server.am.AppTimeTracker; 306 import com.android.server.am.PendingIntentRecord; 307 import com.android.server.display.color.ColorDisplayService; 308 import com.android.server.policy.WindowManagerPolicy; 309 import com.android.server.protolog.common.ProtoLog; 310 import com.android.server.uri.NeededUriGrants; 311 import com.android.server.uri.UriPermissionOwner; 312 import com.android.server.wm.ActivityMetricsLogger.TransitionInfoSnapshot; 313 import com.android.server.wm.ActivityStack.ActivityState; 314 import com.android.server.wm.SurfaceAnimator.AnimationType; 315 import com.android.server.wm.WindowManagerService.H; 316 import com.android.server.wm.utils.InsetUtils; 317 318 import com.google.android.collect.Sets; 319 320 import org.xmlpull.v1.XmlPullParser; 321 import org.xmlpull.v1.XmlPullParserException; 322 import org.xmlpull.v1.XmlSerializer; 323 324 import java.io.File; 325 import java.io.IOException; 326 import java.io.PrintWriter; 327 import java.lang.ref.WeakReference; 328 import java.util.ArrayDeque; 329 import java.util.ArrayList; 330 import java.util.Arrays; 331 import java.util.HashSet; 332 import java.util.List; 333 import java.util.Objects; 334 import java.util.function.Consumer; 335 import java.util.function.Function; 336 import java.util.function.Predicate; 337 338 /** 339 * An entry in the history stack, representing an activity. 340 */ 341 final class ActivityRecord extends WindowToken implements WindowManagerService.AppFreezeListener { 342 private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityRecord" : TAG_ATM; 343 private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE; 344 private static final String TAG_APP = TAG + POSTFIX_APP; 345 private static final String TAG_CONFIGURATION = TAG + POSTFIX_CONFIGURATION; 346 private static final String TAG_CONTAINERS = TAG + POSTFIX_CONTAINERS; 347 private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS; 348 private static final String TAG_PAUSE = TAG + POSTFIX_PAUSE; 349 private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS; 350 private static final String TAG_SAVED_STATE = TAG + POSTFIX_SAVED_STATE; 351 private static final String TAG_STATES = TAG + POSTFIX_STATES; 352 private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH; 353 private static final String TAG_TRANSITION = TAG + POSTFIX_TRANSITION; 354 private static final String TAG_USER_LEAVING = TAG + POSTFIX_USER_LEAVING; 355 private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY; 356 357 private static final String ATTR_ID = "id"; 358 private static final String TAG_INTENT = "intent"; 359 private static final String ATTR_USERID = "user_id"; 360 private static final String TAG_PERSISTABLEBUNDLE = "persistable_bundle"; 361 private static final String ATTR_LAUNCHEDFROMUID = "launched_from_uid"; 362 private static final String ATTR_LAUNCHEDFROMPACKAGE = "launched_from_package"; 363 private static final String ATTR_LAUNCHEDFROMFEATURE = "launched_from_feature"; 364 private static final String ATTR_RESOLVEDTYPE = "resolved_type"; 365 private static final String ATTR_COMPONENTSPECIFIED = "component_specified"; 366 static final String ACTIVITY_ICON_SUFFIX = "_activity_icon_"; 367 368 // How many activities have to be scheduled to stop to force a stop pass. 369 private static final int MAX_STOPPING_TO_FORCE = 3; 370 371 private static final int STARTING_WINDOW_TYPE_NONE = 0; 372 private static final int STARTING_WINDOW_TYPE_SNAPSHOT = 1; 373 private static final int STARTING_WINDOW_TYPE_SPLASH_SCREEN = 2; 374 375 /** 376 * Value to increment the z-layer when boosting a layer during animations. BOOST in l33tsp34k. 377 */ 378 @VisibleForTesting static final int Z_BOOST_BASE = 800570000; 379 static final int INVALID_PID = -1; 380 381 // How long we wait until giving up on the last activity to pause. This 382 // is short because it directly impacts the responsiveness of starting the 383 // next activity. 384 private static final int PAUSE_TIMEOUT = 500; 385 386 // Ticks during which we check progress while waiting for an app to launch. 387 private static final int LAUNCH_TICK = 500; 388 389 // How long we wait for the activity to tell us it has stopped before 390 // giving up. This is a good amount of time because we really need this 391 // from the application in order to get its saved state. Once the stop 392 // is complete we may start destroying client resources triggering 393 // crashes if the UI thread was hung. We put this timeout one second behind 394 // the ANR timeout so these situations will generate ANR instead of 395 // Surface lost or other errors. 396 private static final int STOP_TIMEOUT = 11 * 1000; 397 398 // How long we wait until giving up on an activity telling us it has 399 // finished destroying itself. 400 private static final int DESTROY_TIMEOUT = 10 * 1000; 401 402 final ActivityTaskManagerService mAtmService; 403 final ActivityInfo info; // activity info provided by developer in AndroidManifest 404 // Non-null only for application tokens. 405 // TODO: rename to mActivityToken 406 final ActivityRecord.Token appToken; 407 // Which user is this running for? 408 final int mUserId; 409 // The package implementing intent's component 410 // TODO: rename to mPackageName 411 final String packageName; 412 // the intent component, or target of an alias. 413 final ComponentName mActivityComponent; 414 // Has a wallpaper window as a background. 415 // TODO: Rename to mHasWallpaper and also see if it possible to combine this with the 416 // mOccludesParent field. 417 final boolean hasWallpaper; 418 // Input application handle used by the input dispatcher. 419 private InputApplicationHandle mInputApplicationHandle; 420 421 final int launchedFromPid; // always the pid who started the activity. 422 final int launchedFromUid; // always the uid who started the activity. 423 final String launchedFromPackage; // always the package who started the activity. 424 final @Nullable String launchedFromFeatureId; // always the feature in launchedFromPackage 425 final Intent intent; // the original intent that generated us 426 final String shortComponentName; // the short component name of the intent 427 final String resolvedType; // as per original caller; 428 final String processName; // process where this component wants to run 429 final String taskAffinity; // as per ActivityInfo.taskAffinity 430 final boolean stateNotNeeded; // As per ActivityInfo.flags 431 @VisibleForTesting 432 int mHandoverLaunchDisplayId = INVALID_DISPLAY; // Handover launch display id to next activity. 433 @VisibleForTesting 434 TaskDisplayArea mHandoverTaskDisplayArea; // Handover launch task display area. 435 private final boolean componentSpecified; // did caller specify an explicit component? 436 final boolean rootVoiceInteraction; // was this the root activity of a voice interaction? 437 438 private CharSequence nonLocalizedLabel; // the label information from the package mgr. 439 private int labelRes; // the label information from the package mgr. 440 private int icon; // resource identifier of activity's icon. 441 private int logo; // resource identifier of activity's logo. 442 private int theme; // resource identifier of activity's theme. 443 private int windowFlags; // custom window flags for preview window. 444 private Task task; // the task this is in. 445 private long createTime = System.currentTimeMillis(); 446 long lastVisibleTime; // last time this activity became visible 447 long cpuTimeAtResume; // the cpu time of host process at the time of resuming activity 448 long pauseTime; // last time we started pausing the activity 449 long launchTickTime; // base time for launch tick messages 450 long topResumedStateLossTime; // last time we reported top resumed state loss to an activity 451 // Last configuration reported to the activity in the client process. 452 private MergedConfiguration mLastReportedConfiguration; 453 private int mLastReportedDisplayId; 454 boolean mLastReportedMultiWindowMode; 455 boolean mLastReportedPictureInPictureMode; 456 CompatibilityInfo compat;// last used compatibility mode 457 ActivityRecord resultTo; // who started this entry, so will get our reply 458 final String resultWho; // additional identifier for use by resultTo. 459 final int requestCode; // code given by requester (resultTo) 460 ArrayList<ResultInfo> results; // pending ActivityResult objs we have received 461 HashSet<WeakReference<PendingIntentRecord>> pendingResults; // all pending intents for this act 462 ArrayList<ReferrerIntent> newIntents; // any pending new intents for single-top mode 463 Intent mLastNewIntent; // the last new intent we delivered to client 464 ActivityOptions pendingOptions; // most recently given options 465 ActivityOptions returningOptions; // options that are coming back via convertToTranslucent 466 AppTimeTracker appTimeTracker; // set if we are tracking the time in this app/task/activity 467 ActivityServiceConnectionsHolder mServiceConnectionsHolder; // Service connections. 468 UriPermissionOwner uriPermissions; // current special URI access perms. 469 WindowProcessController app; // if non-null, hosting application 470 private ActivityState mState; // current state we are in 471 private Bundle mIcicle; // last saved activity state 472 private PersistableBundle mPersistentState; // last persistently saved activity state 473 private boolean mHaveState = true; // Indicates whether the last saved state of activity is 474 // preserved. This starts out 'true', since the initial state 475 // of an activity is that we have everything, and we should 476 // never consider it lacking in state to be removed if it 477 // dies. After an activity is launched it follows the value 478 // of #mIcicle. 479 boolean launchFailed; // set if a launched failed, to abort on 2nd try 480 boolean stopped; // is activity pause finished? 481 boolean delayedResume; // not yet resumed because of stopped app switches? 482 boolean finishing; // activity in pending finish list? 483 boolean deferRelaunchUntilPaused; // relaunch of activity is being deferred until pause is 484 // completed 485 boolean preserveWindowOnDeferredRelaunch; // activity windows are preserved on deferred relaunch 486 int configChangeFlags; // which config values have changed 487 private boolean keysPaused; // has key dispatching been paused for it? 488 int launchMode; // the launch mode activity attribute. 489 int lockTaskLaunchMode; // the lockTaskMode manifest attribute, subject to override 490 private boolean mVisible; // Should this token's windows be visible? 491 boolean visibleIgnoringKeyguard; // is this activity visible, ignoring the fact that Keyguard 492 // might hide this activity? 493 // True if the visible state of this token was forced to true due to a transferred starting 494 // window. 495 private boolean mVisibleSetFromTransferredStartingWindow; 496 // TODO: figure out how to consolidate with the same variable in ActivityRecord. 497 private boolean mDeferHidingClient; // If true we told WM to defer reporting to the client 498 // process that it is hidden. 499 private boolean mLastDeferHidingClient; // If true we will defer setting mClientVisible to false 500 // and reporting to the client that it is hidden. 501 private boolean mSetToSleep; // have we told the activity to sleep? 502 boolean nowVisible; // is this activity's window visible? 503 boolean mDrawn; // is this activity's window drawn? 504 boolean mClientVisibilityDeferred;// was the visibility change message to client deferred? 505 boolean idle; // has the activity gone idle? 506 boolean hasBeenLaunched;// has this activity ever been launched? 507 boolean frozenBeforeDestroy;// has been frozen but not yet destroyed. 508 boolean immersive; // immersive mode (don't interrupt if possible) 509 boolean forceNewConfig; // force re-create with new config next time 510 boolean supportsEnterPipOnTaskSwitch; // This flag is set by the system to indicate that the 511 // activity can enter picture in picture while pausing (only when switching to another task) 512 PictureInPictureParams pictureInPictureArgs = new PictureInPictureParams.Builder().build(); 513 // The PiP params used when deferring the entering of picture-in-picture. 514 int launchCount; // count of launches since last state 515 long lastLaunchTime; // time of last launch of this activity 516 ComponentName requestedVrComponent; // the requested component for handling VR mode. 517 518 boolean inHistory; // are we in the history stack? 519 final ActivityStackSupervisor mStackSupervisor; 520 final RootWindowContainer mRootWindowContainer; 521 522 static final int STARTING_WINDOW_NOT_SHOWN = 0; 523 static final int STARTING_WINDOW_SHOWN = 1; 524 static final int STARTING_WINDOW_REMOVED = 2; 525 int mStartingWindowState = STARTING_WINDOW_NOT_SHOWN; 526 private boolean mTaskOverlay = false; // Task is always on-top of other activities in the task. 527 528 // Marking the reason why this activity is being relaunched. Mainly used to track that this 529 // activity is being relaunched to fulfill a resize request due to compatibility issues, e.g. in 530 // pre-NYC apps that don't have a sense of being resized. 531 int mRelaunchReason = RELAUNCH_REASON_NONE; 532 533 TaskDescription taskDescription; // the recents information for this activity 534 535 // These configurations are collected from application's resources based on size-sensitive 536 // qualifiers. For example, layout-w800dp will be added to mHorizontalSizeConfigurations as 800 537 // and drawable-sw400dp will be added to both as 400. 538 private int[] mVerticalSizeConfigurations; 539 private int[] mHorizontalSizeConfigurations; 540 private int[] mSmallestSizeConfigurations; 541 542 /** 543 * The precomputed display insets for resolving configuration. It will be non-null if 544 * {@link #shouldUseSizeCompatMode} returns {@code true}. 545 */ 546 private CompatDisplayInsets mCompatDisplayInsets; 547 548 boolean pendingVoiceInteractionStart; // Waiting for activity-invoked voice session 549 IVoiceInteractionSession voiceSession; // Voice interaction session for this activity 550 551 boolean mVoiceInteraction; 552 553 private int mPendingRelaunchCount; 554 555 // True if we are current in the process of removing this app token from the display 556 private boolean mRemovingFromDisplay = false; 557 558 private RemoteAnimationDefinition mRemoteAnimationDefinition; 559 560 AnimatingActivityRegistry mAnimatingActivityRegistry; 561 562 private Task mLastParent; 563 564 // Have we told the window clients to show themselves? 565 private boolean mClientVisible; 566 567 boolean firstWindowDrawn; 568 // Last drawn state we reported to the app token. 569 private boolean reportedDrawn; 570 private final WindowState.UpdateReportedVisibilityResults mReportedVisibilityResults = 571 new WindowState.UpdateReportedVisibilityResults(); 572 573 private boolean mUseTransferredAnimation; 574 575 /** 576 * @see #currentLaunchCanTurnScreenOn() 577 */ 578 private boolean mCurrentLaunchCanTurnScreenOn = true; 579 580 /** Whether our surface was set to be showing in the last call to {@link #prepareSurfaces} */ 581 private boolean mLastSurfaceShowing = true; 582 583 private Letterbox mLetterbox; 584 585 /** 586 * The activity is opaque and fills the entire space of this task. 587 * @see WindowContainer#fillsParent() 588 */ 589 private boolean mOccludesParent; 590 591 // The input dispatching timeout for this application token in nanoseconds. 592 long mInputDispatchingTimeoutNanos; 593 594 private boolean mShowWhenLocked; 595 private boolean mInheritShownWhenLocked; 596 private boolean mTurnScreenOn; 597 598 /** Have we been asked to have this token keep the screen frozen? */ 599 private boolean mFreezingScreen; 600 601 // These are used for determining when all windows associated with 602 // an activity have been drawn, so they can be made visible together 603 // at the same time. 604 // initialize so that it doesn't match mTransactionSequence which is an int. 605 private long mLastTransactionSequence = Long.MIN_VALUE; 606 private int mNumInterestingWindows; 607 private int mNumDrawnWindows; 608 boolean allDrawn; 609 private boolean mLastAllDrawn; 610 611 private boolean mLastContainsShowWhenLockedWindow; 612 private boolean mLastContainsDismissKeyguardWindow; 613 private boolean mLastContainsTurnScreenOnWindow; 614 615 /** 616 * A flag to determine if this AR is in the process of closing or entering PIP. This is needed 617 * to help AR know that the app is in the process of closing but hasn't yet started closing on 618 * the WM side. 619 */ 620 private boolean mWillCloseOrEnterPip; 621 622 /** 623 * The scale to fit at least one side of the activity to its parent. If the activity uses 624 * 1920x1080, and the actually size on the screen is 960x540, then the scale is 0.5. 625 */ 626 private float mSizeCompatScale = 1f; 627 /** 628 * The bounds in global coordinates for activity in size compatibility mode. 629 * @see ActivityRecord#hasSizeCompatBounds() 630 */ 631 private Rect mSizeCompatBounds; 632 633 // activity is not displayed? 634 // TODO: rename to mNoDisplay 635 @VisibleForTesting 636 boolean noDisplay; 637 boolean mShowForAllUsers; 638 // TODO: Make this final 639 int mTargetSdk; 640 641 // Is this window's surface needed? This is almost like visible, except 642 // it will sometimes be true a little earlier: when the activity record has 643 // been shown, but is still waiting for its app transition to execute 644 // before making its windows shown. 645 boolean mVisibleRequested; 646 647 // Last visibility state we reported to the app token. 648 boolean reportedVisible; 649 650 boolean mDisablePreviewScreenshots; 651 652 // Information about an application starting window if displayed. 653 // Note: these are de-referenced before the starting window animates away. 654 StartingData mStartingData; 655 WindowState startingWindow; 656 WindowManagerPolicy.StartingSurface startingSurface; 657 boolean startingDisplayed; 658 boolean startingMoved; 659 660 // TODO: Have a WindowContainer state for tracking exiting/deferred removal. 661 boolean mIsExiting; 662 663 boolean mEnteringAnimation; 664 665 boolean mAppStopped; 666 // A hint to override the window specified rotation animation, or -1 to use the window specified 667 // value. We use this so that we can select the right animation in the cases of starting 668 // windows, where the app hasn't had time to set a value on the window. 669 int mRotationAnimationHint = -1; 670 671 ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>(); 672 ArrayDeque<Configuration> mFrozenMergedConfig = new ArrayDeque<>(); 673 674 private AppSaturationInfo mLastAppSaturationInfo; 675 676 private final ColorDisplayService.ColorTransformController mColorTransformController = 677 (matrix, translation) -> mWmService.mH.post(() -> { 678 synchronized (mWmService.mGlobalLock) { 679 if (mLastAppSaturationInfo == null) { 680 mLastAppSaturationInfo = new AppSaturationInfo(); 681 } 682 683 mLastAppSaturationInfo.setSaturation(matrix, translation); 684 updateColorTransform(); 685 } 686 }); 687 688 /** 689 * Current sequencing integer of the configuration, for skipping old activity configurations. 690 */ 691 private int mConfigurationSeq; 692 693 /** 694 * Temp configs used in {@link #ensureActivityConfiguration(int, boolean)} 695 */ 696 private final Configuration mTmpConfig = new Configuration(); 697 private final Rect mTmpBounds = new Rect(); 698 699 // Token for targeting this activity for assist purposes. 700 final Binder assistToken = new Binder(); 701 702 private final Runnable mPauseTimeoutRunnable = new Runnable() { 703 @Override 704 public void run() { 705 // We don't at this point know if the activity is fullscreen, 706 // so we need to be conservative and assume it isn't. 707 Slog.w(TAG, "Activity pause timeout for " + ActivityRecord.this); 708 synchronized (mAtmService.mGlobalLock) { 709 if (hasProcess()) { 710 mAtmService.logAppTooSlow(app, pauseTime, "pausing " + ActivityRecord.this); 711 } 712 activityPaused(true); 713 } 714 } 715 }; 716 717 private final Runnable mLaunchTickRunnable = new Runnable() { 718 @Override 719 public void run() { 720 synchronized (mAtmService.mGlobalLock) { 721 if (continueLaunchTicking()) { 722 mAtmService.logAppTooSlow( 723 app, launchTickTime, "launching " + ActivityRecord.this); 724 } 725 } 726 } 727 }; 728 729 private final Runnable mDestroyTimeoutRunnable = new Runnable() { 730 @Override 731 public void run() { 732 synchronized (mAtmService.mGlobalLock) { 733 Slog.w(TAG, "Activity destroy timeout for " + ActivityRecord.this); 734 destroyed("destroyTimeout"); 735 } 736 } 737 }; 738 739 private final Runnable mStopTimeoutRunnable = new Runnable() { 740 @Override 741 public void run() { 742 synchronized (mAtmService.mGlobalLock) { 743 Slog.w(TAG, "Activity stop timeout for " + ActivityRecord.this); 744 if (isInHistory()) { 745 activityStopped( 746 null /*icicle*/, null /*persistentState*/, null /*description*/); 747 } 748 } 749 } 750 }; 751 startingWindowStateToString(int state)752 private static String startingWindowStateToString(int state) { 753 switch (state) { 754 case STARTING_WINDOW_NOT_SHOWN: 755 return "STARTING_WINDOW_NOT_SHOWN"; 756 case STARTING_WINDOW_SHOWN: 757 return "STARTING_WINDOW_SHOWN"; 758 case STARTING_WINDOW_REMOVED: 759 return "STARTING_WINDOW_REMOVED"; 760 default: 761 return "unknown state=" + state; 762 } 763 } 764 765 @Override dump(PrintWriter pw, String prefix, boolean dumpAll)766 void dump(PrintWriter pw, String prefix, boolean dumpAll) { 767 final long now = SystemClock.uptimeMillis(); 768 pw.print(prefix); pw.print("packageName="); pw.print(packageName); 769 pw.print(" processName="); pw.println(processName); 770 pw.print(prefix); pw.print("launchedFromUid="); pw.print(launchedFromUid); 771 pw.print(" launchedFromPackage="); pw.print(launchedFromPackage); 772 pw.print(" launchedFromFeature="); pw.print(launchedFromFeatureId); 773 pw.print(" userId="); pw.println(mUserId); 774 pw.print(prefix); pw.print("app="); pw.println(app); 775 pw.print(prefix); pw.println(intent.toInsecureString()); 776 pw.print(prefix); pw.print("rootOfTask="); pw.print(isRootOfTask()); 777 pw.print(" task="); pw.println(task); 778 pw.print(prefix); pw.print("taskAffinity="); pw.println(taskAffinity); 779 pw.print(prefix); pw.print("mActivityComponent="); 780 pw.println(mActivityComponent.flattenToShortString()); 781 if (info != null && info.applicationInfo != null) { 782 final ApplicationInfo appInfo = info.applicationInfo; 783 pw.print(prefix); pw.print("baseDir="); pw.println(appInfo.sourceDir); 784 if (!Objects.equals(appInfo.sourceDir, appInfo.publicSourceDir)) { 785 pw.print(prefix); pw.print("resDir="); pw.println(appInfo.publicSourceDir); 786 } 787 pw.print(prefix); pw.print("dataDir="); pw.println(appInfo.dataDir); 788 if (appInfo.splitSourceDirs != null) { 789 pw.print(prefix); pw.print("splitDir="); 790 pw.println(Arrays.toString(appInfo.splitSourceDirs)); 791 } 792 } 793 pw.print(prefix); pw.print("stateNotNeeded="); pw.print(stateNotNeeded); 794 pw.print(" componentSpecified="); pw.print(componentSpecified); 795 pw.print(" mActivityType="); pw.println( 796 activityTypeToString(getActivityType())); 797 if (rootVoiceInteraction) { 798 pw.print(prefix); pw.print("rootVoiceInteraction="); pw.println(rootVoiceInteraction); 799 } 800 pw.print(prefix); pw.print("compat="); pw.print(compat); 801 pw.print(" labelRes=0x"); pw.print(Integer.toHexString(labelRes)); 802 pw.print(" icon=0x"); pw.print(Integer.toHexString(icon)); 803 pw.print(" theme=0x"); pw.println(Integer.toHexString(theme)); 804 pw.println(prefix + "mLastReportedConfigurations:"); 805 mLastReportedConfiguration.dump(pw, prefix + " "); 806 807 pw.print(prefix); pw.print("CurrentConfiguration="); pw.println(getConfiguration()); 808 if (!getRequestedOverrideConfiguration().equals(EMPTY)) { 809 pw.println(prefix + "RequestedOverrideConfiguration=" 810 + getRequestedOverrideConfiguration()); 811 } 812 if (!getResolvedOverrideConfiguration().equals(getRequestedOverrideConfiguration())) { 813 pw.println(prefix + "ResolvedOverrideConfiguration=" 814 + getResolvedOverrideConfiguration()); 815 } 816 if (!matchParentBounds()) { 817 pw.println(prefix + "bounds=" + getBounds()); 818 } 819 if (resultTo != null || resultWho != null) { 820 pw.print(prefix); pw.print("resultTo="); pw.print(resultTo); 821 pw.print(" resultWho="); pw.print(resultWho); 822 pw.print(" resultCode="); pw.println(requestCode); 823 } 824 if (taskDescription != null) { 825 final String iconFilename = taskDescription.getIconFilename(); 826 if (iconFilename != null || taskDescription.getLabel() != null || 827 taskDescription.getPrimaryColor() != 0) { 828 pw.print(prefix); pw.print("taskDescription:"); 829 pw.print(" label=\""); pw.print(taskDescription.getLabel()); 830 pw.print("\""); 831 pw.print(" icon="); pw.print(taskDescription.getInMemoryIcon() != null 832 ? taskDescription.getInMemoryIcon().getByteCount() + " bytes" 833 : "null"); 834 pw.print(" iconResource="); 835 pw.print(taskDescription.getIconResourcePackage()); 836 pw.print("/"); 837 pw.print(taskDescription.getIconResource()); 838 pw.print(" iconFilename="); pw.print(taskDescription.getIconFilename()); 839 pw.print(" primaryColor="); 840 pw.println(Integer.toHexString(taskDescription.getPrimaryColor())); 841 pw.print(prefix); pw.print(" backgroundColor="); 842 pw.print(Integer.toHexString(taskDescription.getBackgroundColor())); 843 pw.print(" statusBarColor="); 844 pw.print(Integer.toHexString(taskDescription.getStatusBarColor())); 845 pw.print(" navigationBarColor="); 846 pw.println(Integer.toHexString(taskDescription.getNavigationBarColor())); 847 } 848 } 849 if (results != null) { 850 pw.print(prefix); pw.print("results="); pw.println(results); 851 } 852 if (pendingResults != null && pendingResults.size() > 0) { 853 pw.print(prefix); pw.println("Pending Results:"); 854 for (WeakReference<PendingIntentRecord> wpir : pendingResults) { 855 PendingIntentRecord pir = wpir != null ? wpir.get() : null; 856 pw.print(prefix); pw.print(" - "); 857 if (pir == null) { 858 pw.println("null"); 859 } else { 860 pw.println(pir); 861 pir.dump(pw, prefix + " "); 862 } 863 } 864 } 865 if (newIntents != null && newIntents.size() > 0) { 866 pw.print(prefix); pw.println("Pending New Intents:"); 867 for (int i=0; i<newIntents.size(); i++) { 868 Intent intent = newIntents.get(i); 869 pw.print(prefix); pw.print(" - "); 870 if (intent == null) { 871 pw.println("null"); 872 } else { 873 pw.println(intent.toShortString(false, true, false, false)); 874 } 875 } 876 } 877 if (pendingOptions != null) { 878 pw.print(prefix); pw.print("pendingOptions="); pw.println(pendingOptions); 879 } 880 if (appTimeTracker != null) { 881 appTimeTracker.dumpWithHeader(pw, prefix, false); 882 } 883 if (uriPermissions != null) { 884 uriPermissions.dump(pw, prefix); 885 } 886 pw.print(prefix); pw.print("launchFailed="); pw.print(launchFailed); 887 pw.print(" launchCount="); pw.print(launchCount); 888 pw.print(" lastLaunchTime="); 889 if (lastLaunchTime == 0) pw.print("0"); 890 else TimeUtils.formatDuration(lastLaunchTime, now, pw); 891 pw.println(); 892 pw.print(prefix); pw.print("mHaveState="); pw.print(mHaveState); 893 pw.print(" mIcicle="); pw.println(mIcicle); 894 pw.print(prefix); pw.print("state="); pw.print(mState); 895 pw.print(" stopped="); pw.print(stopped); 896 pw.print(" delayedResume="); pw.print(delayedResume); 897 pw.print(" finishing="); pw.println(finishing); 898 pw.print(prefix); pw.print("keysPaused="); pw.print(keysPaused); 899 pw.print(" inHistory="); pw.print(inHistory); 900 pw.print(" setToSleep="); pw.print(mSetToSleep); 901 pw.print(" idle="); pw.print(idle); 902 pw.print(" mStartingWindowState="); 903 pw.println(startingWindowStateToString(mStartingWindowState)); 904 pw.print(prefix); pw.print("occludesParent="); pw.print(occludesParent()); 905 pw.print(" noDisplay="); pw.print(noDisplay); 906 pw.print(" immersive="); pw.print(immersive); 907 pw.print(" launchMode="); pw.println(launchMode); 908 pw.print(prefix); pw.print("frozenBeforeDestroy="); pw.print(frozenBeforeDestroy); 909 pw.print(" forceNewConfig="); pw.println(forceNewConfig); 910 pw.print(prefix); pw.print("mActivityType="); 911 pw.println(activityTypeToString(getActivityType())); 912 if (requestedVrComponent != null) { 913 pw.print(prefix); 914 pw.print("requestedVrComponent="); 915 pw.println(requestedVrComponent); 916 } 917 super.dump(pw, prefix, dumpAll); 918 if (mVoiceInteraction) { 919 pw.println(prefix + "mVoiceInteraction=true"); 920 } 921 pw.print(prefix); pw.print("mOccludesParent="); pw.print(mOccludesParent); 922 pw.print(" mOrientation="); pw.println(mOrientation); 923 pw.println(prefix + "mVisibleRequested=" + mVisibleRequested 924 + " mVisible=" + mVisible + " mClientVisible=" + mClientVisible 925 + ((mDeferHidingClient) ? " mDeferHidingClient=" + mDeferHidingClient : "") 926 + " reportedDrawn=" + reportedDrawn + " reportedVisible=" + reportedVisible); 927 if (paused) { 928 pw.print(prefix); pw.print("paused="); pw.println(paused); 929 } 930 if (mAppStopped) { 931 pw.print(prefix); pw.print("mAppStopped="); pw.println(mAppStopped); 932 } 933 if (mNumInterestingWindows != 0 || mNumDrawnWindows != 0 934 || allDrawn || mLastAllDrawn) { 935 pw.print(prefix); pw.print("mNumInterestingWindows="); 936 pw.print(mNumInterestingWindows); 937 pw.print(" mNumDrawnWindows="); pw.print(mNumDrawnWindows); 938 pw.print(" allDrawn="); pw.print(allDrawn); 939 pw.print(" lastAllDrawn="); pw.print(mLastAllDrawn); 940 pw.println(")"); 941 } 942 if (mStartingData != null || firstWindowDrawn || mIsExiting) { 943 pw.print(prefix); pw.print("startingData="); pw.print(mStartingData); 944 pw.print(" firstWindowDrawn="); pw.print(firstWindowDrawn); 945 pw.print(" mIsExiting="); pw.println(mIsExiting); 946 } 947 if (startingWindow != null || startingSurface != null 948 || startingDisplayed || startingMoved || mVisibleSetFromTransferredStartingWindow) { 949 pw.print(prefix); pw.print("startingWindow="); pw.print(startingWindow); 950 pw.print(" startingSurface="); pw.print(startingSurface); 951 pw.print(" startingDisplayed="); pw.print(startingDisplayed); 952 pw.print(" startingMoved="); pw.print(startingMoved); 953 pw.println(" mHiddenSetFromTransferredStartingWindow=" 954 + mVisibleSetFromTransferredStartingWindow); 955 } 956 if (!mFrozenBounds.isEmpty()) { 957 pw.print(prefix); pw.print("mFrozenBounds="); pw.println(mFrozenBounds); 958 pw.print(prefix); pw.print("mFrozenMergedConfig="); pw.println(mFrozenMergedConfig); 959 } 960 if (mPendingRelaunchCount != 0) { 961 pw.print(prefix); pw.print("mPendingRelaunchCount="); pw.println(mPendingRelaunchCount); 962 } 963 if (mSizeCompatScale != 1f || mSizeCompatBounds != null) { 964 pw.println(prefix + "mSizeCompatScale=" + mSizeCompatScale + " mSizeCompatBounds=" 965 + mSizeCompatBounds); 966 } 967 if (mRemovingFromDisplay) { 968 pw.println(prefix + "mRemovingFromDisplay=" + mRemovingFromDisplay); 969 } 970 if (lastVisibleTime != 0 || nowVisible) { 971 pw.print(prefix); pw.print("nowVisible="); pw.print(nowVisible); 972 pw.print(" lastVisibleTime="); 973 if (lastVisibleTime == 0) pw.print("0"); 974 else TimeUtils.formatDuration(lastVisibleTime, now, pw); 975 pw.println(); 976 } 977 if (mDeferHidingClient) { 978 pw.println(prefix + "mDeferHidingClient=" + mDeferHidingClient); 979 } 980 if (deferRelaunchUntilPaused || configChangeFlags != 0) { 981 pw.print(prefix); pw.print("deferRelaunchUntilPaused="); 982 pw.print(deferRelaunchUntilPaused); 983 pw.print(" configChangeFlags="); 984 pw.println(Integer.toHexString(configChangeFlags)); 985 } 986 if (mServiceConnectionsHolder != null) { 987 pw.print(prefix); pw.print("connections="); pw.println(mServiceConnectionsHolder); 988 } 989 if (info != null) { 990 pw.println(prefix + "resizeMode=" + ActivityInfo.resizeModeToString(info.resizeMode)); 991 pw.println(prefix + "mLastReportedMultiWindowMode=" + mLastReportedMultiWindowMode 992 + " mLastReportedPictureInPictureMode=" + mLastReportedPictureInPictureMode); 993 if (info.supportsPictureInPicture()) { 994 pw.println(prefix + "supportsPictureInPicture=" + info.supportsPictureInPicture()); 995 pw.println(prefix + "supportsEnterPipOnTaskSwitch: " 996 + supportsEnterPipOnTaskSwitch); 997 } 998 if (info.maxAspectRatio != 0) { 999 pw.println(prefix + "maxAspectRatio=" + info.maxAspectRatio); 1000 } 1001 if (info.minAspectRatio != 0) { 1002 pw.println(prefix + "minAspectRatio=" + info.minAspectRatio); 1003 } 1004 if (info.supportsSizeChanges) { 1005 pw.println(prefix + "supportsSizeChanges=true"); 1006 } 1007 } 1008 } 1009 setAppTimeTracker(AppTimeTracker att)1010 void setAppTimeTracker(AppTimeTracker att) { 1011 appTimeTracker = att; 1012 } 1013 1014 /** Update the saved state of an activity. */ setSavedState(@ullable Bundle savedState)1015 void setSavedState(@Nullable Bundle savedState) { 1016 mIcicle = savedState; 1017 mHaveState = mIcicle != null; 1018 } 1019 1020 /** 1021 * Get the actual Bundle instance of the saved state. 1022 * @see #hasSavedState() for checking if the record has saved state. 1023 */ getSavedState()1024 @Nullable Bundle getSavedState() { 1025 return mIcicle; 1026 } 1027 1028 /** 1029 * Check if the activity has saved state. 1030 * @return {@code true} if the client reported a non-empty saved state from last onStop(), or 1031 * if this record was just created and the client is yet to be launched and resumed. 1032 */ hasSavedState()1033 boolean hasSavedState() { 1034 return mHaveState; 1035 } 1036 1037 /** @return The actual PersistableBundle instance of the saved persistent state. */ getPersistentSavedState()1038 @Nullable PersistableBundle getPersistentSavedState() { 1039 return mPersistentState; 1040 } 1041 updateApplicationInfo(ApplicationInfo aInfo)1042 void updateApplicationInfo(ApplicationInfo aInfo) { 1043 info.applicationInfo = aInfo; 1044 } 1045 crossesHorizontalSizeThreshold(int firstDp, int secondDp)1046 private boolean crossesHorizontalSizeThreshold(int firstDp, int secondDp) { 1047 return crossesSizeThreshold(mHorizontalSizeConfigurations, firstDp, secondDp); 1048 } 1049 crossesVerticalSizeThreshold(int firstDp, int secondDp)1050 private boolean crossesVerticalSizeThreshold(int firstDp, int secondDp) { 1051 return crossesSizeThreshold(mVerticalSizeConfigurations, firstDp, secondDp); 1052 } 1053 crossesSmallestSizeThreshold(int firstDp, int secondDp)1054 private boolean crossesSmallestSizeThreshold(int firstDp, int secondDp) { 1055 return crossesSizeThreshold(mSmallestSizeConfigurations, firstDp, secondDp); 1056 } 1057 1058 /** 1059 * The purpose of this method is to decide whether the activity needs to be relaunched upon 1060 * changing its size. In most cases the activities don't need to be relaunched, if the resize 1061 * is small, all the activity content has to do is relayout itself within new bounds. There are 1062 * cases however, where the activity's content would be completely changed in the new size and 1063 * the full relaunch is required. 1064 * 1065 * The activity will report to us vertical and horizontal thresholds after which a relaunch is 1066 * required. These thresholds are collected from the application resource qualifiers. For 1067 * example, if application has layout-w600dp resource directory, then it needs a relaunch when 1068 * we resize from width of 650dp to 550dp, as it crosses the 600dp threshold. However, if 1069 * it resizes width from 620dp to 700dp, it won't be relaunched as it stays on the same side 1070 * of the threshold. 1071 */ crossesSizeThreshold(int[] thresholds, int firstDp, int secondDp)1072 private static boolean crossesSizeThreshold(int[] thresholds, int firstDp, 1073 int secondDp) { 1074 if (thresholds == null) { 1075 return false; 1076 } 1077 for (int i = thresholds.length - 1; i >= 0; i--) { 1078 final int threshold = thresholds[i]; 1079 if ((firstDp < threshold && secondDp >= threshold) 1080 || (firstDp >= threshold && secondDp < threshold)) { 1081 return true; 1082 } 1083 } 1084 return false; 1085 } 1086 setSizeConfigurations(int[] horizontalSizeConfiguration, int[] verticalSizeConfigurations, int[] smallestSizeConfigurations)1087 void setSizeConfigurations(int[] horizontalSizeConfiguration, 1088 int[] verticalSizeConfigurations, int[] smallestSizeConfigurations) { 1089 mHorizontalSizeConfigurations = horizontalSizeConfiguration; 1090 mVerticalSizeConfigurations = verticalSizeConfigurations; 1091 mSmallestSizeConfigurations = smallestSizeConfigurations; 1092 } 1093 scheduleActivityMovedToDisplay(int displayId, Configuration config)1094 private void scheduleActivityMovedToDisplay(int displayId, Configuration config) { 1095 if (!attachedToProcess()) { 1096 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.w(TAG, 1097 "Can't report activity moved to display - client not running, activityRecord=" 1098 + this + ", displayId=" + displayId); 1099 return; 1100 } 1101 try { 1102 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG, 1103 "Reporting activity moved to display" + ", activityRecord=" + this 1104 + ", displayId=" + displayId + ", config=" + config); 1105 1106 mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, 1107 MoveToDisplayItem.obtain(displayId, config)); 1108 } catch (RemoteException e) { 1109 // If process died, whatever. 1110 } 1111 } 1112 scheduleConfigurationChanged(Configuration config)1113 private void scheduleConfigurationChanged(Configuration config) { 1114 if (!attachedToProcess()) { 1115 if (DEBUG_CONFIGURATION) Slog.w(TAG, 1116 "Can't report activity configuration update - client not running" 1117 + ", activityRecord=" + this); 1118 return; 1119 } 1120 try { 1121 if (DEBUG_CONFIGURATION) Slog.v(TAG, "Sending new config to " + this + ", config: " 1122 + config); 1123 1124 mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, 1125 ActivityConfigurationChangeItem.obtain(config)); 1126 } catch (RemoteException e) { 1127 // If process died, whatever. 1128 } 1129 } 1130 scheduleTopResumedActivityChanged(boolean onTop)1131 boolean scheduleTopResumedActivityChanged(boolean onTop) { 1132 if (!attachedToProcess()) { 1133 if (DEBUG_STATES) { 1134 Slog.w(TAG, "Can't report activity position update - client not running" 1135 + ", activityRecord=" + this); 1136 } 1137 return false; 1138 } 1139 try { 1140 if (DEBUG_STATES) { 1141 Slog.v(TAG, "Sending position change to " + this + ", onTop: " + onTop); 1142 } 1143 1144 mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, 1145 TopResumedActivityChangeItem.obtain(onTop)); 1146 } catch (RemoteException e) { 1147 // If process died, whatever. 1148 return false; 1149 } 1150 return true; 1151 } 1152 updateMultiWindowMode()1153 void updateMultiWindowMode() { 1154 if (task == null || task.getStack() == null || !attachedToProcess()) { 1155 return; 1156 } 1157 1158 // An activity is considered to be in multi-window mode if its task isn't fullscreen. 1159 final boolean inMultiWindowMode = inMultiWindowMode(); 1160 if (inMultiWindowMode != mLastReportedMultiWindowMode) { 1161 if (!inMultiWindowMode && mLastReportedPictureInPictureMode) { 1162 updatePictureInPictureMode(null, false); 1163 } else { 1164 mLastReportedMultiWindowMode = inMultiWindowMode; 1165 computeConfigurationAfterMultiWindowModeChange(); 1166 // If the activity is in stopping or stopped state, for instance, it's in the 1167 // split screen task and not the top one, the last configuration it should keep 1168 // is the one before multi-window mode change. 1169 final ActivityState state = getState(); 1170 if (state != STOPPED && state != STOPPING) { 1171 ensureActivityConfiguration(0 /* globalChanges */, PRESERVE_WINDOWS, 1172 true /* ignoreVisibility */); 1173 } 1174 } 1175 } 1176 } 1177 updatePictureInPictureMode(Rect targetStackBounds, boolean forceUpdate)1178 void updatePictureInPictureMode(Rect targetStackBounds, boolean forceUpdate) { 1179 if (task == null || task.getStack() == null || !attachedToProcess()) { 1180 return; 1181 } 1182 1183 final boolean inPictureInPictureMode = inPinnedWindowingMode() && targetStackBounds != null; 1184 if (inPictureInPictureMode != mLastReportedPictureInPictureMode || forceUpdate) { 1185 // Picture-in-picture mode changes also trigger a multi-window mode change as well, so 1186 // update that here in order. Set the last reported MW state to the same as the PiP 1187 // state since we haven't yet actually resized the task (these callbacks need to 1188 // precede the configuration change from the resize. 1189 mLastReportedPictureInPictureMode = inPictureInPictureMode; 1190 mLastReportedMultiWindowMode = inPictureInPictureMode; 1191 if (targetStackBounds != null && !targetStackBounds.isEmpty()) { 1192 computeConfigurationAfterMultiWindowModeChange(); 1193 } 1194 ensureActivityConfiguration(0 /* globalChanges */, PRESERVE_WINDOWS, 1195 true /* ignoreVisibility */); 1196 } 1197 } 1198 computeConfigurationAfterMultiWindowModeChange()1199 private void computeConfigurationAfterMultiWindowModeChange() { 1200 final Configuration newConfig = new Configuration(); 1201 newConfig.setTo(task.getRequestedOverrideConfiguration()); 1202 Rect outBounds = newConfig.windowConfiguration.getBounds(); 1203 final Configuration parentConfig = task.getParent().getConfiguration(); 1204 task.adjustForMinimalTaskDimensions(outBounds, outBounds, parentConfig); 1205 task.computeConfigResourceOverrides(newConfig, parentConfig); 1206 } 1207 getTask()1208 Task getTask() { 1209 return task; 1210 } 1211 1212 /** 1213 * Sets the Task on this activity for the purposes of re-use during launch where we will 1214 * re-use another activity instead of this one for the launch. 1215 */ setTaskForReuse(Task task)1216 void setTaskForReuse(Task task) { 1217 this.task = task; 1218 } 1219 getStack()1220 ActivityStack getStack() { 1221 return task != null ? task.getStack() : null; 1222 } 1223 1224 @Override onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent)1225 void onParentChanged(ConfigurationContainer newParent, ConfigurationContainer oldParent) { 1226 final Task oldTask = oldParent != null ? (Task) oldParent : null; 1227 final Task newTask = newParent != null ? (Task) newParent : null; 1228 this.task = newTask; 1229 1230 super.onParentChanged(newParent, oldParent); 1231 1232 if (isPersistable()) { 1233 if (oldTask != null) { 1234 mAtmService.notifyTaskPersisterLocked(oldTask, false); 1235 } 1236 if (newTask != null) { 1237 mAtmService.notifyTaskPersisterLocked(newTask, false); 1238 } 1239 } 1240 1241 if (oldParent == null && newParent != null) { 1242 // First time we are adding the activity to the system. 1243 mVoiceInteraction = newTask.voiceSession != null; 1244 mInputDispatchingTimeoutNanos = getInputDispatchingTimeoutLocked(this) * 1000000L; 1245 1246 // TODO(b/36505427): Maybe this call should be moved inside 1247 // updateOverrideConfiguration() 1248 newTask.updateOverrideConfigurationFromLaunchBounds(); 1249 // Make sure override configuration is up-to-date before using to create window 1250 // controller. 1251 updateSizeCompatMode(); 1252 // When an activity is started directly into a split-screen fullscreen stack, we need to 1253 // update the initial multi-window modes so that the callbacks are scheduled correctly 1254 // when the user leaves that mode. 1255 mLastReportedMultiWindowMode = inMultiWindowMode(); 1256 mLastReportedPictureInPictureMode = inPinnedWindowingMode(); 1257 } 1258 1259 // When the associated task is {@code null}, the {@link ActivityRecord} can no longer 1260 // access visual elements like the {@link DisplayContent}. We must remove any associations 1261 // such as animations. 1262 if (task == null) { 1263 // It is possible we have been marked as a closing app earlier. We must remove ourselves 1264 // from this list so we do not participate in any future animations. 1265 if (getDisplayContent() != null) { 1266 getDisplayContent().mClosingApps.remove(this); 1267 } 1268 } else if (mLastParent != null && mLastParent.getStack() != null) { 1269 task.getStack().mExitingActivities.remove(this); 1270 } 1271 final ActivityStack stack = getStack(); 1272 1273 // If we reparent, make sure to remove ourselves from the old animation registry. 1274 if (mAnimatingActivityRegistry != null) { 1275 mAnimatingActivityRegistry.notifyFinished(this); 1276 } 1277 mAnimatingActivityRegistry = stack != null 1278 ? stack.getAnimatingActivityRegistry() 1279 : null; 1280 1281 mLastParent = task; 1282 1283 updateColorTransform(); 1284 1285 if (oldTask != null) { 1286 oldTask.cleanUpActivityReferences(this); 1287 } 1288 if (newTask != null && isState(RESUMED)) { 1289 newTask.setResumedActivity(this, "onParentChanged"); 1290 } 1291 1292 if (stack != null && stack.topRunningActivity() == this) { 1293 // make ensure the TaskOrganizer still works after re-parenting 1294 if (firstWindowDrawn) { 1295 stack.setHasBeenVisible(true); 1296 } 1297 } 1298 } 1299 updateColorTransform()1300 private void updateColorTransform() { 1301 if (mSurfaceControl != null && mLastAppSaturationInfo != null) { 1302 getPendingTransaction().setColorTransform(mSurfaceControl, 1303 mLastAppSaturationInfo.mMatrix, mLastAppSaturationInfo.mTranslation); 1304 mWmService.scheduleAnimationLocked(); 1305 } 1306 } 1307 1308 @Override onDisplayChanged(DisplayContent dc)1309 void onDisplayChanged(DisplayContent dc) { 1310 DisplayContent prevDc = mDisplayContent; 1311 super.onDisplayChanged(dc); 1312 if (prevDc == null || prevDc == mDisplayContent) { 1313 return; 1314 } 1315 1316 if (prevDc.mOpeningApps.remove(this)) { 1317 // Transfer opening transition to new display. 1318 mDisplayContent.mOpeningApps.add(this); 1319 mDisplayContent.prepareAppTransition(prevDc.mAppTransition.getAppTransition(), true); 1320 mDisplayContent.executeAppTransition(); 1321 } 1322 1323 prevDc.mClosingApps.remove(this); 1324 1325 if (prevDc.mFocusedApp == this) { 1326 prevDc.setFocusedApp(null); 1327 if (dc.getTopMostActivity() == this) { 1328 dc.setFocusedApp(this); 1329 } 1330 } 1331 1332 if (mLetterbox != null) { 1333 mLetterbox.onMovedToDisplay(mDisplayContent.getDisplayId()); 1334 } 1335 } 1336 layoutLetterbox(WindowState winHint)1337 void layoutLetterbox(WindowState winHint) { 1338 final WindowState w = findMainWindow(); 1339 if (w == null || winHint != null && w != winHint) { 1340 return; 1341 } 1342 final boolean surfaceReady = w.isDrawnLw() // Regular case 1343 || w.mWinAnimator.mSurfaceDestroyDeferred // The preserved surface is still ready. 1344 || w.isDragResizeChanged(); // Waiting for relayoutWindow to call preserveSurface. 1345 final boolean needsLetterbox = surfaceReady && w.isLetterboxedAppWindow() && fillsParent(); 1346 if (needsLetterbox) { 1347 if (mLetterbox == null) { 1348 mLetterbox = new Letterbox(() -> makeChildSurface(null), 1349 mWmService.mTransactionFactory); 1350 mLetterbox.attachInput(w); 1351 } 1352 getPosition(mTmpPoint); 1353 // Get the bounds of the "space-to-fill". The transformed bounds have the highest 1354 // priority because the activity is launched in a rotated environment. In multi-window 1355 // mode, the task-level represents this. In fullscreen-mode, the task container does 1356 // (since the orientation letterbox is also applied to the task). 1357 final Rect transformedBounds = getFixedRotationTransformDisplayBounds(); 1358 final Rect spaceToFill = transformedBounds != null 1359 ? transformedBounds 1360 : inMultiWindowMode() 1361 ? task.getBounds() 1362 : getRootTask().getParent().getBounds(); 1363 mLetterbox.layout(spaceToFill, w.getFrameLw(), mTmpPoint); 1364 } else if (mLetterbox != null) { 1365 mLetterbox.hide(); 1366 } 1367 } 1368 updateLetterboxSurface(WindowState winHint)1369 void updateLetterboxSurface(WindowState winHint) { 1370 final WindowState w = findMainWindow(); 1371 if (w != winHint && winHint != null && w != null) { 1372 return; 1373 } 1374 layoutLetterbox(winHint); 1375 if (mLetterbox != null && mLetterbox.needsApplySurfaceChanges()) { 1376 mLetterbox.applySurfaceChanges(getPendingTransaction()); 1377 } 1378 } 1379 getLetterboxInsets()1380 Rect getLetterboxInsets() { 1381 if (mLetterbox != null) { 1382 return mLetterbox.getInsets(); 1383 } else { 1384 return new Rect(); 1385 } 1386 } 1387 1388 /** Gets the inner bounds of letterbox. The bounds will be empty if there is no letterbox. */ getLetterboxInnerBounds(Rect outBounds)1389 void getLetterboxInnerBounds(Rect outBounds) { 1390 if (mLetterbox != null) { 1391 outBounds.set(mLetterbox.getInnerFrame()); 1392 } else { 1393 outBounds.setEmpty(); 1394 } 1395 } 1396 1397 /** 1398 * @see Letterbox#notIntersectsOrFullyContains(Rect) 1399 */ letterboxNotIntersectsOrFullyContains(Rect rect)1400 boolean letterboxNotIntersectsOrFullyContains(Rect rect) { 1401 return mLetterbox == null || mLetterbox.notIntersectsOrFullyContains(rect); 1402 } 1403 1404 /** 1405 * @return {@code true} if there is a letterbox and any part of that letterbox overlaps with 1406 * the given {@code rect}. 1407 */ isLetterboxOverlappingWith(Rect rect)1408 boolean isLetterboxOverlappingWith(Rect rect) { 1409 return mLetterbox != null && mLetterbox.isOverlappingWith(rect); 1410 } 1411 1412 static class Token extends IApplicationToken.Stub { 1413 private WeakReference<ActivityRecord> weakActivity; 1414 private final String name; 1415 private final String tokenString; 1416 Token(Intent intent)1417 Token(Intent intent) { 1418 name = intent.getComponent().flattenToShortString(); 1419 tokenString = "Token{" + Integer.toHexString(System.identityHashCode(this)) + "}"; 1420 } 1421 attach(ActivityRecord activity)1422 private void attach(ActivityRecord activity) { 1423 if (weakActivity != null) { 1424 throw new IllegalStateException("Already attached..." + this); 1425 } 1426 weakActivity = new WeakReference<>(activity); 1427 } 1428 tokenToActivityRecordLocked(Token token)1429 private static @Nullable ActivityRecord tokenToActivityRecordLocked(Token token) { 1430 if (token == null) { 1431 return null; 1432 } 1433 ActivityRecord r = token.weakActivity.get(); 1434 if (r == null || r.getRootTask() == null) { 1435 return null; 1436 } 1437 return r; 1438 } 1439 1440 @Override toString()1441 public String toString() { 1442 StringBuilder sb = new StringBuilder(128); 1443 sb.append("Token{"); 1444 sb.append(Integer.toHexString(System.identityHashCode(this))); 1445 sb.append(' '); 1446 if (weakActivity != null) { 1447 sb.append(weakActivity.get()); 1448 } 1449 sb.append('}'); 1450 return sb.toString(); 1451 } 1452 1453 @Override getName()1454 public String getName() { 1455 return name; 1456 } 1457 } 1458 forTokenLocked(IBinder token)1459 static @Nullable ActivityRecord forTokenLocked(IBinder token) { 1460 try { 1461 return Token.tokenToActivityRecordLocked((Token)token); 1462 } catch (ClassCastException e) { 1463 Slog.w(TAG, "Bad activity token: " + token, e); 1464 return null; 1465 } 1466 } 1467 isResolverActivity(String className)1468 static boolean isResolverActivity(String className) { 1469 return ResolverActivity.class.getName().equals(className); 1470 } 1471 isResolverOrDelegateActivity()1472 boolean isResolverOrDelegateActivity() { 1473 return isResolverActivity(mActivityComponent.getClassName()) || Objects.equals( 1474 mActivityComponent, mAtmService.mStackSupervisor.getSystemChooserActivity()); 1475 } 1476 isResolverOrChildActivity()1477 boolean isResolverOrChildActivity() { 1478 if (!"android".equals(packageName)) { 1479 return false; 1480 } 1481 try { 1482 return ResolverActivity.class.isAssignableFrom( 1483 Object.class.getClassLoader().loadClass(mActivityComponent.getClassName())); 1484 } catch (ClassNotFoundException e) { 1485 return false; 1486 } 1487 } 1488 ActivityRecord(ActivityTaskManagerService _service, WindowProcessController _caller, int _launchedFromPid, int _launchedFromUid, String _launchedFromPackage, @Nullable String _launchedFromFeature, Intent _intent, String _resolvedType, ActivityInfo aInfo, Configuration _configuration, ActivityRecord _resultTo, String _resultWho, int _reqCode, boolean _componentSpecified, boolean _rootVoiceInteraction, ActivityStackSupervisor supervisor, ActivityOptions options, ActivityRecord sourceRecord)1489 ActivityRecord(ActivityTaskManagerService _service, WindowProcessController _caller, 1490 int _launchedFromPid, int _launchedFromUid, String _launchedFromPackage, 1491 @Nullable String _launchedFromFeature, Intent _intent, String _resolvedType, 1492 ActivityInfo aInfo, Configuration _configuration, ActivityRecord _resultTo, 1493 String _resultWho, int _reqCode, boolean _componentSpecified, 1494 boolean _rootVoiceInteraction, ActivityStackSupervisor supervisor, 1495 ActivityOptions options, ActivityRecord sourceRecord) { 1496 super(_service.mWindowManager, new Token(_intent).asBinder(), TYPE_APPLICATION, true, 1497 null /* displayContent */, false /* ownerCanManageAppTokens */); 1498 1499 mAtmService = _service; 1500 appToken = (Token) token; 1501 info = aInfo; 1502 mUserId = UserHandle.getUserId(info.applicationInfo.uid); 1503 packageName = info.applicationInfo.packageName; 1504 intent = _intent; 1505 1506 // If the class name in the intent doesn't match that of the target, this is probably an 1507 // alias. We have to create a new ComponentName object to keep track of the real activity 1508 // name, so that FLAG_ACTIVITY_CLEAR_TOP is handled properly. 1509 if (info.targetActivity == null 1510 || (info.targetActivity.equals(intent.getComponent().getClassName()) 1511 && (info.launchMode == LAUNCH_MULTIPLE 1512 || info.launchMode == LAUNCH_SINGLE_TOP))) { 1513 mActivityComponent = intent.getComponent(); 1514 } else { 1515 mActivityComponent = 1516 new ComponentName(info.packageName, info.targetActivity); 1517 } 1518 1519 mTargetSdk = info.applicationInfo.targetSdkVersion; 1520 mShowForAllUsers = (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0; 1521 setOrientation(info.screenOrientation); 1522 mRotationAnimationHint = info.rotationAnimation; 1523 1524 mShowWhenLocked = (aInfo.flags & ActivityInfo.FLAG_SHOW_WHEN_LOCKED) != 0; 1525 mInheritShownWhenLocked = (aInfo.privateFlags & FLAG_INHERIT_SHOW_WHEN_LOCKED) != 0; 1526 mTurnScreenOn = (aInfo.flags & FLAG_TURN_SCREEN_ON) != 0; 1527 1528 int realTheme = info.getThemeResource(); 1529 if (realTheme == Resources.ID_NULL) { 1530 realTheme = aInfo.applicationInfo.targetSdkVersion < HONEYCOMB 1531 ? android.R.style.Theme : android.R.style.Theme_Holo; 1532 } 1533 1534 final AttributeCache.Entry ent = AttributeCache.instance().get(packageName, 1535 realTheme, com.android.internal.R.styleable.Window, mUserId); 1536 1537 if (ent != null) { 1538 mOccludesParent = !ActivityInfo.isTranslucentOrFloating(ent.array); 1539 hasWallpaper = ent.array.getBoolean(R.styleable.Window_windowShowWallpaper, false); 1540 noDisplay = ent.array.getBoolean(R.styleable.Window_windowNoDisplay, false); 1541 } else { 1542 hasWallpaper = false; 1543 noDisplay = false; 1544 } 1545 1546 if (options != null) { 1547 mLaunchTaskBehind = options.getLaunchTaskBehind(); 1548 1549 final int rotationAnimation = options.getRotationAnimationHint(); 1550 // Only override manifest supplied option if set. 1551 if (rotationAnimation >= 0) { 1552 mRotationAnimationHint = rotationAnimation; 1553 } 1554 } 1555 1556 // Application tokens start out hidden. 1557 setVisible(false); 1558 mVisibleRequested = false; 1559 1560 ColorDisplayService.ColorDisplayServiceInternal cds = LocalServices.getService( 1561 ColorDisplayService.ColorDisplayServiceInternal.class); 1562 cds.attachColorTransformController(packageName, mUserId, 1563 new WeakReference<>(mColorTransformController)); 1564 1565 appToken.attach(this); 1566 1567 mRootWindowContainer = _service.mRootWindowContainer; 1568 launchedFromPid = _launchedFromPid; 1569 launchedFromUid = _launchedFromUid; 1570 launchedFromPackage = _launchedFromPackage; 1571 launchedFromFeatureId = _launchedFromFeature; 1572 shortComponentName = _intent.getComponent().flattenToShortString(); 1573 resolvedType = _resolvedType; 1574 componentSpecified = _componentSpecified; 1575 rootVoiceInteraction = _rootVoiceInteraction; 1576 mLastReportedConfiguration = new MergedConfiguration(_configuration); 1577 resultTo = _resultTo; 1578 resultWho = _resultWho; 1579 requestCode = _reqCode; 1580 setState(INITIALIZING, "ActivityRecord ctor"); 1581 launchFailed = false; 1582 stopped = false; 1583 delayedResume = false; 1584 finishing = false; 1585 deferRelaunchUntilPaused = false; 1586 keysPaused = false; 1587 inHistory = false; 1588 nowVisible = false; 1589 mDrawn = false; 1590 mClientVisible = true; 1591 idle = false; 1592 hasBeenLaunched = false; 1593 mStackSupervisor = supervisor; 1594 1595 info.taskAffinity = getTaskAffinityWithUid(info.taskAffinity, info.applicationInfo.uid); 1596 taskAffinity = info.taskAffinity; 1597 final String uid = Integer.toString(info.applicationInfo.uid); 1598 if (info.windowLayout != null && info.windowLayout.windowLayoutAffinity != null 1599 && !info.windowLayout.windowLayoutAffinity.startsWith(uid)) { 1600 info.windowLayout.windowLayoutAffinity = 1601 uid + ":" + info.windowLayout.windowLayoutAffinity; 1602 } 1603 stateNotNeeded = (aInfo.flags & FLAG_STATE_NOT_NEEDED) != 0; 1604 nonLocalizedLabel = aInfo.nonLocalizedLabel; 1605 labelRes = aInfo.labelRes; 1606 if (nonLocalizedLabel == null && labelRes == 0) { 1607 ApplicationInfo app = aInfo.applicationInfo; 1608 nonLocalizedLabel = app.nonLocalizedLabel; 1609 labelRes = app.labelRes; 1610 } 1611 icon = aInfo.getIconResource(); 1612 logo = aInfo.getLogoResource(); 1613 theme = aInfo.getThemeResource(); 1614 if ((aInfo.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0) { 1615 windowFlags |= LayoutParams.FLAG_HARDWARE_ACCELERATED; 1616 } 1617 if ((aInfo.flags & FLAG_MULTIPROCESS) != 0 && _caller != null 1618 && (aInfo.applicationInfo.uid == SYSTEM_UID 1619 || aInfo.applicationInfo.uid == _caller.mInfo.uid)) { 1620 processName = _caller.mName; 1621 } else { 1622 processName = aInfo.processName; 1623 } 1624 1625 if ((aInfo.flags & FLAG_EXCLUDE_FROM_RECENTS) != 0) { 1626 intent.addFlags(FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); 1627 } 1628 1629 launchMode = aInfo.launchMode; 1630 1631 setActivityType(_componentSpecified, _launchedFromUid, _intent, options, sourceRecord); 1632 1633 immersive = (aInfo.flags & FLAG_IMMERSIVE) != 0; 1634 1635 requestedVrComponent = (aInfo.requestedVrComponent == null) ? 1636 null : ComponentName.unflattenFromString(aInfo.requestedVrComponent); 1637 1638 lockTaskLaunchMode = getLockTaskLaunchMode(aInfo, options); 1639 1640 if (options != null) { 1641 pendingOptions = options; 1642 final PendingIntent usageReport = pendingOptions.getUsageTimeReport(); 1643 if (usageReport != null) { 1644 appTimeTracker = new AppTimeTracker(usageReport); 1645 } 1646 // Gets launch task display area and display id from options. Returns 1647 // null/INVALID_DISPLAY if not set. 1648 final WindowContainerToken daToken = options.getLaunchTaskDisplayArea(); 1649 mHandoverTaskDisplayArea = daToken != null 1650 ? (TaskDisplayArea) WindowContainer.fromBinder(daToken.asBinder()) : null; 1651 mHandoverLaunchDisplayId = options.getLaunchDisplayId(); 1652 } 1653 } 1654 1655 /** 1656 * Generate the task affinity with uid. For b/35954083, Limit task affinity to uid to avoid 1657 * issues associated with sharing affinity across uids. 1658 * 1659 * @param affinity The affinity of the activity. 1660 * @param uid The user-ID that has been assigned to this application. 1661 * @return The task affinity with uid. 1662 */ getTaskAffinityWithUid(String affinity, int uid)1663 static String getTaskAffinityWithUid(String affinity, int uid) { 1664 final String uidStr = Integer.toString(uid); 1665 if (affinity != null && !affinity.startsWith(uidStr)) { 1666 affinity = uidStr + ":" + affinity; 1667 } 1668 return affinity; 1669 } 1670 getLockTaskLaunchMode(ActivityInfo aInfo, @Nullable ActivityOptions options)1671 static int getLockTaskLaunchMode(ActivityInfo aInfo, @Nullable ActivityOptions options) { 1672 int lockTaskLaunchMode = aInfo.lockTaskLaunchMode; 1673 // Non-priv apps are not allowed to use always or never, fall back to default 1674 if (!aInfo.applicationInfo.isPrivilegedApp() 1675 && (lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_ALWAYS 1676 || lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_NEVER)) { 1677 lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_DEFAULT; 1678 } 1679 if (options != null) { 1680 final boolean useLockTask = options.getLockTaskMode(); 1681 if (useLockTask && lockTaskLaunchMode == LOCK_TASK_LAUNCH_MODE_DEFAULT) { 1682 lockTaskLaunchMode = LOCK_TASK_LAUNCH_MODE_IF_ALLOWLISTED; 1683 } 1684 } 1685 return lockTaskLaunchMode; 1686 } 1687 getInputApplicationHandle(boolean update)1688 @NonNull InputApplicationHandle getInputApplicationHandle(boolean update) { 1689 if (mInputApplicationHandle == null) { 1690 mInputApplicationHandle = new InputApplicationHandle(appToken, toString(), 1691 mInputDispatchingTimeoutNanos); 1692 } else if (update) { 1693 final String name = toString(); 1694 if (mInputDispatchingTimeoutNanos != mInputApplicationHandle.dispatchingTimeoutNanos 1695 || !name.equals(mInputApplicationHandle.name)) { 1696 mInputApplicationHandle = new InputApplicationHandle(appToken, name, 1697 mInputDispatchingTimeoutNanos); 1698 } 1699 } 1700 return mInputApplicationHandle; 1701 } 1702 1703 @Override asActivityRecord()1704 ActivityRecord asActivityRecord() { 1705 // I am an activity record! 1706 return this; 1707 } 1708 1709 @Override hasActivity()1710 boolean hasActivity() { 1711 // I am an activity! 1712 return true; 1713 } 1714 setProcess(WindowProcessController proc)1715 void setProcess(WindowProcessController proc) { 1716 app = proc; 1717 final ActivityRecord root = task != null ? task.getRootActivity() : null; 1718 if (root == this) { 1719 task.setRootProcess(proc); 1720 } 1721 proc.addActivityIfNeeded(this); 1722 } 1723 hasProcess()1724 boolean hasProcess() { 1725 return app != null; 1726 } 1727 attachedToProcess()1728 boolean attachedToProcess() { 1729 return hasProcess() && app.hasThread(); 1730 } 1731 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)1732 boolean addStartingWindow(String pkg, int theme, CompatibilityInfo compatInfo, 1733 CharSequence nonLocalizedLabel, int labelRes, int icon, int logo, int windowFlags, 1734 IBinder transferFrom, boolean newTask, boolean taskSwitch, boolean processRunning, 1735 boolean allowTaskSnapshot, boolean activityCreated) { 1736 // If the display is frozen, we won't do anything until the actual window is 1737 // displayed so there is no reason to put in the starting window. 1738 if (!okToDisplay()) { 1739 return false; 1740 } 1741 1742 if (mStartingData != null) { 1743 return false; 1744 } 1745 1746 final WindowState mainWin = findMainWindow(); 1747 if (mainWin != null && mainWin.mWinAnimator.getShown()) { 1748 // App already has a visible window...why would you want a starting window? 1749 return false; 1750 } 1751 1752 final ActivityManager.TaskSnapshot snapshot = 1753 mWmService.mTaskSnapshotController.getSnapshot(task.mTaskId, task.mUserId, 1754 false /* restoreFromDisk */, false /* isLowResolution */); 1755 final int type = getStartingWindowType(newTask, taskSwitch, processRunning, 1756 allowTaskSnapshot, activityCreated, snapshot); 1757 1758 if (type == STARTING_WINDOW_TYPE_SNAPSHOT) { 1759 if (isActivityTypeHome()) { 1760 // The snapshot of home is only used once because it won't be updated while screen 1761 // is on (see {@link TaskSnapshotController#screenTurningOff}). 1762 mWmService.mTaskSnapshotController.removeSnapshotCache(task.mTaskId); 1763 if ((mDisplayContent.mAppTransition.getTransitFlags() 1764 & WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION) == 0) { 1765 // Only use snapshot of home as starting window when unlocking directly. 1766 return false; 1767 } 1768 } 1769 return createSnapshot(snapshot); 1770 } 1771 1772 // If this is a translucent window, then don't show a starting window -- the current 1773 // effect (a full-screen opaque starting window that fades away to the real contents 1774 // when it is ready) does not work for this. 1775 ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Checking theme of starting window: 0x%x", theme); 1776 if (theme != 0) { 1777 AttributeCache.Entry ent = AttributeCache.instance().get(pkg, theme, 1778 com.android.internal.R.styleable.Window, 1779 mWmService.mCurrentUserId); 1780 if (ent == null) { 1781 // Whoops! App doesn't exist. Um. Okay. We'll just pretend like we didn't 1782 // see that. 1783 return false; 1784 } 1785 final boolean windowIsTranslucent = ent.array.getBoolean( 1786 com.android.internal.R.styleable.Window_windowIsTranslucent, false); 1787 final boolean windowIsFloating = ent.array.getBoolean( 1788 com.android.internal.R.styleable.Window_windowIsFloating, false); 1789 final boolean windowShowWallpaper = ent.array.getBoolean( 1790 com.android.internal.R.styleable.Window_windowShowWallpaper, false); 1791 final boolean windowDisableStarting = ent.array.getBoolean( 1792 com.android.internal.R.styleable.Window_windowDisablePreview, false); 1793 ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Translucent=%s Floating=%s ShowWallpaper=%s", 1794 windowIsTranslucent, windowIsFloating, windowShowWallpaper); 1795 if (windowIsTranslucent) { 1796 return false; 1797 } 1798 if (windowIsFloating || windowDisableStarting) { 1799 return false; 1800 } 1801 if (windowShowWallpaper) { 1802 if (getDisplayContent().mWallpaperController 1803 .getWallpaperTarget() == null) { 1804 // If this theme is requesting a wallpaper, and the wallpaper 1805 // is not currently visible, then this effectively serves as 1806 // an opaque window and our starting window transition animation 1807 // can still work. We just need to make sure the starting window 1808 // is also showing the wallpaper. 1809 windowFlags |= FLAG_SHOW_WALLPAPER; 1810 } else { 1811 return false; 1812 } 1813 } 1814 } 1815 1816 if (transferStartingWindow(transferFrom)) { 1817 return true; 1818 } 1819 1820 // There is no existing starting window, and we don't want to create a splash screen, so 1821 // that's it! 1822 if (type != STARTING_WINDOW_TYPE_SPLASH_SCREEN) { 1823 return false; 1824 } 1825 1826 ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Creating SplashScreenStartingData"); 1827 mStartingData = new SplashScreenStartingData(mWmService, pkg, 1828 theme, compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags, 1829 getMergedOverrideConfiguration()); 1830 scheduleAddStartingWindow(); 1831 return true; 1832 } 1833 createSnapshot(ActivityManager.TaskSnapshot snapshot)1834 private boolean createSnapshot(ActivityManager.TaskSnapshot snapshot) { 1835 if (snapshot == null) { 1836 return false; 1837 } 1838 1839 ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Creating SnapshotStartingData"); 1840 mStartingData = new SnapshotStartingData(mWmService, snapshot); 1841 scheduleAddStartingWindow(); 1842 return true; 1843 } 1844 scheduleAddStartingWindow()1845 void scheduleAddStartingWindow() { 1846 // Note: we really want to do sendMessageAtFrontOfQueue() because we 1847 // want to process the message ASAP, before any other queued 1848 // messages. 1849 if (!mWmService.mAnimationHandler.hasCallbacks(mAddStartingWindow)) { 1850 ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Enqueueing ADD_STARTING"); 1851 mWmService.mAnimationHandler.postAtFrontOfQueue(mAddStartingWindow); 1852 } 1853 } 1854 1855 private class AddStartingWindow implements Runnable { 1856 1857 @Override run()1858 public void run() { 1859 // Can be accessed without holding the global lock 1860 final StartingData startingData; 1861 synchronized (mWmService.mGlobalLock) { 1862 // There can only be one adding request, silly caller! 1863 mWmService.mAnimationHandler.removeCallbacks(this); 1864 1865 if (mStartingData == null) { 1866 // Animation has been canceled... do nothing. 1867 ProtoLog.v(WM_DEBUG_STARTING_WINDOW, 1868 "startingData was nulled out before handling" 1869 + " mAddStartingWindow: %s", ActivityRecord.this); 1870 return; 1871 } 1872 startingData = mStartingData; 1873 } 1874 1875 ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Add starting %s: startingData=%s", 1876 this, startingData); 1877 1878 1879 WindowManagerPolicy.StartingSurface surface = null; 1880 try { 1881 surface = startingData.createStartingSurface(ActivityRecord.this); 1882 } catch (Exception e) { 1883 Slog.w(TAG, "Exception when adding starting window", e); 1884 } 1885 if (surface != null) { 1886 boolean abort = false; 1887 synchronized (mWmService.mGlobalLock) { 1888 // If the window was successfully added, then we need to remove it. 1889 if (mStartingData == null) { 1890 ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Aborted starting %s: startingData=%s", 1891 ActivityRecord.this, mStartingData); 1892 1893 startingWindow = null; 1894 mStartingData = null; 1895 abort = true; 1896 } else { 1897 startingSurface = surface; 1898 } 1899 if (!abort) { 1900 ProtoLog.v(WM_DEBUG_STARTING_WINDOW, 1901 "Added starting %s: startingWindow=%s startingView=%s", 1902 ActivityRecord.this, startingWindow, startingSurface); 1903 } 1904 } 1905 if (abort) { 1906 surface.remove(); 1907 } 1908 } else { 1909 ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Surface returned was null: %s", 1910 ActivityRecord.this); 1911 } 1912 } 1913 } 1914 1915 private final AddStartingWindow mAddStartingWindow = new AddStartingWindow(); 1916 getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning, boolean allowTaskSnapshot, boolean activityCreated, ActivityManager.TaskSnapshot snapshot)1917 private int getStartingWindowType(boolean newTask, boolean taskSwitch, boolean processRunning, 1918 boolean allowTaskSnapshot, boolean activityCreated, 1919 ActivityManager.TaskSnapshot snapshot) { 1920 if (newTask || !processRunning || (taskSwitch && !activityCreated)) { 1921 return STARTING_WINDOW_TYPE_SPLASH_SCREEN; 1922 } else if (taskSwitch && allowTaskSnapshot) { 1923 if (isSnapshotCompatible(snapshot)) { 1924 return STARTING_WINDOW_TYPE_SNAPSHOT; 1925 } 1926 if (!isActivityTypeHome()) { 1927 return STARTING_WINDOW_TYPE_SPLASH_SCREEN; 1928 } 1929 return STARTING_WINDOW_TYPE_NONE; 1930 } else { 1931 return STARTING_WINDOW_TYPE_NONE; 1932 } 1933 } 1934 1935 /** 1936 * Returns {@code true} if the task snapshot is compatible with this activity (at least the 1937 * rotation must be the same). 1938 */ 1939 @VisibleForTesting isSnapshotCompatible(ActivityManager.TaskSnapshot snapshot)1940 boolean isSnapshotCompatible(ActivityManager.TaskSnapshot snapshot) { 1941 if (snapshot == null) { 1942 return false; 1943 } 1944 final int rotation = mDisplayContent.rotationForActivityInDifferentOrientation(this); 1945 final int targetRotation = rotation != ROTATION_UNDEFINED 1946 // The display may rotate according to the orientation of this activity. 1947 ? rotation 1948 // The activity won't change display orientation. 1949 : task.getWindowConfiguration().getRotation(); 1950 return snapshot.getRotation() == targetRotation; 1951 } 1952 removeStartingWindow()1953 void removeStartingWindow() { 1954 if (startingWindow == null) { 1955 if (mStartingData != null) { 1956 // Starting window has not been added yet, but it is scheduled to be added. 1957 // Go ahead and cancel the request. 1958 ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Clearing startingData for token=%s", this); 1959 mStartingData = null; 1960 } 1961 return; 1962 } 1963 1964 final WindowManagerPolicy.StartingSurface surface; 1965 if (mStartingData != null) { 1966 surface = startingSurface; 1967 mStartingData = null; 1968 startingSurface = null; 1969 startingWindow = null; 1970 startingDisplayed = false; 1971 if (surface == null) { 1972 ProtoLog.v(WM_DEBUG_STARTING_WINDOW, 1973 "startingWindow was set but startingSurface==null, couldn't " 1974 + "remove"); 1975 1976 return; 1977 } 1978 } else { 1979 ProtoLog.v(WM_DEBUG_STARTING_WINDOW, 1980 "Tried to remove starting window but startingWindow was null: %s", 1981 this); 1982 return; 1983 } 1984 1985 ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Schedule remove starting %s startingWindow=%s" 1986 + " startingView=%s Callers=%s", 1987 this, startingWindow, startingSurface, Debug.getCallers(5)); 1988 1989 1990 // Use the same thread to remove the window as we used to add it, as otherwise we end up 1991 // with things in the view hierarchy being called from different threads. 1992 mWmService.mAnimationHandler.post(() -> { 1993 ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Removing startingView=%s", surface); 1994 try { 1995 surface.remove(); 1996 } catch (Exception e) { 1997 Slog.w(TAG_WM, "Exception when removing starting window", e); 1998 } 1999 }); 2000 } 2001 removeAppTokenFromDisplay()2002 private void removeAppTokenFromDisplay() { 2003 if (mWmService.mRoot == null) return; 2004 2005 final DisplayContent dc = mWmService.mRoot.getDisplayContent(getDisplayId()); 2006 if (dc == null) { 2007 Slog.w(TAG, "removeAppTokenFromDisplay: Attempted to remove token: " 2008 + appToken + " from non-existing displayId=" + getDisplayId()); 2009 return; 2010 } 2011 // Resume key dispatching if it is currently paused before we remove the container. 2012 resumeKeyDispatchingLocked(); 2013 dc.removeAppToken(appToken.asBinder()); 2014 } 2015 2016 /** 2017 * Reparents this activity into {@param newTask} at the provided {@param position}. The caller 2018 * should ensure that the {@param newTask} is not already the parent of this activity. 2019 */ reparent(Task newTask, int position, String reason)2020 void reparent(Task newTask, int position, String reason) { 2021 if (getParent() == null) { 2022 Slog.w(TAG, "reparent: Attempted to reparent non-existing app token: " + appToken); 2023 return; 2024 } 2025 final Task prevTask = task; 2026 if (prevTask == newTask) { 2027 throw new IllegalArgumentException(reason + ": task=" + newTask 2028 + " is already the parent of r=" + this); 2029 } 2030 2031 ProtoLog.i(WM_DEBUG_ADD_REMOVE, "reparent: moving activity=%s" 2032 + " to task=%d at %d", this, task.mTaskId, position); 2033 reparent(newTask, position); 2034 } 2035 isHomeIntent(Intent intent)2036 private boolean isHomeIntent(Intent intent) { 2037 return ACTION_MAIN.equals(intent.getAction()) 2038 && (intent.hasCategory(CATEGORY_HOME) 2039 || intent.hasCategory(CATEGORY_SECONDARY_HOME)) 2040 && intent.getCategories().size() == 1 2041 && intent.getData() == null 2042 && intent.getType() == null; 2043 } 2044 isMainIntent(Intent intent)2045 static boolean isMainIntent(Intent intent) { 2046 return ACTION_MAIN.equals(intent.getAction()) 2047 && intent.hasCategory(CATEGORY_LAUNCHER) 2048 && intent.getCategories().size() == 1 2049 && intent.getData() == null 2050 && intent.getType() == null; 2051 } 2052 2053 @VisibleForTesting canLaunchHomeActivity(int uid, ActivityRecord sourceRecord)2054 boolean canLaunchHomeActivity(int uid, ActivityRecord sourceRecord) { 2055 if (uid == Process.myUid() || uid == 0) { 2056 // System process can launch home activity. 2057 return true; 2058 } 2059 // Allow the recents component to launch the home activity. 2060 final RecentTasks recentTasks = mStackSupervisor.mService.getRecentTasks(); 2061 if (recentTasks != null && recentTasks.isCallerRecents(uid)) { 2062 return true; 2063 } 2064 // Resolver or system chooser activity can launch home activity. 2065 return sourceRecord != null && sourceRecord.isResolverOrDelegateActivity(); 2066 } 2067 2068 /** 2069 * @return whether the given package name can launch an assist activity. 2070 */ canLaunchAssistActivity(String packageName)2071 private boolean canLaunchAssistActivity(String packageName) { 2072 final ComponentName assistComponent = 2073 mAtmService.mActiveVoiceInteractionServiceComponent; 2074 if (assistComponent != null) { 2075 return assistComponent.getPackageName().equals(packageName); 2076 } 2077 return false; 2078 } 2079 canLaunchDreamActivity(String packageName)2080 static boolean canLaunchDreamActivity(String packageName) { 2081 if (packageName == null) { 2082 return false; 2083 } 2084 2085 if (!LocalServices.getService(ActivityTaskManagerInternal.class).isDreaming()) { 2086 return false; 2087 } 2088 2089 final DreamManagerInternal dreamManager = 2090 LocalServices.getService(DreamManagerInternal.class); 2091 2092 // Verify that the package is the current active dream or doze component. The 2093 // getActiveDreamComponent() call path does not acquire the DreamManager lock and thus 2094 // is safe to use. 2095 final ComponentName activeDream = dreamManager.getActiveDreamComponent(false /* doze */); 2096 final ComponentName activeDoze = dreamManager.getActiveDreamComponent(true /* doze */); 2097 return TextUtils.equals(packageName, getPackageName(activeDream)) 2098 || TextUtils.equals(packageName, getPackageName(activeDoze)); 2099 } 2100 getPackageName(ComponentName componentName)2101 private static String getPackageName(ComponentName componentName) { 2102 return componentName != null ? componentName.getPackageName() : null; 2103 } 2104 setActivityType(boolean componentSpecified, int launchedFromUid, Intent intent, ActivityOptions options, ActivityRecord sourceRecord)2105 private void setActivityType(boolean componentSpecified, int launchedFromUid, Intent intent, 2106 ActivityOptions options, ActivityRecord sourceRecord) { 2107 int activityType = ACTIVITY_TYPE_UNDEFINED; 2108 if ((!componentSpecified || canLaunchHomeActivity(launchedFromUid, sourceRecord)) 2109 && isHomeIntent(intent) && !isResolverOrDelegateActivity()) { 2110 // This sure looks like a home activity! 2111 activityType = ACTIVITY_TYPE_HOME; 2112 2113 if (info.resizeMode == RESIZE_MODE_FORCE_RESIZEABLE 2114 || info.resizeMode == RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION) { 2115 // We only allow home activities to be resizeable if they explicitly requested it. 2116 info.resizeMode = RESIZE_MODE_UNRESIZEABLE; 2117 } 2118 } else if (mAtmService.getRecentTasks().isRecentsComponent(mActivityComponent, 2119 info.applicationInfo.uid)) { 2120 activityType = ACTIVITY_TYPE_RECENTS; 2121 } else if (options != null && options.getLaunchActivityType() == ACTIVITY_TYPE_ASSISTANT 2122 && canLaunchAssistActivity(launchedFromPackage)) { 2123 activityType = ACTIVITY_TYPE_ASSISTANT; 2124 } else if (options != null && options.getLaunchActivityType() == ACTIVITY_TYPE_DREAM 2125 && canLaunchDreamActivity(launchedFromPackage) 2126 && DreamActivity.class.getName() == info.name) { 2127 activityType = ACTIVITY_TYPE_DREAM; 2128 } 2129 setActivityType(activityType); 2130 } 2131 setTaskToAffiliateWith(Task taskToAffiliateWith)2132 void setTaskToAffiliateWith(Task taskToAffiliateWith) { 2133 if (launchMode != LAUNCH_SINGLE_INSTANCE && launchMode != LAUNCH_SINGLE_TASK) { 2134 task.setTaskToAffiliateWith(taskToAffiliateWith); 2135 } 2136 } 2137 2138 /** @return Root task of this activity, null if there is no task. */ getRootTask()2139 ActivityStack getRootTask() { 2140 return task != null ? (ActivityStack) task.getRootTask() : null; 2141 } 2142 getRootTaskId()2143 int getRootTaskId() { 2144 return task != null ? task.getRootTaskId() : INVALID_TASK_ID; 2145 } 2146 getDisplay()2147 DisplayContent getDisplay() { 2148 final ActivityStack stack = getRootTask(); 2149 return stack != null ? stack.getDisplay() : null; 2150 } 2151 2152 @Override 2153 @Nullable getDisplayArea()2154 TaskDisplayArea getDisplayArea() { 2155 return (TaskDisplayArea) super.getDisplayArea(); 2156 } 2157 2158 @Override fillsParent()2159 boolean fillsParent() { 2160 return occludesParent(true /* includingFinishing */); 2161 } 2162 2163 /** Returns true if this activity is not finishing, is opaque and fills the entire space of 2164 * this task. */ occludesParent()2165 boolean occludesParent() { 2166 return occludesParent(false /* includingFinishing */); 2167 } 2168 occludesParent(boolean includingFinishing)2169 private boolean occludesParent(boolean includingFinishing) { 2170 if (!includingFinishing && finishing) { 2171 return false; 2172 } 2173 return mOccludesParent; 2174 } 2175 setOccludesParent(boolean occludesParent)2176 boolean setOccludesParent(boolean occludesParent) { 2177 final boolean changed = occludesParent != mOccludesParent; 2178 mOccludesParent = occludesParent; 2179 setMainWindowOpaque(occludesParent); 2180 mWmService.mWindowPlacerLocked.requestTraversal(); 2181 2182 if (changed && task != null && !occludesParent) { 2183 getRootTask().convertActivityToTranslucent(this); 2184 } 2185 // Always ensure visibility if this activity doesn't occlude parent, so the 2186 // {@link #returningOptions} of the activity under this one can be applied in 2187 // {@link #handleAlreadyVisible()}. 2188 if (changed || !occludesParent) { 2189 mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); 2190 } 2191 return changed; 2192 } 2193 setMainWindowOpaque(boolean isOpaque)2194 void setMainWindowOpaque(boolean isOpaque) { 2195 final WindowState win = findMainWindow(); 2196 if (win == null) { 2197 return; 2198 } 2199 isOpaque = isOpaque & !PixelFormat.formatHasAlpha(win.getAttrs().format); 2200 win.mWinAnimator.setOpaqueLocked(isOpaque); 2201 } 2202 takeFromHistory()2203 void takeFromHistory() { 2204 if (inHistory) { 2205 inHistory = false; 2206 if (task != null && !finishing) { 2207 task = null; 2208 } 2209 clearOptionsLocked(); 2210 } 2211 } 2212 isInHistory()2213 boolean isInHistory() { 2214 return inHistory; 2215 } 2216 isInStackLocked()2217 boolean isInStackLocked() { 2218 final ActivityStack stack = getRootTask(); 2219 return stack != null && stack.isInTask(this) != null; 2220 } 2221 isPersistable()2222 boolean isPersistable() { 2223 return (info.persistableMode == PERSIST_ROOT_ONLY || 2224 info.persistableMode == PERSIST_ACROSS_REBOOTS) && 2225 (intent == null || (intent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0); 2226 } 2227 2228 @Override isFocusable()2229 boolean isFocusable() { 2230 return super.isFocusable() && (canReceiveKeys() || isAlwaysFocusable()); 2231 } 2232 canReceiveKeys()2233 boolean canReceiveKeys() { 2234 // TODO(156521483): Propagate the state down the hierarchy instead of checking the parent 2235 return getWindowConfiguration().canReceiveKeys() 2236 && (task == null || task.getWindowConfiguration().canReceiveKeys()); 2237 } 2238 isResizeable()2239 boolean isResizeable() { 2240 return mAtmService.mForceResizableActivities 2241 || ActivityInfo.isResizeableMode(info.resizeMode) 2242 || info.supportsPictureInPicture(); 2243 } 2244 2245 /** @return whether this activity is non-resizeable or forced to be resizeable */ isNonResizableOrForcedResizable(int windowingMode)2246 boolean isNonResizableOrForcedResizable(int windowingMode) { 2247 if (windowingMode == WINDOWING_MODE_PINNED && info.supportsPictureInPicture()) { 2248 return false; 2249 } 2250 return info.resizeMode != RESIZE_MODE_RESIZEABLE 2251 && info.resizeMode != RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION; 2252 } 2253 2254 /** 2255 * @return whether this activity supports PiP multi-window and can be put in the pinned stack. 2256 */ supportsPictureInPicture()2257 boolean supportsPictureInPicture() { 2258 return mAtmService.mSupportsPictureInPicture && isActivityTypeStandardOrUndefined() 2259 && info.supportsPictureInPicture(); 2260 } 2261 2262 /** 2263 * @return whether this activity supports split-screen multi-window and can be put in the docked 2264 * stack. 2265 */ 2266 @Override supportsSplitScreenWindowingMode()2267 public boolean supportsSplitScreenWindowingMode() { 2268 // An activity can not be docked even if it is considered resizeable because it only 2269 // supports picture-in-picture mode but has a non-resizeable resizeMode 2270 return super.supportsSplitScreenWindowingMode() 2271 && mAtmService.mSupportsSplitScreenMultiWindow && supportsResizeableMultiWindow(); 2272 } 2273 2274 /** 2275 * @return whether this activity supports freeform multi-window and can be put in the freeform 2276 * stack. 2277 */ supportsFreeform()2278 boolean supportsFreeform() { 2279 return mAtmService.mSupportsFreeformWindowManagement && supportsResizeableMultiWindow(); 2280 } 2281 2282 /** 2283 * @return whether this activity supports non-PiP multi-window. 2284 */ supportsResizeableMultiWindow()2285 private boolean supportsResizeableMultiWindow() { 2286 return mAtmService.mSupportsMultiWindow && !isActivityTypeHome() 2287 && (ActivityInfo.isResizeableMode(info.resizeMode) 2288 || mAtmService.mForceResizableActivities); 2289 } 2290 2291 /** 2292 * Check whether this activity can be launched on the specified display. 2293 * 2294 * @param displayId Target display id. 2295 * @return {@code true} if either it is the default display or this activity can be put on a 2296 * secondary screen. 2297 */ canBeLaunchedOnDisplay(int displayId)2298 boolean canBeLaunchedOnDisplay(int displayId) { 2299 return mAtmService.mStackSupervisor.canPlaceEntityOnDisplay(displayId, launchedFromPid, 2300 launchedFromUid, info); 2301 } 2302 2303 /** 2304 * @param beforeStopping Whether this check is for an auto-enter-pip operation, that is to say 2305 * the activity has requested to enter PiP when it would otherwise be stopped. 2306 * 2307 * @return whether this activity is currently allowed to enter PIP. 2308 */ checkEnterPictureInPictureState(String caller, boolean beforeStopping)2309 boolean checkEnterPictureInPictureState(String caller, boolean beforeStopping) { 2310 if (!supportsPictureInPicture()) { 2311 return false; 2312 } 2313 2314 // Check app-ops and see if PiP is supported for this package 2315 if (!checkEnterPictureInPictureAppOpsState()) { 2316 return false; 2317 } 2318 2319 // Check to see if we are in VR mode, and disallow PiP if so 2320 if (mAtmService.shouldDisableNonVrUiLocked()) { 2321 return false; 2322 } 2323 2324 boolean isKeyguardLocked = mAtmService.isKeyguardLocked(); 2325 boolean isCurrentAppLocked = 2326 mAtmService.getLockTaskModeState() != LOCK_TASK_MODE_NONE; 2327 final TaskDisplayArea taskDisplayArea = getDisplayArea(); 2328 boolean hasPinnedStack = taskDisplayArea != null && taskDisplayArea.hasPinnedTask(); 2329 // Don't return early if !isNotLocked, since we want to throw an exception if the activity 2330 // is in an incorrect state 2331 boolean isNotLockedOrOnKeyguard = !isKeyguardLocked && !isCurrentAppLocked; 2332 2333 // We don't allow auto-PiP when something else is already pipped. 2334 if (beforeStopping && hasPinnedStack) { 2335 return false; 2336 } 2337 2338 switch (mState) { 2339 case RESUMED: 2340 // When visible, allow entering PiP if the app is not locked. If it is over the 2341 // keyguard, then we will prompt to unlock in the caller before entering PiP. 2342 return !isCurrentAppLocked && 2343 (supportsEnterPipOnTaskSwitch || !beforeStopping); 2344 case PAUSING: 2345 case PAUSED: 2346 // When pausing, then only allow enter PiP as in the resume state, and in addition, 2347 // require that there is not an existing PiP activity and that the current system 2348 // state supports entering PiP 2349 return isNotLockedOrOnKeyguard && !hasPinnedStack 2350 && supportsEnterPipOnTaskSwitch; 2351 case STOPPING: 2352 // When stopping in a valid state, then only allow enter PiP as in the pause state. 2353 // Otherwise, fall through to throw an exception if the caller is trying to enter 2354 // PiP in an invalid stopping state. 2355 if (supportsEnterPipOnTaskSwitch) { 2356 return isNotLockedOrOnKeyguard && !hasPinnedStack; 2357 } 2358 default: 2359 return false; 2360 } 2361 } 2362 2363 /** 2364 * Sets if this {@link ActivityRecord} is in the process of closing or entering PIP. 2365 * {@link #mWillCloseOrEnterPip}} 2366 */ setWillCloseOrEnterPip(boolean willCloseOrEnterPip)2367 void setWillCloseOrEnterPip(boolean willCloseOrEnterPip) { 2368 mWillCloseOrEnterPip = willCloseOrEnterPip; 2369 } 2370 2371 /** 2372 * Returns whether this {@link ActivityRecord} is considered closing. Conditions are either 2373 * 1. Is this app animating and was requested to be hidden 2374 * 2. App is delayed closing since it might enter PIP. 2375 */ isClosingOrEnteringPip()2376 boolean isClosingOrEnteringPip() { 2377 return (isAnimating(TRANSITION | PARENTS) && !mVisibleRequested) || mWillCloseOrEnterPip; 2378 } 2379 /** 2380 * @return Whether AppOps allows this package to enter picture-in-picture. 2381 */ checkEnterPictureInPictureAppOpsState()2382 private boolean checkEnterPictureInPictureAppOpsState() { 2383 return mAtmService.getAppOpsManager().checkOpNoThrow( 2384 OP_PICTURE_IN_PICTURE, info.applicationInfo.uid, packageName) == MODE_ALLOWED; 2385 } 2386 isAlwaysFocusable()2387 private boolean isAlwaysFocusable() { 2388 return (info.flags & FLAG_ALWAYS_FOCUSABLE) != 0; 2389 } 2390 windowsAreFocusable()2391 boolean windowsAreFocusable() { 2392 return windowsAreFocusable(false /* fromUserTouch */); 2393 } 2394 2395 // TODO: Does this really need to be different from isAlwaysFocusable()? For the activity side 2396 // focusable means resumeable. I guess with that in mind maybe we should rename the other 2397 // method to isResumeable() or something like that. windowsAreFocusable(boolean fromUserTouch)2398 boolean windowsAreFocusable(boolean fromUserTouch) { 2399 if (!fromUserTouch && mTargetSdk < Build.VERSION_CODES.Q) { 2400 final int pid = getPid(); 2401 final ActivityRecord topFocusedAppOfMyProcess = 2402 mWmService.mRoot.mTopFocusedAppByProcess.get(pid); 2403 if (topFocusedAppOfMyProcess != null && topFocusedAppOfMyProcess != this) { 2404 // For the apps below Q, there can be only one app which has the focused window per 2405 // process, because legacy apps may not be ready for a multi-focus system. 2406 return false; 2407 2408 } 2409 } 2410 return (canReceiveKeys() || isAlwaysFocusable()) && getDisplay() != null; 2411 } 2412 2413 /** 2414 * Move activity with its stack to front and make the stack focused. 2415 * @param reason the reason to move to top 2416 * @return {@code true} if the stack is focusable and has been moved to top or the activity 2417 * is not yet resumed while the stack is already on top, {@code false} otherwise. 2418 */ moveFocusableActivityToTop(String reason)2419 boolean moveFocusableActivityToTop(String reason) { 2420 if (!isFocusable()) { 2421 if (DEBUG_FOCUS) { 2422 Slog.d(TAG_FOCUS, "moveActivityStackToFront: unfocusable activity=" + this); 2423 } 2424 return false; 2425 } 2426 2427 final ActivityStack stack = getRootTask(); 2428 if (stack == null) { 2429 Slog.w(TAG, "moveActivityStackToFront: invalid task or stack: activity=" 2430 + this + " task=" + task); 2431 return false; 2432 } 2433 2434 if (mRootWindowContainer.getTopResumedActivity() == this 2435 && getDisplayContent().mFocusedApp == this) { 2436 if (DEBUG_FOCUS) { 2437 Slog.d(TAG_FOCUS, "moveActivityStackToFront: already on top, activity=" + this); 2438 } 2439 return !isState(RESUMED); 2440 } 2441 2442 if (DEBUG_FOCUS) { 2443 Slog.d(TAG_FOCUS, "moveActivityStackToFront: activity=" + this); 2444 } 2445 2446 stack.moveToFront(reason, task); 2447 // Report top activity change to tracking services and WM 2448 if (mRootWindowContainer.getTopResumedActivity() == this) { 2449 mAtmService.setResumedActivityUncheckLocked(this, reason); 2450 } 2451 return true; 2452 } 2453 finishIfSubActivity(ActivityRecord parent, String otherResultWho, int otherRequestCode)2454 void finishIfSubActivity(ActivityRecord parent, String otherResultWho, int otherRequestCode) { 2455 if (resultTo != parent 2456 || requestCode != otherRequestCode 2457 || !Objects.equals(resultWho, otherResultWho)) return; 2458 2459 finishIfPossible("request-sub", false /* oomAdj */); 2460 } 2461 2462 /** Finish all activities in the task with the same affinity as this one. */ finishIfSameAffinity(ActivityRecord r)2463 boolean finishIfSameAffinity(ActivityRecord r) { 2464 // End search once we get to the activity that doesn't have the same affinity. 2465 if (!Objects.equals(r.taskAffinity, taskAffinity)) return true; 2466 2467 r.finishIfPossible("request-affinity", true /* oomAdj */); 2468 return false; 2469 } 2470 2471 /** 2472 * Sets the result for activity that started this one, clears the references to activities 2473 * started for result from this one, and clears new intents. 2474 */ finishActivityResults(int resultCode, Intent resultData, NeededUriGrants resultGrants)2475 private void finishActivityResults(int resultCode, Intent resultData, 2476 NeededUriGrants resultGrants) { 2477 // Send the result if needed 2478 if (resultTo != null) { 2479 if (DEBUG_RESULTS) { 2480 Slog.v(TAG_RESULTS, "Adding result to " + resultTo 2481 + " who=" + resultWho + " req=" + requestCode 2482 + " res=" + resultCode + " data=" + resultData); 2483 } 2484 if (resultTo.mUserId != mUserId) { 2485 if (resultData != null) { 2486 resultData.prepareToLeaveUser(mUserId); 2487 } 2488 } 2489 if (info.applicationInfo.uid > 0) { 2490 mAtmService.mUgmInternal.grantUriPermissionUncheckedFromIntent(resultGrants, 2491 resultTo.getUriPermissionsLocked()); 2492 } 2493 resultTo.addResultLocked(this, resultWho, requestCode, resultCode, resultData); 2494 resultTo = null; 2495 } else if (DEBUG_RESULTS) { 2496 Slog.v(TAG_RESULTS, "No result destination from " + this); 2497 } 2498 2499 // Make sure this HistoryRecord is not holding on to other resources, 2500 // because clients have remote IPC references to this object so we 2501 // can't assume that will go away and want to avoid circular IPC refs. 2502 results = null; 2503 pendingResults = null; 2504 newIntents = null; 2505 setSavedState(null /* savedState */); 2506 } 2507 2508 /** Activity finish request was not executed. */ 2509 static final int FINISH_RESULT_CANCELLED = 0; 2510 /** Activity finish was requested, activity will be fully removed later. */ 2511 static final int FINISH_RESULT_REQUESTED = 1; 2512 /** Activity finish was requested, activity was removed from history. */ 2513 static final int FINISH_RESULT_REMOVED = 2; 2514 2515 /** Definition of possible results for activity finish request. */ 2516 @IntDef(prefix = { "FINISH_RESULT_" }, value = { 2517 FINISH_RESULT_CANCELLED, 2518 FINISH_RESULT_REQUESTED, 2519 FINISH_RESULT_REMOVED, 2520 }) 2521 @interface FinishRequest {} 2522 2523 /** 2524 * See {@link #finishIfPossible(int, Intent, String, boolean)} 2525 */ finishIfPossible(String reason, boolean oomAdj)2526 @FinishRequest int finishIfPossible(String reason, boolean oomAdj) { 2527 return finishIfPossible(Activity.RESULT_CANCELED, 2528 null /* resultData */, null /* resultGrants */, reason, oomAdj); 2529 } 2530 2531 /** 2532 * Finish activity if possible. If activity was resumed - we must first pause it to make the 2533 * activity below resumed. Otherwise we will try to complete the request immediately by calling 2534 * {@link #completeFinishing(String)}. 2535 * @return One of {@link FinishRequest} values: 2536 * {@link #FINISH_RESULT_REMOVED} if this activity has been removed from the history list. 2537 * {@link #FINISH_RESULT_REQUESTED} if removal process was started, but it is still in the list 2538 * and will be removed from history later. 2539 * {@link #FINISH_RESULT_CANCELLED} if activity is already finishing or in invalid state and the 2540 * request to finish it was not ignored. 2541 */ finishIfPossible(int resultCode, Intent resultData, NeededUriGrants resultGrants, String reason, boolean oomAdj)2542 @FinishRequest int finishIfPossible(int resultCode, Intent resultData, 2543 NeededUriGrants resultGrants, String reason, boolean oomAdj) { 2544 if (DEBUG_RESULTS || DEBUG_STATES) { 2545 Slog.v(TAG_STATES, "Finishing activity r=" + this + ", result=" + resultCode 2546 + ", data=" + resultData + ", reason=" + reason); 2547 } 2548 2549 if (finishing) { 2550 Slog.w(TAG, "Duplicate finish request for r=" + this); 2551 return FINISH_RESULT_CANCELLED; 2552 } 2553 2554 if (!isInStackLocked()) { 2555 Slog.w(TAG, "Finish request when not in stack for r=" + this); 2556 return FINISH_RESULT_CANCELLED; 2557 } 2558 2559 final ActivityStack stack = getRootTask(); 2560 final boolean mayAdjustTop = (isState(RESUMED) || stack.mResumedActivity == null) 2561 && stack.isFocusedStackOnDisplay() 2562 // Do not adjust focus task because the task will be reused to launch new activity. 2563 && !task.isClearingToReuseTask(); 2564 final boolean shouldAdjustGlobalFocus = mayAdjustTop 2565 // It must be checked before {@link #makeFinishingLocked} is called, because a stack 2566 // is not visible if it only contains finishing activities. 2567 && mRootWindowContainer.isTopDisplayFocusedStack(stack); 2568 2569 mAtmService.deferWindowLayout(); 2570 try { 2571 makeFinishingLocked(); 2572 // Make a local reference to its task since this.task could be set to null once this 2573 // activity is destroyed and detached from task. 2574 final Task task = getTask(); 2575 EventLogTags.writeWmFinishActivity(mUserId, System.identityHashCode(this), 2576 task.mTaskId, shortComponentName, reason); 2577 ActivityRecord next = task.getActivityAbove(this); 2578 if (next != null) { 2579 if ((intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) { 2580 // If the caller asked that this activity (and all above it) 2581 // be cleared when the task is reset, don't lose that information, 2582 // but propagate it up to the next activity. 2583 next.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 2584 } 2585 } 2586 2587 pauseKeyDispatchingLocked(); 2588 2589 // We are finishing the top focused activity and its task has nothing to be focused so 2590 // the next focusable task should be focused. 2591 if (mayAdjustTop && ((ActivityStack) task).topRunningActivity(true /* focusableOnly */) 2592 == null) { 2593 task.adjustFocusToNextFocusableTask("finish-top", false /* allowFocusSelf */, 2594 shouldAdjustGlobalFocus); 2595 } 2596 2597 finishActivityResults(resultCode, resultData, resultGrants); 2598 2599 final boolean endTask = task.getActivityBelow(this) == null 2600 && !task.isClearingToReuseTask(); 2601 final int transit = endTask ? TRANSIT_TASK_CLOSE : TRANSIT_ACTIVITY_CLOSE; 2602 if (isState(RESUMED)) { 2603 if (endTask) { 2604 mAtmService.getTaskChangeNotificationController().notifyTaskRemovalStarted( 2605 task.getTaskInfo()); 2606 } 2607 // Prepare app close transition, but don't execute just yet. It is possible that 2608 // an activity that will be made resumed in place of this one will immediately 2609 // launch another new activity. In this case current closing transition will be 2610 // combined with open transition for the new activity. 2611 if (DEBUG_VISIBILITY || DEBUG_TRANSITION) { 2612 Slog.v(TAG_TRANSITION, "Prepare close transition: finishing " + this); 2613 } 2614 mDisplayContent.prepareAppTransition(transit, false); 2615 2616 // When finishing the activity preemptively take the snapshot before the app window 2617 // is marked as hidden and any configuration changes take place 2618 if (mAtmService.mWindowManager.mTaskSnapshotController != null) { 2619 final ArraySet<Task> tasks = Sets.newArraySet(task); 2620 mAtmService.mWindowManager.mTaskSnapshotController.snapshotTasks(tasks); 2621 mAtmService.mWindowManager.mTaskSnapshotController 2622 .addSkipClosingAppSnapshotTasks(tasks); 2623 } 2624 2625 // Tell window manager to prepare for this one to be removed. 2626 setVisibility(false); 2627 2628 if (stack.mPausingActivity == null) { 2629 if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish needs to pause: " + this); 2630 if (DEBUG_USER_LEAVING) { 2631 Slog.v(TAG_USER_LEAVING, "finish() => pause with userLeaving=false"); 2632 } 2633 stack.startPausingLocked(false /* userLeaving */, false /* uiSleeping */, 2634 null /* resuming */); 2635 } 2636 2637 if (endTask) { 2638 mAtmService.getLockTaskController().clearLockedTask(task); 2639 // This activity was in the top focused stack and this is the last activity in 2640 // that task, give this activity a higher layer so it can stay on top before the 2641 // closing task transition be executed. 2642 if (mayAdjustTop) { 2643 mNeedsZBoost = true; 2644 mDisplayContent.assignWindowLayers(false /* setLayoutNeeded */); 2645 } 2646 } 2647 } else if (!isState(PAUSING)) { 2648 if (mVisibleRequested) { 2649 // Prepare and execute close transition. 2650 prepareActivityHideTransitionAnimation(transit); 2651 } 2652 2653 final boolean removedActivity = completeFinishing("finishIfPossible") == null; 2654 // Performance optimization - only invoke OOM adjustment if the state changed to 2655 // 'STOPPING'. Otherwise it will not change the OOM scores. 2656 if (oomAdj && isState(STOPPING)) { 2657 mAtmService.updateOomAdj(); 2658 } 2659 2660 // The following code is an optimization. When the last non-task overlay activity 2661 // is removed from the task, we remove the entire task from the stack. However, 2662 // since that is done after the scheduled destroy callback from the activity, that 2663 // call to change the visibility of the task overlay activities would be out of 2664 // sync with the activity visibility being set for this finishing activity above. 2665 // In this case, we can set the visibility of all the task overlay activities when 2666 // we detect the last one is finishing to keep them in sync. 2667 if (task.onlyHasTaskOverlayActivities(false /* includeFinishing */)) { 2668 final PooledConsumer c = PooledLambda.obtainConsumer( 2669 ActivityRecord::prepareActivityHideTransitionAnimationIfOvarlay, 2670 PooledLambda.__(ActivityRecord.class), transit); 2671 task.forAllActivities(c); 2672 c.recycle(); 2673 } 2674 return removedActivity ? FINISH_RESULT_REMOVED : FINISH_RESULT_REQUESTED; 2675 } else { 2676 if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish waiting for pause of: " + this); 2677 } 2678 2679 return FINISH_RESULT_REQUESTED; 2680 } finally { 2681 mAtmService.continueWindowLayout(); 2682 } 2683 } 2684 prepareActivityHideTransitionAnimationIfOvarlay(int transit)2685 private void prepareActivityHideTransitionAnimationIfOvarlay(int transit) { 2686 if (mTaskOverlay) { 2687 prepareActivityHideTransitionAnimation(transit); 2688 } 2689 } 2690 prepareActivityHideTransitionAnimation(int transit)2691 private void prepareActivityHideTransitionAnimation(int transit) { 2692 final DisplayContent dc = getDisplay().mDisplayContent; 2693 dc.prepareAppTransition(transit, false); 2694 setVisibility(false); 2695 dc.executeAppTransition(); 2696 } 2697 2698 /** 2699 * Complete activity finish request that was initiated earlier. If the activity is still 2700 * pausing we will wait for it to complete its transition. If the activity that should appear in 2701 * place of this one is not visible yet - we'll wait for it first. Otherwise - activity can be 2702 * destroyed right away. 2703 * @param reason Reason for finishing the activity. 2704 * @return Flag indicating whether the activity was removed from history. 2705 */ completeFinishing(String reason)2706 ActivityRecord completeFinishing(String reason) { 2707 if (!finishing || isState(RESUMED)) { 2708 throw new IllegalArgumentException( 2709 "Activity must be finishing and not resumed to complete, r=" + this 2710 + ", finishing=" + finishing + ", state=" + mState); 2711 } 2712 2713 if (isState(PAUSING)) { 2714 // Activity is marked as finishing and will be processed once it completes. 2715 return this; 2716 } 2717 2718 final boolean isCurrentVisible = mVisibleRequested || isState(PAUSED); 2719 if (isCurrentVisible) { 2720 final ActivityStack stack = getStack(); 2721 final ActivityRecord activity = stack.mResumedActivity; 2722 boolean ensureVisibility = false; 2723 if (activity != null && !activity.occludesParent()) { 2724 // If the resume activity is not opaque, we need to make sure the visibilities of 2725 // activities be updated, they may be seen by users. 2726 ensureVisibility = true; 2727 } else if (mStackSupervisor.getKeyguardController().isKeyguardLocked() 2728 && stack.topActivityOccludesKeyguard()) { 2729 // Ensure activity visibilities and update lockscreen occluded/dismiss state when 2730 // finishing the top activity that occluded keyguard. So that, the 2731 // ActivityStack#mTopActivityOccludesKeyguard can be updated and the activity below 2732 // won't be resumed. 2733 ensureVisibility = true; 2734 } 2735 2736 if (ensureVisibility) { 2737 getDisplay().ensureActivitiesVisible(null /* starting */, 0 /* configChanges */, 2738 false /* preserveWindows */, true /* notifyClients */); 2739 } 2740 } 2741 2742 boolean activityRemoved = false; 2743 2744 // If this activity is currently visible, and the resumed activity is not yet visible, then 2745 // hold off on finishing until the resumed one becomes visible. 2746 // The activity that we are finishing may be over the lock screen. In this case, we do not 2747 // want to consider activities that cannot be shown on the lock screen as running and should 2748 // proceed with finishing the activity if there is no valid next top running activity. 2749 // Note that if this finishing activity is floating task, we don't need to wait the 2750 // next activity resume and can destroy it directly. 2751 // TODO(b/137329632): find the next activity directly underneath this one, not just anywhere 2752 final ActivityRecord next = getDisplayArea().topRunningActivity( 2753 true /* considerKeyguardState */); 2754 // isNextNotYetVisible is to check if the next activity is invisible, or it has been 2755 // requested to be invisible but its windows haven't reported as invisible. If so, it 2756 // implied that the current finishing activity should be added into stopping list rather 2757 // than destroy immediately. 2758 final boolean isNextNotYetVisible = next != null 2759 && (!next.nowVisible || !next.mVisibleRequested); 2760 if (isCurrentVisible && isNextNotYetVisible) { 2761 // Add this activity to the list of stopping activities. It will be processed and 2762 // destroyed when the next activity reports idle. 2763 addToStopping(false /* scheduleIdle */, false /* idleDelayed */, 2764 "completeFinishing"); 2765 setState(STOPPING, "completeFinishing"); 2766 } else if (addToFinishingAndWaitForIdle()) { 2767 // We added this activity to the finishing list and something else is becoming resumed. 2768 // The activity will complete finishing when the next activity reports idle. No need to 2769 // do anything else here. 2770 } else { 2771 // Not waiting for the next one to become visible, and nothing else will be resumed in 2772 // place of this activity - requesting destruction right away. 2773 activityRemoved = destroyIfPossible(reason); 2774 } 2775 2776 return activityRemoved ? null : this; 2777 } 2778 2779 /** 2780 * Destroy and cleanup the activity both on client and server if possible. If activity is the 2781 * last one left on display with home stack and there is no other running activity - delay 2782 * destroying it until the next one starts. 2783 */ destroyIfPossible(String reason)2784 boolean destroyIfPossible(String reason) { 2785 setState(FINISHING, "destroyIfPossible"); 2786 2787 // Make sure the record is cleaned out of other places. 2788 mStackSupervisor.mStoppingActivities.remove(this); 2789 2790 final ActivityStack stack = getRootTask(); 2791 final TaskDisplayArea taskDisplayArea = getDisplayArea(); 2792 // TODO(b/137329632): Exclude current activity when looking for the next one with 2793 // DisplayContent#topRunningActivity(). 2794 final ActivityRecord next = taskDisplayArea.topRunningActivity(); 2795 final boolean isLastStackOverEmptyHome = 2796 next == null && stack.isFocusedStackOnDisplay() 2797 && taskDisplayArea.getOrCreateRootHomeTask() != null; 2798 if (isLastStackOverEmptyHome) { 2799 // Don't destroy activity immediately if this is the last activity on the display and 2800 // the display contains home stack. Although there is no next activity at the moment, 2801 // another home activity should be started later. Keep this activity alive until next 2802 // home activity is resumed. This way the user won't see a temporary black screen. 2803 addToFinishingAndWaitForIdle(); 2804 return false; 2805 } 2806 makeFinishingLocked(); 2807 2808 final boolean activityRemoved = destroyImmediately(true /* removeFromApp */, 2809 "finish-imm:" + reason); 2810 2811 // If the display does not have running activity, the configuration may need to be 2812 // updated for restoring original orientation of the display. 2813 if (next == null) { 2814 mRootWindowContainer.ensureVisibilityAndConfig(next, getDisplayId(), 2815 false /* markFrozenIfConfigChanged */, true /* deferResume */); 2816 } 2817 if (activityRemoved) { 2818 mRootWindowContainer.resumeFocusedStacksTopActivities(); 2819 } 2820 2821 if (DEBUG_CONTAINERS) { 2822 Slog.d(TAG_CONTAINERS, "destroyIfPossible: r=" + this + " destroy returned removed=" 2823 + activityRemoved); 2824 } 2825 2826 return activityRemoved; 2827 } 2828 2829 /** 2830 * Add this activity to the list of finishing and trigger resuming of activities in focused 2831 * stacks. 2832 * @return {@code true} if some other activity is being resumed as a result of this call. 2833 */ 2834 @VisibleForTesting addToFinishingAndWaitForIdle()2835 boolean addToFinishingAndWaitForIdle() { 2836 if (DEBUG_STATES) Slog.v(TAG, "Enqueueing pending finish: " + this); 2837 setState(FINISHING, "addToFinishingAndWaitForIdle"); 2838 if (!mStackSupervisor.mFinishingActivities.contains(this)) { 2839 mStackSupervisor.mFinishingActivities.add(this); 2840 } 2841 resumeKeyDispatchingLocked(); 2842 return mRootWindowContainer.resumeFocusedStacksTopActivities(); 2843 } 2844 2845 /** 2846 * Destroy the current CLIENT SIDE instance of an activity. This may be called both when 2847 * actually finishing an activity, or when performing a configuration switch where we destroy 2848 * the current client-side object but then create a new client-side object for this same 2849 * HistoryRecord. 2850 * Normally the server-side record will be removed when the client reports back after 2851 * destruction. If, however, at this point there is no client process attached, the record will 2852 * be removed immediately. 2853 * 2854 * @return {@code true} if activity was immediately removed from history, {@code false} 2855 * otherwise. 2856 */ destroyImmediately(boolean removeFromApp, String reason)2857 boolean destroyImmediately(boolean removeFromApp, String reason) { 2858 if (DEBUG_SWITCH || DEBUG_CLEANUP) { 2859 Slog.v(TAG_SWITCH, "Removing activity from " + reason + ": token=" + this 2860 + ", app=" + (hasProcess() ? app.mName : "(null)")); 2861 } 2862 2863 if (isState(DESTROYING, DESTROYED)) { 2864 if (DEBUG_STATES) { 2865 Slog.v(TAG_STATES, "activity " + this + " already destroying." 2866 + "skipping request with reason:" + reason); 2867 } 2868 return false; 2869 } 2870 2871 EventLogTags.writeWmDestroyActivity(mUserId, System.identityHashCode(this), 2872 task.mTaskId, shortComponentName, reason); 2873 2874 boolean removedFromHistory = false; 2875 2876 cleanUp(false /* cleanServices */, false /* setState */); 2877 2878 if (hasProcess()) { 2879 if (removeFromApp) { 2880 app.removeActivity(this); 2881 if (!app.hasActivities()) { 2882 mAtmService.clearHeavyWeightProcessIfEquals(app); 2883 // Update any services we are bound to that might care about whether 2884 // their client may have activities. 2885 // No longer have activities, so update LRU list and oom adj. 2886 app.updateProcessInfo(true /* updateServiceConnectionActivities */, 2887 false /* activityChange */, true /* updateOomAdj */, 2888 false /* addPendingTopUid */); 2889 } 2890 } 2891 2892 boolean skipDestroy = false; 2893 2894 try { 2895 if (DEBUG_SWITCH) Slog.i(TAG_SWITCH, "Destroying: " + this); 2896 mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, 2897 DestroyActivityItem.obtain(finishing, configChangeFlags)); 2898 } catch (Exception e) { 2899 // We can just ignore exceptions here... if the process has crashed, our death 2900 // notification will clean things up. 2901 if (finishing) { 2902 removeFromHistory(reason + " exceptionInScheduleDestroy"); 2903 removedFromHistory = true; 2904 skipDestroy = true; 2905 } 2906 } 2907 2908 nowVisible = false; 2909 2910 // If the activity is finishing, we need to wait on removing it from the list to give it 2911 // a chance to do its cleanup. During that time it may make calls back with its token 2912 // so we need to be able to find it on the list and so we don't want to remove it from 2913 // the list yet. Otherwise, we can just immediately put it in the destroyed state since 2914 // we are not removing it from the list. 2915 if (finishing && !skipDestroy) { 2916 if (DEBUG_STATES) { 2917 Slog.v(TAG_STATES, "Moving to DESTROYING: " + this + " (destroy requested)"); 2918 } 2919 setState(DESTROYING, 2920 "destroyActivityLocked. finishing and not skipping destroy"); 2921 mAtmService.mH.postDelayed(mDestroyTimeoutRunnable, DESTROY_TIMEOUT); 2922 } else { 2923 if (DEBUG_STATES) { 2924 Slog.v(TAG_STATES, "Moving to DESTROYED: " + this + " (destroy skipped)"); 2925 } 2926 setState(DESTROYED, 2927 "destroyActivityLocked. not finishing or skipping destroy"); 2928 if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during destroy for activity " + this); 2929 app = null; 2930 } 2931 } else { 2932 // Remove this record from the history. 2933 if (finishing) { 2934 removeFromHistory(reason + " hadNoApp"); 2935 removedFromHistory = true; 2936 } else { 2937 if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to DESTROYED: " + this + " (no app)"); 2938 setState(DESTROYED, "destroyActivityLocked. not finishing and had no app"); 2939 } 2940 } 2941 2942 configChangeFlags = 0; 2943 2944 return removedFromHistory; 2945 } 2946 safelyDestroy(String reason)2947 boolean safelyDestroy(String reason) { 2948 if (isDestroyable()) { 2949 if (DEBUG_SWITCH) { 2950 final ActivityStack stack = getRootTask(); 2951 Slog.v(TAG_SWITCH, "Safely destroying " + this + " in state " + getState() 2952 + " resumed=" + stack.mResumedActivity 2953 + " pausing=" + stack.mPausingActivity 2954 + " for reason " + reason); 2955 } 2956 return destroyImmediately(true /* removeFromApp */, reason); 2957 } 2958 return false; 2959 } 2960 2961 /** Note: call {@link #cleanUp(boolean, boolean)} before this method. */ removeFromHistory(String reason)2962 void removeFromHistory(String reason) { 2963 finishActivityResults(Activity.RESULT_CANCELED, 2964 null /* resultData */, null /* resultGrants */); 2965 makeFinishingLocked(); 2966 if (ActivityTaskManagerDebugConfig.DEBUG_ADD_REMOVE) { 2967 Slog.i(TAG_ADD_REMOVE, "Removing activity " + this + " from stack callers=" 2968 + Debug.getCallers(5)); 2969 } 2970 2971 takeFromHistory(); 2972 removeTimeouts(); 2973 if (DEBUG_STATES) { 2974 Slog.v(TAG_STATES, "Moving to DESTROYED: " + this + " (removed from history)"); 2975 } 2976 setState(DESTROYED, "removeFromHistory"); 2977 if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during remove for activity " + this); 2978 app = null; 2979 removeAppTokenFromDisplay(); 2980 2981 cleanUpActivityServices(); 2982 removeUriPermissionsLocked(); 2983 } 2984 makeFinishingLocked()2985 void makeFinishingLocked() { 2986 if (finishing) { 2987 return; 2988 } 2989 finishing = true; 2990 if (stopped) { 2991 clearOptionsLocked(); 2992 } 2993 } 2994 2995 /** 2996 * This method is to only be called from the client via binder when the activity is destroyed 2997 * AND finished. 2998 */ destroyed(String reason)2999 void destroyed(String reason) { 3000 removeDestroyTimeout(); 3001 3002 if (DEBUG_CONTAINERS) Slog.d(TAG_CONTAINERS, "activityDestroyedLocked: r=" + this); 3003 3004 if (!isState(DESTROYING, DESTROYED)) { 3005 throw new IllegalStateException( 3006 "Reported destroyed for activity that is not destroying: r=" + this); 3007 } 3008 3009 if (isInStackLocked()) { 3010 cleanUp(true /* cleanServices */, false /* setState */); 3011 removeFromHistory(reason); 3012 } 3013 3014 mRootWindowContainer.resumeFocusedStacksTopActivities(); 3015 } 3016 3017 /** 3018 * Perform the common clean-up of an activity record. This is called both as part of 3019 * destroyActivityLocked() (when destroying the client-side representation) and cleaning things 3020 * up as a result of its hosting processing going away, in which case there is no remaining 3021 * client-side state to destroy so only the cleanup here is needed. 3022 * 3023 * Note: Call before {@link #removeFromHistory(String)}. 3024 */ cleanUp(boolean cleanServices, boolean setState)3025 void cleanUp(boolean cleanServices, boolean setState) { 3026 task.cleanUpActivityReferences(this); 3027 3028 deferRelaunchUntilPaused = false; 3029 frozenBeforeDestroy = false; 3030 3031 if (setState) { 3032 setState(DESTROYED, "cleanUp"); 3033 if (DEBUG_APP) Slog.v(TAG_APP, "Clearing app during cleanUp for activity " + this); 3034 app = null; 3035 } 3036 3037 // Inform supervisor the activity has been removed. 3038 mStackSupervisor.cleanupActivity(this); 3039 3040 // Remove any pending results. 3041 if (finishing && pendingResults != null) { 3042 for (WeakReference<PendingIntentRecord> apr : pendingResults) { 3043 PendingIntentRecord rec = apr.get(); 3044 if (rec != null) { 3045 mAtmService.mPendingIntentController.cancelIntentSender(rec, 3046 false /* cleanActivity */); 3047 } 3048 } 3049 pendingResults = null; 3050 } 3051 3052 if (cleanServices) { 3053 cleanUpActivityServices(); 3054 } 3055 3056 // Get rid of any pending idle timeouts. 3057 removeTimeouts(); 3058 // Clean-up activities are no longer relaunching (e.g. app process died). Notify window 3059 // manager so it can update its bookkeeping. 3060 clearRelaunching(); 3061 } 3062 isRelaunching()3063 boolean isRelaunching() { 3064 return mPendingRelaunchCount > 0; 3065 } 3066 shouldFreezeBounds()3067 boolean shouldFreezeBounds() { 3068 // For freeform windows, we can't freeze the bounds at the moment because this would make 3069 // the resizing unresponsive. 3070 if (task == null || task.inFreeformWindowingMode()) { 3071 return false; 3072 } 3073 3074 // We freeze the bounds while drag resizing to deal with the time between 3075 // the divider/drag handle being released, and the handling it's new 3076 // configuration. If we are relaunched outside of the drag resizing state, 3077 // we need to be careful not to do this. 3078 return task.isDragResizing(); 3079 } 3080 startRelaunching()3081 void startRelaunching() { 3082 if (shouldFreezeBounds()) { 3083 freezeBounds(); 3084 } 3085 3086 // In the process of tearing down before relaunching, the app will 3087 // try and clean up it's child surfaces. We need to prevent this from 3088 // happening, so we sever the children, transfering their ownership 3089 // from the client it-self to the parent surface (owned by us). 3090 detachChildren(); 3091 3092 mPendingRelaunchCount++; 3093 } 3094 3095 /** 3096 * Freezes the task bounds. The size of this task reported the app will be fixed to the bounds 3097 * freezed by {@link Task#prepareFreezingBounds} until {@link #unfreezeBounds} gets called, even 3098 * if they change in the meantime. If the bounds are already frozen, the bounds will be frozen 3099 * with a queue. 3100 */ freezeBounds()3101 private void freezeBounds() { 3102 mFrozenBounds.offer(new Rect(task.mPreparedFrozenBounds)); 3103 3104 if (task.mPreparedFrozenMergedConfig.equals(Configuration.EMPTY)) { 3105 // We didn't call prepareFreezingBounds on the task, so use the current value. 3106 mFrozenMergedConfig.offer(new Configuration(task.getConfiguration())); 3107 } else { 3108 mFrozenMergedConfig.offer(new Configuration(task.mPreparedFrozenMergedConfig)); 3109 } 3110 // Calling unset() to make it equal to Configuration.EMPTY. 3111 task.mPreparedFrozenMergedConfig.unset(); 3112 } 3113 detachChildren()3114 void detachChildren() { 3115 SurfaceControl.openTransaction(); 3116 for (int i = mChildren.size() - 1; i >= 0; i--) { 3117 final WindowState w = mChildren.get(i); 3118 w.mWinAnimator.detachChildren(); 3119 } 3120 SurfaceControl.closeTransaction(); 3121 } 3122 finishRelaunching()3123 void finishRelaunching() { 3124 unfreezeBounds(); 3125 3126 if (mPendingRelaunchCount > 0) { 3127 mPendingRelaunchCount--; 3128 } else { 3129 // Update keyguard flags upon finishing relaunch. 3130 checkKeyguardFlagsChanged(); 3131 } 3132 } 3133 clearRelaunching()3134 void clearRelaunching() { 3135 if (mPendingRelaunchCount == 0) { 3136 return; 3137 } 3138 unfreezeBounds(); 3139 mPendingRelaunchCount = 0; 3140 } 3141 3142 /** 3143 * Unfreezes the previously frozen bounds. See {@link #freezeBounds}. 3144 */ unfreezeBounds()3145 private void unfreezeBounds() { 3146 if (mFrozenBounds.isEmpty()) { 3147 return; 3148 } 3149 mFrozenBounds.remove(); 3150 if (!mFrozenMergedConfig.isEmpty()) { 3151 mFrozenMergedConfig.remove(); 3152 } 3153 for (int i = mChildren.size() - 1; i >= 0; i--) { 3154 final WindowState win = mChildren.get(i); 3155 win.onUnfreezeBounds(); 3156 } 3157 mWmService.mWindowPlacerLocked.performSurfacePlacement(); 3158 } 3159 3160 /** 3161 * Perform clean-up of service connections in an activity record. 3162 */ cleanUpActivityServices()3163 private void cleanUpActivityServices() { 3164 if (mServiceConnectionsHolder == null) { 3165 return; 3166 } 3167 // Throw away any services that have been bound by this activity. 3168 mServiceConnectionsHolder.disconnectActivityFromServices(); 3169 // This activity record is removing, make sure not to disconnect twice. 3170 mServiceConnectionsHolder = null; 3171 } 3172 3173 @Override removeImmediately()3174 void removeImmediately() { 3175 onRemovedFromDisplay(); 3176 super.removeImmediately(); 3177 } 3178 3179 @Override removeIfPossible()3180 void removeIfPossible() { 3181 mIsExiting = false; 3182 removeAllWindowsIfPossible(); 3183 removeImmediately(); 3184 } 3185 3186 @Override handleCompleteDeferredRemoval()3187 boolean handleCompleteDeferredRemoval() { 3188 if (mIsExiting) { 3189 removeIfPossible(); 3190 } 3191 return super.handleCompleteDeferredRemoval(); 3192 } 3193 onRemovedFromDisplay()3194 void onRemovedFromDisplay() { 3195 if (mRemovingFromDisplay) { 3196 return; 3197 } 3198 mRemovingFromDisplay = true; 3199 3200 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, "Removing app token: %s", this); 3201 3202 commitVisibility(false /* visible */, true /* performLayout */); 3203 3204 getDisplayContent().mOpeningApps.remove(this); 3205 getDisplayContent().mUnknownAppVisibilityController.appRemovedOrHidden(this); 3206 mWmService.mTaskSnapshotController.onAppRemoved(this); 3207 mStackSupervisor.getActivityMetricsLogger().notifyActivityRemoved(this); 3208 waitingToShow = false; 3209 3210 // Defer removal of this activity when either a child is animating, or app transition is on 3211 // going. App transition animation might be applied on the parent stack not on the activity, 3212 // but the actual frame buffer is associated with the activity, so we have to keep the 3213 // activity while a parent is animating. 3214 boolean delayed = isAnimating(TRANSITION | PARENTS | CHILDREN); 3215 if (getDisplayContent().mClosingApps.contains(this)) { 3216 delayed = true; 3217 } else if (getDisplayContent().mAppTransition.isTransitionSet()) { 3218 getDisplayContent().mClosingApps.add(this); 3219 delayed = true; 3220 } 3221 3222 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, 3223 "Removing app %s delayed=%b animation=%s animating=%b", this, delayed, 3224 getAnimation(), isAnimating(TRANSITION | PARENTS)); 3225 3226 ProtoLog.v(WM_DEBUG_ADD_REMOVE, "removeAppToken: %s" 3227 + " delayed=%b Callers=%s", this, delayed, Debug.getCallers(4)); 3228 3229 if (mStartingData != null) { 3230 removeStartingWindow(); 3231 } 3232 3233 // If this window was animating, then we need to ensure that the app transition notifies 3234 // that animations have completed in DisplayContent.handleAnimatingStoppedAndTransition(), 3235 // so add to that list now 3236 if (isAnimating(TRANSITION | PARENTS)) { 3237 getDisplayContent().mNoAnimationNotifyOnTransitionFinished.add(token); 3238 } 3239 3240 final ActivityStack stack = getStack(); 3241 if (delayed && !isEmpty()) { 3242 // set the token aside because it has an active animation to be finished 3243 ProtoLog.v(WM_DEBUG_ADD_REMOVE, 3244 "removeAppToken make exiting: %s", this); 3245 if (stack != null) { 3246 stack.mExitingActivities.add(this); 3247 } 3248 mIsExiting = true; 3249 } else { 3250 // Make sure there is no animation running on this token, so any windows associated 3251 // with it will be removed as soon as their animations are complete 3252 cancelAnimation(); 3253 if (stack != null) { 3254 stack.mExitingActivities.remove(this); 3255 } 3256 removeIfPossible(); 3257 } 3258 3259 stopFreezingScreen(true, true); 3260 3261 final DisplayContent dc = getDisplayContent(); 3262 if (dc.mFocusedApp == this) { 3263 ProtoLog.v(WM_DEBUG_FOCUS_LIGHT, 3264 "Removing focused app token:%s displayId=%d", this, 3265 dc.getDisplayId()); 3266 dc.setFocusedApp(null); 3267 mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/); 3268 } 3269 if (mLetterbox != null) { 3270 mLetterbox.destroy(); 3271 mLetterbox = null; 3272 } 3273 3274 if (!delayed) { 3275 updateReportedVisibilityLocked(); 3276 } 3277 3278 // Reset the last saved PiP snap fraction on removal. 3279 mDisplayContent.mPinnedStackControllerLocked.onActivityHidden(mActivityComponent); 3280 mWmService.mEmbeddedWindowController.onActivityRemoved(this); 3281 mRemovingFromDisplay = false; 3282 } 3283 3284 /** 3285 * Returns true if the new child window we are adding to this token is considered greater than 3286 * the existing child window in this token in terms of z-order. 3287 */ 3288 @Override isFirstChildWindowGreaterThanSecond(WindowState newWindow, WindowState existingWindow)3289 protected boolean isFirstChildWindowGreaterThanSecond(WindowState newWindow, 3290 WindowState existingWindow) { 3291 final int type1 = newWindow.mAttrs.type; 3292 final int type2 = existingWindow.mAttrs.type; 3293 3294 // Base application windows should be z-ordered BELOW all other windows in the app token. 3295 if (type1 == TYPE_BASE_APPLICATION && type2 != TYPE_BASE_APPLICATION) { 3296 return false; 3297 } else if (type1 != TYPE_BASE_APPLICATION && type2 == TYPE_BASE_APPLICATION) { 3298 return true; 3299 } 3300 3301 // Starting windows should be z-ordered ABOVE all other windows in the app token. 3302 if (type1 == TYPE_APPLICATION_STARTING && type2 != TYPE_APPLICATION_STARTING) { 3303 return true; 3304 } else if (type1 != TYPE_APPLICATION_STARTING && type2 == TYPE_APPLICATION_STARTING) { 3305 return false; 3306 } 3307 3308 // Otherwise the new window is greater than the existing window. 3309 return true; 3310 } 3311 3312 /** 3313 * @return {@code true} if starting window is in app's hierarchy. 3314 */ hasStartingWindow()3315 boolean hasStartingWindow() { 3316 if (startingDisplayed || mStartingData != null) { 3317 return true; 3318 } 3319 for (int i = mChildren.size() - 1; i >= 0; i--) { 3320 if (getChildAt(i).mAttrs.type == TYPE_APPLICATION_STARTING) { 3321 return true; 3322 } 3323 } 3324 return false; 3325 } 3326 isLastWindow(WindowState win)3327 boolean isLastWindow(WindowState win) { 3328 return mChildren.size() == 1 && mChildren.get(0) == win; 3329 } 3330 3331 @Override addWindow(WindowState w)3332 void addWindow(WindowState w) { 3333 super.addWindow(w); 3334 3335 boolean gotReplacementWindow = false; 3336 for (int i = mChildren.size() - 1; i >= 0; i--) { 3337 final WindowState candidate = mChildren.get(i); 3338 gotReplacementWindow |= candidate.setReplacementWindowIfNeeded(w); 3339 } 3340 3341 // if we got a replacement window, reset the timeout to give drawing more time 3342 if (gotReplacementWindow) { 3343 mWmService.scheduleWindowReplacementTimeouts(this); 3344 } 3345 checkKeyguardFlagsChanged(); 3346 } 3347 3348 @Override removeChild(WindowState child)3349 void removeChild(WindowState child) { 3350 if (!mChildren.contains(child)) { 3351 // This can be true when testing. 3352 return; 3353 } 3354 super.removeChild(child); 3355 checkKeyguardFlagsChanged(); 3356 updateLetterboxSurface(child); 3357 } 3358 onWindowReplacementTimeout()3359 void onWindowReplacementTimeout() { 3360 for (int i = mChildren.size() - 1; i >= 0; --i) { 3361 (mChildren.get(i)).onWindowReplacementTimeout(); 3362 } 3363 } 3364 setAppLayoutChanges(int changes, String reason)3365 void setAppLayoutChanges(int changes, String reason) { 3366 if (!mChildren.isEmpty()) { 3367 final DisplayContent dc = getDisplayContent(); 3368 dc.pendingLayoutChanges |= changes; 3369 if (DEBUG_LAYOUT_REPEATS) { 3370 mWmService.mWindowPlacerLocked.debugLayoutRepeats(reason, dc.pendingLayoutChanges); 3371 } 3372 } 3373 } 3374 removeReplacedWindowIfNeeded(WindowState replacement)3375 void removeReplacedWindowIfNeeded(WindowState replacement) { 3376 for (int i = mChildren.size() - 1; i >= 0; i--) { 3377 final WindowState win = mChildren.get(i); 3378 if (win.removeReplacedWindowIfNeeded(replacement)) { 3379 return; 3380 } 3381 } 3382 } 3383 transferStartingWindow(IBinder transferFrom)3384 boolean transferStartingWindow(IBinder transferFrom) { 3385 final ActivityRecord fromActivity = getDisplayContent().getActivityRecord(transferFrom); 3386 if (fromActivity == null) { 3387 return false; 3388 } 3389 3390 final WindowState tStartingWindow = fromActivity.startingWindow; 3391 if (tStartingWindow != null && fromActivity.startingSurface != null) { 3392 // In this case, the starting icon has already been displayed, so start 3393 // letting windows get shown immediately without any more transitions. 3394 getDisplayContent().mSkipAppTransitionAnimation = true; 3395 3396 ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Moving existing starting %s" 3397 + " from %s to %s", tStartingWindow, fromActivity, this); 3398 3399 final long origId = Binder.clearCallingIdentity(); 3400 try { 3401 // Link the fixed rotation transform to this activity since we are transferring the 3402 // starting window. 3403 if (fromActivity.hasFixedRotationTransform()) { 3404 mDisplayContent.handleTopActivityLaunchingInDifferentOrientation(this, 3405 false /* checkOpening */); 3406 } 3407 3408 // Transfer the starting window over to the new token. 3409 mStartingData = fromActivity.mStartingData; 3410 startingSurface = fromActivity.startingSurface; 3411 startingDisplayed = fromActivity.startingDisplayed; 3412 fromActivity.startingDisplayed = false; 3413 startingWindow = tStartingWindow; 3414 reportedVisible = fromActivity.reportedVisible; 3415 fromActivity.mStartingData = null; 3416 fromActivity.startingSurface = null; 3417 fromActivity.startingWindow = null; 3418 fromActivity.startingMoved = true; 3419 tStartingWindow.mToken = this; 3420 tStartingWindow.mActivityRecord = this; 3421 3422 ProtoLog.v(WM_DEBUG_ADD_REMOVE, 3423 "Removing starting %s from %s", tStartingWindow, fromActivity); 3424 fromActivity.removeChild(tStartingWindow); 3425 addWindow(tStartingWindow); 3426 3427 // Propagate other interesting state between the tokens. If the old token is displayed, 3428 // we should immediately force the new one to be displayed. If it is animating, we need 3429 // to move that animation to the new one. 3430 if (fromActivity.allDrawn) { 3431 allDrawn = true; 3432 } 3433 if (fromActivity.firstWindowDrawn) { 3434 firstWindowDrawn = true; 3435 } 3436 if (fromActivity.isVisible()) { 3437 setVisible(true); 3438 mVisibleRequested = true; 3439 mVisibleSetFromTransferredStartingWindow = true; 3440 } 3441 setClientVisible(fromActivity.mClientVisible); 3442 3443 if (fromActivity.isAnimating()) { 3444 transferAnimation(fromActivity); 3445 3446 // When transferring an animation, we no longer need to apply an animation to 3447 // the token we transfer the animation over. Thus, set this flag to indicate 3448 // we've transferred the animation. 3449 mUseTransferredAnimation = true; 3450 } 3451 // Post cleanup after the visibility and animation are transferred. 3452 fromActivity.postWindowRemoveStartingWindowCleanup(tStartingWindow); 3453 fromActivity.mVisibleSetFromTransferredStartingWindow = false; 3454 3455 mWmService.updateFocusedWindowLocked( 3456 UPDATE_FOCUS_WILL_PLACE_SURFACES, true /*updateInputWindows*/); 3457 getDisplayContent().setLayoutNeeded(); 3458 mWmService.mWindowPlacerLocked.performSurfacePlacement(); 3459 } finally { 3460 Binder.restoreCallingIdentity(origId); 3461 } 3462 return true; 3463 } else if (fromActivity.mStartingData != null) { 3464 // The previous app was getting ready to show a 3465 // starting window, but hasn't yet done so. Steal it! 3466 ProtoLog.v(WM_DEBUG_STARTING_WINDOW, 3467 "Moving pending starting from %s to %s", fromActivity, this); 3468 mStartingData = fromActivity.mStartingData; 3469 fromActivity.mStartingData = null; 3470 fromActivity.startingMoved = true; 3471 scheduleAddStartingWindow(); 3472 return true; 3473 } 3474 3475 // TODO: Transfer thumbnail 3476 3477 return false; 3478 } 3479 3480 /** 3481 * Tries to transfer the starting window from a token that's above ourselves in the task but 3482 * not visible anymore. This is a common scenario apps use: Trampoline activity T start main 3483 * activity M in the same task. Now, when reopening the task, T starts on top of M but then 3484 * immediately finishes after, so we have to transfer T to M. 3485 */ transferStartingWindowFromHiddenAboveTokenIfNeeded()3486 void transferStartingWindowFromHiddenAboveTokenIfNeeded() { 3487 final PooledFunction p = PooledLambda.obtainFunction(ActivityRecord::transferStartingWindow, 3488 this, PooledLambda.__(ActivityRecord.class)); 3489 task.forAllActivities(p); 3490 p.recycle(); 3491 } 3492 transferStartingWindow(ActivityRecord fromActivity)3493 private boolean transferStartingWindow(ActivityRecord fromActivity) { 3494 if (fromActivity == this) return true; 3495 3496 return !fromActivity.mVisibleRequested && transferStartingWindow(fromActivity.token); 3497 } 3498 checkKeyguardFlagsChanged()3499 void checkKeyguardFlagsChanged() { 3500 final boolean containsDismissKeyguard = containsDismissKeyguardWindow(); 3501 final boolean containsShowWhenLocked = containsShowWhenLockedWindow(); 3502 if (containsDismissKeyguard != mLastContainsDismissKeyguardWindow 3503 || containsShowWhenLocked != mLastContainsShowWhenLockedWindow) { 3504 mWmService.notifyKeyguardFlagsChanged(null /* callback */, 3505 getDisplayContent().getDisplayId()); 3506 } 3507 mLastContainsDismissKeyguardWindow = containsDismissKeyguard; 3508 mLastContainsShowWhenLockedWindow = containsShowWhenLocked; 3509 mLastContainsTurnScreenOnWindow = containsTurnScreenOnWindow(); 3510 } 3511 containsDismissKeyguardWindow()3512 boolean containsDismissKeyguardWindow() { 3513 // Window state is transient during relaunch. We are not guaranteed to be frozen during the 3514 // entirety of the relaunch. 3515 if (isRelaunching()) { 3516 return mLastContainsDismissKeyguardWindow; 3517 } 3518 3519 for (int i = mChildren.size() - 1; i >= 0; i--) { 3520 if ((mChildren.get(i).mAttrs.flags & FLAG_DISMISS_KEYGUARD) != 0) { 3521 return true; 3522 } 3523 } 3524 return false; 3525 } 3526 containsShowWhenLockedWindow()3527 boolean containsShowWhenLockedWindow() { 3528 // When we are relaunching, it is possible for us to be unfrozen before our previous 3529 // windows have been added back. Using the cached value ensures that our previous 3530 // showWhenLocked preference is honored until relaunching is complete. 3531 if (isRelaunching()) { 3532 return mLastContainsShowWhenLockedWindow; 3533 } 3534 3535 for (int i = mChildren.size() - 1; i >= 0; i--) { 3536 if ((mChildren.get(i).mAttrs.flags & FLAG_SHOW_WHEN_LOCKED) != 0) { 3537 return true; 3538 } 3539 } 3540 3541 return false; 3542 } 3543 setShowWhenLocked(boolean showWhenLocked)3544 void setShowWhenLocked(boolean showWhenLocked) { 3545 mShowWhenLocked = showWhenLocked; 3546 mAtmService.mRootWindowContainer.ensureActivitiesVisible(null /* starting */, 3547 0 /* configChanges */, false /* preserveWindows */); 3548 } 3549 setInheritShowWhenLocked(boolean inheritShowWhenLocked)3550 void setInheritShowWhenLocked(boolean inheritShowWhenLocked) { 3551 mInheritShownWhenLocked = inheritShowWhenLocked; 3552 mAtmService.mRootWindowContainer.ensureActivitiesVisible(null /* starting */, 3553 0 /* configChanges */, false /* preserveWindows */); 3554 } 3555 3556 /** 3557 * @return {@code true} if the activity windowing mode is not 3558 * {@link android.app.WindowConfiguration#WINDOWING_MODE_PINNED} and a) activity 3559 * contains windows that have {@link LayoutParams#FLAG_SHOW_WHEN_LOCKED} set or if the 3560 * activity has set {@link #mShowWhenLocked}, or b) if the activity has set 3561 * {@link #mInheritShownWhenLocked} and the activity behind this satisfies the 3562 * conditions a) above. 3563 * Multi-windowing mode will be exited if {@code true} is returned. 3564 */ canShowWhenLocked()3565 boolean canShowWhenLocked() { 3566 if (!inPinnedWindowingMode() && (mShowWhenLocked || containsShowWhenLockedWindow())) { 3567 return true; 3568 } else if (mInheritShownWhenLocked) { 3569 final ActivityRecord r = task.getActivityBelow(this); 3570 return r != null && !r.inPinnedWindowingMode() && (r.mShowWhenLocked 3571 || r.containsShowWhenLockedWindow()); 3572 } else { 3573 return false; 3574 } 3575 } 3576 3577 /** 3578 * @return Whether we are allowed to show non-starting windows at the moment. We disallow 3579 * showing windows during transitions in case we have windows that have wide-color-gamut 3580 * color mode set to avoid jank in the middle of the transition. 3581 */ canShowWindows()3582 boolean canShowWindows() { 3583 return allDrawn && !(isAnimating(PARENTS) && hasNonDefaultColorWindow()); 3584 } 3585 3586 /** 3587 * @return true if we have a window that has a non-default color mode set; false otherwise. 3588 */ hasNonDefaultColorWindow()3589 private boolean hasNonDefaultColorWindow() { 3590 return forAllWindows(ws -> ws.mAttrs.getColorMode() != COLOR_MODE_DEFAULT, 3591 true /* topToBottom */); 3592 } 3593 getImeTargetBelowWindow(WindowState w)3594 WindowState getImeTargetBelowWindow(WindowState w) { 3595 final int index = mChildren.indexOf(w); 3596 if (index > 0) { 3597 return mChildren.get(index - 1) 3598 .getWindow(WindowState::canBeImeTarget); 3599 } 3600 return null; 3601 } 3602 getHighestAnimLayerWindow(WindowState currentTarget)3603 WindowState getHighestAnimLayerWindow(WindowState currentTarget) { 3604 WindowState candidate = null; 3605 for (int i = mChildren.indexOf(currentTarget); i >= 0; i--) { 3606 final WindowState w = mChildren.get(i); 3607 if (w.mRemoved) { 3608 continue; 3609 } 3610 if (candidate == null) { 3611 candidate = w; 3612 } 3613 } 3614 return candidate; 3615 } 3616 3617 @Override forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom)3618 boolean forAllWindows(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom) { 3619 // For legacy reasons we process the TaskStack.mExitingActivities first in DisplayContent 3620 // before the non-exiting app tokens. So, we skip the exiting app tokens here. 3621 // TODO: Investigate if we need to continue to do this or if we can just process them 3622 // in-order. 3623 if (mIsExiting && !forAllWindowsUnchecked(WindowState::waitingForReplacement, true)) { 3624 return false; 3625 } 3626 return forAllWindowsUnchecked(callback, traverseTopToBottom); 3627 } 3628 forAllWindowsUnchecked(ToBooleanFunction<WindowState> callback, boolean traverseTopToBottom)3629 boolean forAllWindowsUnchecked(ToBooleanFunction<WindowState> callback, 3630 boolean traverseTopToBottom) { 3631 return super.forAllWindows(callback, traverseTopToBottom); 3632 } 3633 3634 @Override forAllActivities( Function<ActivityRecord, Boolean> callback, boolean traverseTopToBottom)3635 boolean forAllActivities( 3636 Function<ActivityRecord, Boolean> callback, boolean traverseTopToBottom) { 3637 return callback.apply(this); 3638 } 3639 3640 @Override forAllActivities(Consumer<ActivityRecord> callback, boolean traverseTopToBottom)3641 void forAllActivities(Consumer<ActivityRecord> callback, boolean traverseTopToBottom) { 3642 callback.accept(this); 3643 } 3644 3645 @Override getActivity(Predicate<ActivityRecord> callback, boolean traverseTopToBottom, ActivityRecord boundary)3646 ActivityRecord getActivity(Predicate<ActivityRecord> callback, boolean traverseTopToBottom, 3647 ActivityRecord boundary) { 3648 return callback.test(this) ? this : null; 3649 } 3650 3651 @Override setLayer(Transaction t, int layer)3652 protected void setLayer(Transaction t, int layer) { 3653 if (!mSurfaceAnimator.hasLeash()) { 3654 t.setLayer(mSurfaceControl, layer); 3655 } 3656 } 3657 3658 @Override setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer)3659 protected void setRelativeLayer(Transaction t, SurfaceControl relativeTo, int layer) { 3660 if (!mSurfaceAnimator.hasLeash()) { 3661 t.setRelativeLayer(mSurfaceControl, relativeTo, layer); 3662 } 3663 } 3664 3665 @Override reparentSurfaceControl(Transaction t, SurfaceControl newParent)3666 protected void reparentSurfaceControl(Transaction t, SurfaceControl newParent) { 3667 if (!mSurfaceAnimator.hasLeash()) { 3668 t.reparent(mSurfaceControl, newParent); 3669 } 3670 } 3671 logStartActivity(int tag, Task task)3672 void logStartActivity(int tag, Task task) { 3673 final Uri data = intent.getData(); 3674 final String strData = data != null ? data.toSafeString() : null; 3675 3676 EventLog.writeEvent(tag, 3677 mUserId, System.identityHashCode(this), task.mTaskId, 3678 shortComponentName, intent.getAction(), 3679 intent.getType(), strData, intent.getFlags()); 3680 } 3681 getUriPermissionsLocked()3682 UriPermissionOwner getUriPermissionsLocked() { 3683 if (uriPermissions == null) { 3684 uriPermissions = new UriPermissionOwner(mAtmService.mUgmInternal, this); 3685 } 3686 return uriPermissions; 3687 } 3688 addResultLocked(ActivityRecord from, String resultWho, int requestCode, int resultCode, Intent resultData)3689 void addResultLocked(ActivityRecord from, String resultWho, 3690 int requestCode, int resultCode, 3691 Intent resultData) { 3692 ActivityResult r = new ActivityResult(from, resultWho, 3693 requestCode, resultCode, resultData); 3694 if (results == null) { 3695 results = new ArrayList<ResultInfo>(); 3696 } 3697 results.add(r); 3698 } 3699 removeResultsLocked(ActivityRecord from, String resultWho, int requestCode)3700 void removeResultsLocked(ActivityRecord from, String resultWho, 3701 int requestCode) { 3702 if (results != null) { 3703 for (int i=results.size()-1; i>=0; i--) { 3704 ActivityResult r = (ActivityResult)results.get(i); 3705 if (r.mFrom != from) continue; 3706 if (r.mResultWho == null) { 3707 if (resultWho != null) continue; 3708 } else { 3709 if (!r.mResultWho.equals(resultWho)) continue; 3710 } 3711 if (r.mRequestCode != requestCode) continue; 3712 3713 results.remove(i); 3714 } 3715 } 3716 } 3717 sendResult(int callingUid, String resultWho, int requestCode, int resultCode, Intent data, NeededUriGrants dataGrants)3718 void sendResult(int callingUid, String resultWho, int requestCode, int resultCode, 3719 Intent data, NeededUriGrants dataGrants) { 3720 if (callingUid > 0) { 3721 mAtmService.mUgmInternal.grantUriPermissionUncheckedFromIntent(dataGrants, 3722 getUriPermissionsLocked()); 3723 } 3724 3725 if (DEBUG_RESULTS) { 3726 Slog.v(TAG, "Send activity result to " + this 3727 + " : who=" + resultWho + " req=" + requestCode 3728 + " res=" + resultCode + " data=" + data); 3729 } 3730 if (isState(RESUMED) && attachedToProcess()) { 3731 try { 3732 final ArrayList<ResultInfo> list = new ArrayList<ResultInfo>(); 3733 list.add(new ResultInfo(resultWho, requestCode, resultCode, data)); 3734 mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, 3735 ActivityResultItem.obtain(list)); 3736 return; 3737 } catch (Exception e) { 3738 Slog.w(TAG, "Exception thrown sending result to " + this, e); 3739 } 3740 } 3741 3742 addResultLocked(null /* from */, resultWho, requestCode, resultCode, data); 3743 } 3744 addNewIntentLocked(ReferrerIntent intent)3745 private void addNewIntentLocked(ReferrerIntent intent) { 3746 if (newIntents == null) { 3747 newIntents = new ArrayList<>(); 3748 } 3749 newIntents.add(intent); 3750 } 3751 isSleeping()3752 final boolean isSleeping() { 3753 final ActivityStack stack = getRootTask(); 3754 return stack != null ? stack.shouldSleepActivities() : mAtmService.isSleepingLocked(); 3755 } 3756 3757 /** 3758 * Deliver a new Intent to an existing activity, so that its onNewIntent() 3759 * method will be called at the proper time. 3760 */ deliverNewIntentLocked(int callingUid, Intent intent, NeededUriGrants intentGrants, String referrer)3761 final void deliverNewIntentLocked(int callingUid, Intent intent, NeededUriGrants intentGrants, 3762 String referrer) { 3763 // The activity now gets access to the data associated with this Intent. 3764 mAtmService.mUgmInternal.grantUriPermissionUncheckedFromIntent(intentGrants, 3765 getUriPermissionsLocked()); 3766 final ReferrerIntent rintent = new ReferrerIntent(intent, referrer); 3767 boolean unsent = true; 3768 final boolean isTopActivityWhileSleeping = isTopRunningActivity() && isSleeping(); 3769 3770 // We want to immediately deliver the intent to the activity if: 3771 // - It is currently resumed or paused. i.e. it is currently visible to the user and we want 3772 // the user to see the visual effects caused by the intent delivery now. 3773 // - The device is sleeping and it is the top activity behind the lock screen (b/6700897). 3774 if ((mState == RESUMED || mState == PAUSED || isTopActivityWhileSleeping) 3775 && attachedToProcess()) { 3776 try { 3777 ArrayList<ReferrerIntent> ar = new ArrayList<>(1); 3778 ar.add(rintent); 3779 // Making sure the client state is RESUMED after transaction completed and doing 3780 // so only if activity is currently RESUMED. Otherwise, client may have extra 3781 // life-cycle calls to RESUMED (and PAUSED later). 3782 mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, 3783 NewIntentItem.obtain(ar, mState == RESUMED)); 3784 unsent = false; 3785 } catch (RemoteException e) { 3786 Slog.w(TAG, "Exception thrown sending new intent to " + this, e); 3787 } catch (NullPointerException e) { 3788 Slog.w(TAG, "Exception thrown sending new intent to " + this, e); 3789 } 3790 } 3791 if (unsent) { 3792 addNewIntentLocked(rintent); 3793 } 3794 } 3795 updateOptionsLocked(ActivityOptions options)3796 void updateOptionsLocked(ActivityOptions options) { 3797 if (options != null) { 3798 if (DEBUG_TRANSITION) Slog.i(TAG, "Update options for " + this); 3799 if (pendingOptions != null) { 3800 pendingOptions.abort(); 3801 } 3802 pendingOptions = options; 3803 } 3804 } 3805 applyOptionsLocked()3806 void applyOptionsLocked() { 3807 if (pendingOptions != null 3808 && pendingOptions.getAnimationType() != ANIM_SCENE_TRANSITION) { 3809 if (DEBUG_TRANSITION) Slog.i(TAG, "Applying options for " + this); 3810 applyOptionsLocked(pendingOptions, intent); 3811 if (task == null) { 3812 clearOptionsLocked(false /* withAbort */); 3813 } else { 3814 // This will clear the options for all the ActivityRecords for this Task. 3815 task.forAllActivities((r) -> { 3816 r.clearOptionsLocked(false /* withAbort */); 3817 }); 3818 } 3819 } 3820 } 3821 3822 /** 3823 * Apply override app transition base on options & animation type. 3824 */ applyOptionsLocked(ActivityOptions pendingOptions, Intent intent)3825 void applyOptionsLocked(ActivityOptions pendingOptions, Intent intent) { 3826 final int animationType = pendingOptions.getAnimationType(); 3827 final DisplayContent displayContent = getDisplayContent(); 3828 switch (animationType) { 3829 case ANIM_CUSTOM: 3830 displayContent.mAppTransition.overridePendingAppTransition( 3831 pendingOptions.getPackageName(), 3832 pendingOptions.getCustomEnterResId(), 3833 pendingOptions.getCustomExitResId(), 3834 pendingOptions.getAnimationStartedListener(), 3835 pendingOptions.getAnimationFinishedListener()); 3836 break; 3837 case ANIM_CLIP_REVEAL: 3838 displayContent.mAppTransition.overridePendingAppTransitionClipReveal( 3839 pendingOptions.getStartX(), pendingOptions.getStartY(), 3840 pendingOptions.getWidth(), pendingOptions.getHeight()); 3841 if (intent.getSourceBounds() == null) { 3842 intent.setSourceBounds(new Rect(pendingOptions.getStartX(), 3843 pendingOptions.getStartY(), 3844 pendingOptions.getStartX() + pendingOptions.getWidth(), 3845 pendingOptions.getStartY() + pendingOptions.getHeight())); 3846 } 3847 break; 3848 case ANIM_SCALE_UP: 3849 displayContent.mAppTransition.overridePendingAppTransitionScaleUp( 3850 pendingOptions.getStartX(), pendingOptions.getStartY(), 3851 pendingOptions.getWidth(), pendingOptions.getHeight()); 3852 if (intent.getSourceBounds() == null) { 3853 intent.setSourceBounds(new Rect(pendingOptions.getStartX(), 3854 pendingOptions.getStartY(), 3855 pendingOptions.getStartX() + pendingOptions.getWidth(), 3856 pendingOptions.getStartY() + pendingOptions.getHeight())); 3857 } 3858 break; 3859 case ANIM_THUMBNAIL_SCALE_UP: 3860 case ANIM_THUMBNAIL_SCALE_DOWN: 3861 final boolean scaleUp = (animationType == ANIM_THUMBNAIL_SCALE_UP); 3862 final GraphicBuffer buffer = pendingOptions.getThumbnail(); 3863 displayContent.mAppTransition.overridePendingAppTransitionThumb(buffer, 3864 pendingOptions.getStartX(), pendingOptions.getStartY(), 3865 pendingOptions.getAnimationStartedListener(), 3866 scaleUp); 3867 if (intent.getSourceBounds() == null && buffer != null) { 3868 intent.setSourceBounds(new Rect(pendingOptions.getStartX(), 3869 pendingOptions.getStartY(), 3870 pendingOptions.getStartX() + buffer.getWidth(), 3871 pendingOptions.getStartY() + buffer.getHeight())); 3872 } 3873 break; 3874 case ANIM_THUMBNAIL_ASPECT_SCALE_UP: 3875 case ANIM_THUMBNAIL_ASPECT_SCALE_DOWN: 3876 final AppTransitionAnimationSpec[] specs = pendingOptions.getAnimSpecs(); 3877 final IAppTransitionAnimationSpecsFuture specsFuture = 3878 pendingOptions.getSpecsFuture(); 3879 if (specsFuture != null) { 3880 displayContent.mAppTransition.overridePendingAppTransitionMultiThumbFuture( 3881 specsFuture, pendingOptions.getAnimationStartedListener(), 3882 animationType == ANIM_THUMBNAIL_ASPECT_SCALE_UP); 3883 } else if (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_DOWN 3884 && specs != null) { 3885 displayContent.mAppTransition.overridePendingAppTransitionMultiThumb( 3886 specs, pendingOptions.getAnimationStartedListener(), 3887 pendingOptions.getAnimationFinishedListener(), false); 3888 } else { 3889 displayContent.mAppTransition.overridePendingAppTransitionAspectScaledThumb( 3890 pendingOptions.getThumbnail(), 3891 pendingOptions.getStartX(), pendingOptions.getStartY(), 3892 pendingOptions.getWidth(), pendingOptions.getHeight(), 3893 pendingOptions.getAnimationStartedListener(), 3894 (animationType == ANIM_THUMBNAIL_ASPECT_SCALE_UP)); 3895 if (intent.getSourceBounds() == null) { 3896 intent.setSourceBounds(new Rect(pendingOptions.getStartX(), 3897 pendingOptions.getStartY(), 3898 pendingOptions.getStartX() + pendingOptions.getWidth(), 3899 pendingOptions.getStartY() + pendingOptions.getHeight())); 3900 } 3901 } 3902 break; 3903 case ANIM_OPEN_CROSS_PROFILE_APPS: 3904 displayContent.mAppTransition 3905 .overridePendingAppTransitionStartCrossProfileApps(); 3906 break; 3907 case ANIM_REMOTE_ANIMATION: 3908 displayContent.mAppTransition.overridePendingAppTransitionRemote( 3909 pendingOptions.getRemoteAnimationAdapter()); 3910 break; 3911 case ANIM_NONE: 3912 case ANIM_UNDEFINED: 3913 break; 3914 default: 3915 Slog.e(TAG_WM, "applyOptionsLocked: Unknown animationType=" + animationType); 3916 break; 3917 } 3918 } 3919 clearAllDrawn()3920 void clearAllDrawn() { 3921 allDrawn = false; 3922 } 3923 3924 /** 3925 * Returns whether the drawn window states of this {@link ActivityRecord} has considered every 3926 * child {@link WindowState}. A child is considered if it has been passed into 3927 * {@link #updateDrawnWindowStates(WindowState)} after being added. This is used to determine 3928 * whether states, such as {@code allDrawn}, can be set, which relies on state variables such as 3929 * {@code mNumInterestingWindows}, which depend on all {@link WindowState}s being considered. 3930 * 3931 * @return {@code true} If all children have been considered, {@code false}. 3932 */ allDrawnStatesConsidered()3933 private boolean allDrawnStatesConsidered() { 3934 for (int i = mChildren.size() - 1; i >= 0; --i) { 3935 final WindowState child = mChildren.get(i); 3936 if (child.mightAffectAllDrawn() && !child.getDrawnStateEvaluated()) { 3937 return false; 3938 } 3939 } 3940 return true; 3941 } 3942 3943 /** 3944 * Determines if the token has finished drawing. This should only be called from 3945 * {@link DisplayContent#applySurfaceChangesTransaction} 3946 */ updateAllDrawn()3947 void updateAllDrawn() { 3948 if (!allDrawn) { 3949 // Number of drawn windows can be less when a window is being relaunched, wait for 3950 // all windows to be launched and drawn for this token be considered all drawn. 3951 final int numInteresting = mNumInterestingWindows; 3952 3953 // We must make sure that all present children have been considered (determined by 3954 // {@link #allDrawnStatesConsidered}) before evaluating whether everything has been 3955 // drawn. 3956 if (numInteresting > 0 && allDrawnStatesConsidered() 3957 && mNumDrawnWindows >= numInteresting && !isRelaunching()) { 3958 if (DEBUG_VISIBILITY) Slog.v(TAG, "allDrawn: " + this 3959 + " interesting=" + numInteresting + " drawn=" + mNumDrawnWindows); 3960 allDrawn = true; 3961 // Force an additional layout pass where 3962 // WindowStateAnimator#commitFinishDrawingLocked() will call performShowLocked(). 3963 if (mDisplayContent != null) { 3964 mDisplayContent.setLayoutNeeded(); 3965 } 3966 mWmService.mH.obtainMessage(H.NOTIFY_ACTIVITY_DRAWN, token).sendToTarget(); 3967 } 3968 } 3969 } 3970 getOptionsForTargetActivityLocked()3971 ActivityOptions getOptionsForTargetActivityLocked() { 3972 return pendingOptions != null ? pendingOptions.forTargetActivity() : null; 3973 } 3974 clearOptionsLocked()3975 void clearOptionsLocked() { 3976 clearOptionsLocked(true /* withAbort */); 3977 } 3978 clearOptionsLocked(boolean withAbort)3979 void clearOptionsLocked(boolean withAbort) { 3980 if (withAbort && pendingOptions != null) { 3981 pendingOptions.abort(); 3982 } 3983 pendingOptions = null; 3984 } 3985 takeOptionsLocked(boolean fromClient)3986 ActivityOptions takeOptionsLocked(boolean fromClient) { 3987 if (DEBUG_TRANSITION) Slog.i(TAG, "Taking options for " + this + " callers=" 3988 + Debug.getCallers(6)); 3989 ActivityOptions opts = pendingOptions; 3990 3991 // If we are trying to take activity options from the client, do not null it out if it's a 3992 // remote animation as the client doesn't need it ever. This is a workaround when client is 3993 // faster to take the options than we are to resume the next activity. 3994 // TODO (b/132432864): Fix the root cause of these transition preparing/applying options 3995 // timing somehow 3996 if (!fromClient || opts == null || opts.getRemoteAnimationAdapter() == null) { 3997 pendingOptions = null; 3998 } 3999 return opts; 4000 } 4001 allowMoveToFront()4002 boolean allowMoveToFront() { 4003 return pendingOptions == null || !pendingOptions.getAvoidMoveToFront(); 4004 } 4005 removeUriPermissionsLocked()4006 void removeUriPermissionsLocked() { 4007 if (uriPermissions != null) { 4008 uriPermissions.removeUriPermissions(); 4009 uriPermissions = null; 4010 } 4011 } 4012 pauseKeyDispatchingLocked()4013 void pauseKeyDispatchingLocked() { 4014 if (!keysPaused) { 4015 keysPaused = true; 4016 4017 if (getDisplayContent() != null) { 4018 getDisplayContent().getInputMonitor().pauseDispatchingLw(this); 4019 } 4020 } 4021 } 4022 resumeKeyDispatchingLocked()4023 void resumeKeyDispatchingLocked() { 4024 if (keysPaused) { 4025 keysPaused = false; 4026 4027 if (getDisplayContent() != null) { 4028 getDisplayContent().getInputMonitor().resumeDispatchingLw(this); 4029 } 4030 } 4031 } 4032 updateTaskDescription(CharSequence description)4033 private void updateTaskDescription(CharSequence description) { 4034 task.lastDescription = description; 4035 } 4036 setDeferHidingClient(boolean deferHidingClient)4037 void setDeferHidingClient(boolean deferHidingClient) { 4038 if (mDeferHidingClient == deferHidingClient) { 4039 return; 4040 } 4041 mDeferHidingClient = deferHidingClient; 4042 if (!mDeferHidingClient && !mVisibleRequested) { 4043 // Hiding the client is no longer deferred and the app isn't visible still, go ahead and 4044 // update the visibility. 4045 setVisibility(false); 4046 } 4047 } 4048 4049 @Override isVisible()4050 boolean isVisible() { 4051 // If the activity isn't hidden then it is considered visible and there is no need to check 4052 // its children windows to see if they are visible. 4053 return mVisible; 4054 } 4055 setVisible(boolean visible)4056 void setVisible(boolean visible) { 4057 if (visible != mVisible) { 4058 mVisible = visible; 4059 scheduleAnimation(); 4060 } 4061 } 4062 4063 /** 4064 * Set visibility on this {@link ActivityRecord} 4065 * 4066 * <p class="note"><strong>Note: </strong>This function might not update the visibility of 4067 * this {@link ActivityRecord} immediately. In case we are preparing an app transition, we 4068 * delay changing the visibility of this {@link ActivityRecord} until we execute that 4069 * transition.</p> 4070 * 4071 * @param visible {@code true} if the {@link ActivityRecord} should become visible, otherwise 4072 * this should become invisible. 4073 */ setVisibility(boolean visible)4074 void setVisibility(boolean visible) { 4075 if (getParent() == null) { 4076 Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: " 4077 + appToken); 4078 return; 4079 } 4080 if (visible) { 4081 mDeferHidingClient = false; 4082 } 4083 setVisibility(visible, mDeferHidingClient); 4084 mAtmService.addWindowLayoutReasons( 4085 ActivityTaskManagerService.LAYOUT_REASON_VISIBILITY_CHANGED); 4086 mStackSupervisor.getActivityMetricsLogger().notifyVisibilityChanged(this); 4087 mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true; 4088 } 4089 4090 @VisibleForTesting setVisibility(boolean visible, boolean deferHidingClient)4091 void setVisibility(boolean visible, boolean deferHidingClient) { 4092 final AppTransition appTransition = getDisplayContent().mAppTransition; 4093 4094 // Don't set visibility to false if we were already not visible. This prevents WM from 4095 // adding the app to the closing app list which doesn't make sense for something that is 4096 // already not visible. However, set visibility to true even if we are already visible. 4097 // This makes sure the app is added to the opening apps list so that the right 4098 // transition can be selected. 4099 // TODO: Probably a good idea to separate the concept of opening/closing apps from the 4100 // concept of setting visibility... 4101 if (!visible && !mVisibleRequested) { 4102 4103 if (!deferHidingClient && mLastDeferHidingClient) { 4104 // We previously deferred telling the client to hide itself when visibility was 4105 // initially set to false. Now we would like it to hide, so go ahead and set it. 4106 mLastDeferHidingClient = deferHidingClient; 4107 setClientVisible(false); 4108 } 4109 return; 4110 } 4111 4112 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, 4113 "setAppVisibility(%s, visible=%b): %s visible=%b mVisibleRequested=%b Callers=%s", 4114 appToken, visible, appTransition, isVisible(), mVisibleRequested, 4115 Debug.getCallers(6)); 4116 4117 onChildVisibilityRequested(visible); 4118 4119 final DisplayContent displayContent = getDisplayContent(); 4120 displayContent.mOpeningApps.remove(this); 4121 displayContent.mClosingApps.remove(this); 4122 waitingToShow = false; 4123 mVisibleRequested = visible; 4124 mLastDeferHidingClient = deferHidingClient; 4125 4126 if (!visible) { 4127 // If the app is dead while it was visible, we kept its dead window on screen. 4128 // Now that the app is going invisible, we can remove it. It will be restarted 4129 // if made visible again. 4130 removeDeadWindows(); 4131 } else { 4132 if (!appTransition.isTransitionSet() 4133 && appTransition.isReady()) { 4134 // Add the app mOpeningApps if transition is unset but ready. This means 4135 // we're doing a screen freeze, and the unfreeze will wait for all opening 4136 // apps to be ready. 4137 displayContent.mOpeningApps.add(this); 4138 } 4139 startingMoved = false; 4140 // If the token is currently hidden (should be the common case), or has been 4141 // stopped, then we need to set up to wait for its windows to be ready. 4142 if (!isVisible() || mAppStopped) { 4143 clearAllDrawn(); 4144 4145 // If the app was already visible, don't reset the waitingToShow state. 4146 if (!isVisible()) { 4147 waitingToShow = true; 4148 4149 // If the client isn't hidden, we don't need to reset the drawing state. 4150 if (!isClientVisible()) { 4151 // Let's reset the draw state in order to prevent the starting window to be 4152 // immediately dismissed when the app still has the surface. 4153 forAllWindows(w -> { 4154 if (w.mWinAnimator.mDrawState == HAS_DRAWN) { 4155 w.mWinAnimator.resetDrawState(); 4156 4157 // Force add to mResizingWindows, so that we are guaranteed to get 4158 // another reportDrawn callback. 4159 w.resetLastContentInsets(); 4160 } 4161 }, true /* traverseTopToBottom */); 4162 } 4163 } 4164 } 4165 4166 // In the case where we are making an app visible but holding off for a transition, 4167 // we still need to tell the client to make its windows visible so they get drawn. 4168 // Otherwise, we will wait on performing the transition until all windows have been 4169 // drawn, they never will be, and we are sad. 4170 setClientVisible(true); 4171 4172 requestUpdateWallpaperIfNeeded(); 4173 4174 ProtoLog.v(WM_DEBUG_ADD_REMOVE, "No longer Stopped: %s", this); 4175 mAppStopped = false; 4176 4177 transferStartingWindowFromHiddenAboveTokenIfNeeded(); 4178 } 4179 4180 // If we are preparing an app transition, then delay changing 4181 // the visibility of this token until we execute that transition. 4182 // Note that we ignore display frozen since we want the opening / closing transition type 4183 // can be updated correctly even display frozen, and it's safe since in applyAnimation will 4184 // still check DC#okToAnimate again if the transition animation is fine to apply. 4185 if (okToAnimate(true /* ignoreFrozen */) && appTransition.isTransitionSet()) { 4186 if (visible) { 4187 displayContent.mOpeningApps.add(this); 4188 mEnteringAnimation = true; 4189 } else { 4190 displayContent.mClosingApps.add(this); 4191 mEnteringAnimation = false; 4192 } 4193 if (appTransition.getAppTransition() == TRANSIT_TASK_OPEN_BEHIND) { 4194 // We're launchingBehind, add the launching activity to mOpeningApps. 4195 final WindowState win = getDisplayContent().findFocusedWindow(); 4196 if (win != null) { 4197 final ActivityRecord focusedActivity = win.mActivityRecord; 4198 if (focusedActivity != null) { 4199 ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, 4200 "TRANSIT_TASK_OPEN_BEHIND, adding %s to mOpeningApps", 4201 focusedActivity); 4202 4203 // Force animation to be loaded. 4204 displayContent.mOpeningApps.add(focusedActivity); 4205 } 4206 } 4207 } 4208 return; 4209 } 4210 4211 commitVisibility(visible, true /* performLayout */); 4212 updateReportedVisibilityLocked(); 4213 } 4214 4215 @Override applyAnimation(LayoutParams lp, int transit, boolean enter, boolean isVoiceInteraction, @Nullable ArrayList<WindowContainer> sources)4216 boolean applyAnimation(LayoutParams lp, int transit, boolean enter, 4217 boolean isVoiceInteraction, @Nullable ArrayList<WindowContainer> sources) { 4218 if (mUseTransferredAnimation) { 4219 return false; 4220 } 4221 return super.applyAnimation(lp, transit, enter, isVoiceInteraction, sources); 4222 } 4223 4224 /** 4225 * Update visibility to this {@link ActivityRecord}. 4226 * 4227 * <p class="note"><strong>Note: </strong> Unlike {@link #setVisibility}, this immediately 4228 * updates the visibility without starting an app transition. Since this function may start 4229 * animation on {@link WindowState} depending on app transition animation status, an app 4230 * transition animation must be started before calling this function if necessary.</p> 4231 * 4232 * @param visible {@code true} if this {@link ActivityRecord} should become visible, otherwise 4233 * this should become invisible. 4234 * @param performLayout if {@code true}, perform surface placement after committing visibility. 4235 */ commitVisibility(boolean visible, boolean performLayout)4236 void commitVisibility(boolean visible, boolean performLayout) { 4237 // Reset the state of mHiddenSetFromTransferredStartingWindow since visibility is actually 4238 // been set by the app now. 4239 mVisibleSetFromTransferredStartingWindow = false; 4240 if (visible == isVisible()) { 4241 return; 4242 } 4243 4244 final int windowsCount = mChildren.size(); 4245 for (int i = 0; i < windowsCount; i++) { 4246 mChildren.get(i).onAppVisibilityChanged(visible, isAnimating(PARENTS)); 4247 } 4248 setVisible(visible); 4249 mVisibleRequested = visible; 4250 if (!visible) { 4251 stopFreezingScreen(true, true); 4252 } else { 4253 // If we are being set visible, and the starting window is not yet displayed, 4254 // then make sure it doesn't get displayed. 4255 if (startingWindow != null && !startingWindow.isDrawnLw()) { 4256 startingWindow.clearPolicyVisibilityFlag(LEGACY_POLICY_VISIBILITY); 4257 startingWindow.mLegacyPolicyVisibilityAfterAnim = false; 4258 } 4259 // We are becoming visible, so better freeze the screen with the windows that are 4260 // getting visible so we also wait for them. 4261 forAllWindows(mWmService::makeWindowFreezingScreenIfNeededLocked, true); 4262 } 4263 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, 4264 "commitVisibility: %s: visible=%b mVisibleRequested=%b", this, 4265 isVisible(), mVisibleRequested); 4266 final DisplayContent displayContent = getDisplayContent(); 4267 displayContent.getInputMonitor().setUpdateInputWindowsNeededLw(); 4268 if (performLayout) { 4269 mWmService.updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES, 4270 false /*updateInputWindows*/); 4271 mWmService.mWindowPlacerLocked.performSurfacePlacement(); 4272 } 4273 displayContent.getInputMonitor().updateInputWindowsLw(false /*force*/); 4274 mUseTransferredAnimation = false; 4275 4276 postApplyAnimation(visible); 4277 } 4278 4279 /** 4280 * Post process after applying an app transition animation. 4281 * 4282 * <p class="note"><strong>Note: </strong> This function must be called after the animations 4283 * have been applied and {@link #commitVisibility}.</p> 4284 * 4285 * @param visible {@code true} if this {@link ActivityRecord} has become visible, otherwise 4286 * this has become invisible. 4287 */ postApplyAnimation(boolean visible)4288 private void postApplyAnimation(boolean visible) { 4289 final boolean delayed = isAnimating(PARENTS | CHILDREN); 4290 if (!delayed) { 4291 // We aren't delayed anything, but exiting windows rely on the animation finished 4292 // callback being called in case the ActivityRecord was pretending to be delayed, 4293 // which we might have done because we were in closing/opening apps list. 4294 onAnimationFinished(ANIMATION_TYPE_APP_TRANSITION, null /* AnimationAdapter */); 4295 if (visible) { 4296 // The token was made immediately visible, there will be no entrance animation. 4297 // We need to inform the client the enter animation was finished. 4298 mEnteringAnimation = true; 4299 mWmService.mActivityManagerAppTransitionNotifier.onAppTransitionFinishedLocked( 4300 token); 4301 } 4302 } 4303 4304 // If we're becoming visible, immediately change client visibility as well. there seem 4305 // to be some edge cases where we change our visibility but client visibility never gets 4306 // updated. 4307 // If we're becoming invisible, update the client visibility if we are not running an 4308 // animation. Otherwise, we'll update client visibility in onAnimationFinished. 4309 if (visible || !isAnimating(PARENTS)) { 4310 setClientVisible(visible); 4311 } 4312 4313 final DisplayContent displayContent = getDisplayContent(); 4314 if (!displayContent.mClosingApps.contains(this) 4315 && !displayContent.mOpeningApps.contains(this)) { 4316 // Take the screenshot before possibly hiding the WSA, otherwise the screenshot 4317 // will not be taken. 4318 mWmService.mTaskSnapshotController.notifyAppVisibilityChanged(this, visible); 4319 } 4320 4321 // If we are hidden but there is no delay needed we immediately 4322 // apply the Surface transaction so that the ActivityManager 4323 // can have some guarantee on the Surface state following 4324 // setting the visibility. This captures cases like dismissing 4325 // the docked or pinned stack where there is no app transition. 4326 // 4327 // In the case of a "Null" animation, there will be 4328 // no animation but there will still be a transition set. 4329 // We still need to delay hiding the surface such that it 4330 // can be synchronized with showing the next surface in the transition. 4331 if (!isVisible() && !delayed && !displayContent.mAppTransition.isTransitionSet()) { 4332 SurfaceControl.openTransaction(); 4333 try { 4334 forAllWindows(win -> { 4335 win.mWinAnimator.hide("immediately hidden"); }, true); 4336 } finally { 4337 SurfaceControl.closeTransaction(); 4338 } 4339 } 4340 } 4341 4342 /** 4343 * Check if visibility of this {@link ActivityRecord} should be updated as part of an app 4344 * transition. 4345 * 4346 * <p class="note><strong>Note:</strong> If the visibility of this {@link ActivityRecord} is 4347 * already set to {@link #mVisible}, we don't need to update the visibility. So {@code false} is 4348 * returned.</p> 4349 * 4350 * @param visible {@code true} if this {@link ActivityRecord} should become visible, 4351 * {@code false} if this should become invisible. 4352 * @return {@code true} if visibility of this {@link ActivityRecord} should be updated, and 4353 * an app transition animation should be run. 4354 */ shouldApplyAnimation(boolean visible)4355 boolean shouldApplyAnimation(boolean visible) { 4356 // Allow for state update and animation to be applied if: 4357 // * activity is transitioning visibility state 4358 // * or the activity was marked as hidden and is exiting before we had a chance to play the 4359 // transition animation 4360 // * or this is an opening app and windows are being replaced (e.g. freeform window to 4361 // normal window). 4362 return isVisible() != visible || (!isVisible() && mIsExiting) 4363 || (visible && forAllWindows(WindowState::waitingForReplacement, true)); 4364 } 4365 4366 /** 4367 * See {@link Activity#setDisablePreviewScreenshots}. 4368 */ setDisablePreviewScreenshots(boolean disable)4369 void setDisablePreviewScreenshots(boolean disable) { 4370 mDisablePreviewScreenshots = disable; 4371 } 4372 4373 /** 4374 * Retrieves whether we'd like to generate a snapshot that's based solely on the theme. This is 4375 * the case when preview screenshots are disabled {@link #setDisablePreviewScreenshots} or when 4376 * we can't take a snapshot for other reasons, for example, if we have a secure window. 4377 * 4378 * @return True if we need to generate an app theme snapshot, false if we'd like to take a real 4379 * screenshot. 4380 */ shouldUseAppThemeSnapshot()4381 boolean shouldUseAppThemeSnapshot() { 4382 return mDisablePreviewScreenshots || forAllWindows(WindowState::isSecureLocked, 4383 true /* topToBottom */); 4384 } 4385 4386 /** 4387 * Sets whether the current launch can turn the screen on. 4388 * @see #currentLaunchCanTurnScreenOn() 4389 */ setCurrentLaunchCanTurnScreenOn(boolean currentLaunchCanTurnScreenOn)4390 void setCurrentLaunchCanTurnScreenOn(boolean currentLaunchCanTurnScreenOn) { 4391 mCurrentLaunchCanTurnScreenOn = currentLaunchCanTurnScreenOn; 4392 } 4393 4394 /** 4395 * Indicates whether the current launch can turn the screen on. This is to prevent multiple 4396 * relayouts from turning the screen back on. The screen should only turn on at most 4397 * once per activity resume. 4398 * <p> 4399 * Note this flag is only meaningful when {@link WindowManager.LayoutParams#FLAG_TURN_SCREEN_ON} 4400 * or {@link ActivityRecord#canTurnScreenOn} is set. 4401 * 4402 * @return {@code true} if the activity is ready to turn on the screen. 4403 */ currentLaunchCanTurnScreenOn()4404 boolean currentLaunchCanTurnScreenOn() { 4405 return mCurrentLaunchCanTurnScreenOn; 4406 } 4407 setState(ActivityState state, String reason)4408 void setState(ActivityState state, String reason) { 4409 if (DEBUG_STATES) Slog.v(TAG_STATES, "State movement: " + this + " from:" + getState() 4410 + " to:" + state + " reason:" + reason); 4411 4412 if (state == mState) { 4413 // No need to do anything if state doesn't change. 4414 if (DEBUG_STATES) Slog.v(TAG_STATES, "State unchanged from:" + state); 4415 return; 4416 } 4417 4418 mState = state; 4419 4420 if (task != null) { 4421 task.onActivityStateChanged(this, state, reason); 4422 } 4423 4424 // The WindowManager interprets the app stopping signal as 4425 // an indication that the Surface will eventually be destroyed. 4426 // This however isn't necessarily true if we are going to sleep. 4427 if (state == STOPPING && !isSleeping()) { 4428 if (getParent() == null) { 4429 Slog.w(TAG_WM, "Attempted to notify stopping on non-existing app token: " 4430 + appToken); 4431 return; 4432 } 4433 detachChildren(); 4434 } 4435 4436 if (state == RESUMED) { 4437 mAtmService.updateBatteryStats(this, true); 4438 mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_RESUMED); 4439 } else if (state == PAUSED) { 4440 mAtmService.updateBatteryStats(this, false); 4441 mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_PAUSED); 4442 } else if (state == STOPPED) { 4443 mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_STOPPED); 4444 } else if (state == DESTROYED) { 4445 mAtmService.updateActivityUsageStats(this, Event.ACTIVITY_DESTROYED); 4446 } 4447 } 4448 getState()4449 ActivityState getState() { 4450 return mState; 4451 } 4452 4453 /** 4454 * Returns {@code true} if the Activity is in the specified state. 4455 */ isState(ActivityState state)4456 boolean isState(ActivityState state) { 4457 return state == mState; 4458 } 4459 4460 /** 4461 * Returns {@code true} if the Activity is in one of the specified states. 4462 */ isState(ActivityState state1, ActivityState state2)4463 boolean isState(ActivityState state1, ActivityState state2) { 4464 return state1 == mState || state2 == mState; 4465 } 4466 4467 /** 4468 * Returns {@code true} if the Activity is in one of the specified states. 4469 */ isState(ActivityState state1, ActivityState state2, ActivityState state3)4470 boolean isState(ActivityState state1, ActivityState state2, ActivityState state3) { 4471 return state1 == mState || state2 == mState || state3 == mState; 4472 } 4473 4474 /** 4475 * Returns {@code true} if the Activity is in one of the specified states. 4476 */ isState(ActivityState state1, ActivityState state2, ActivityState state3, ActivityState state4)4477 boolean isState(ActivityState state1, ActivityState state2, ActivityState state3, 4478 ActivityState state4) { 4479 return state1 == mState || state2 == mState || state3 == mState || state4 == mState; 4480 } 4481 4482 /** 4483 * Returns {@code true} if the Activity is in one of the specified states. 4484 */ isState(ActivityState state1, ActivityState state2, ActivityState state3, ActivityState state4, ActivityState state5)4485 boolean isState(ActivityState state1, ActivityState state2, ActivityState state3, 4486 ActivityState state4, ActivityState state5) { 4487 return state1 == mState || state2 == mState || state3 == mState || state4 == mState 4488 || state5 == mState; 4489 } 4490 4491 /** 4492 * Returns {@code true} if the Activity is in one of the specified states. 4493 */ isState(ActivityState state1, ActivityState state2, ActivityState state3, ActivityState state4, ActivityState state5, ActivityState state6)4494 boolean isState(ActivityState state1, ActivityState state2, ActivityState state3, 4495 ActivityState state4, ActivityState state5, ActivityState state6) { 4496 return state1 == mState || state2 == mState || state3 == mState || state4 == mState 4497 || state5 == mState || state6 == mState; 4498 } 4499 destroySurfaces()4500 void destroySurfaces() { 4501 destroySurfaces(false /*cleanupOnResume*/); 4502 } 4503 4504 /** 4505 * Destroy surfaces which have been marked as eligible by the animator, taking care to ensure 4506 * the client has finished with them. 4507 * 4508 * @param cleanupOnResume whether this is done when app is resumed without fully stopped. If 4509 * set to true, destroy only surfaces of removed windows, and clear relevant flags of the 4510 * others so that they are ready to be reused. If set to false (common case), destroy all 4511 * surfaces that's eligible, if the app is already stopped. 4512 */ destroySurfaces(boolean cleanupOnResume)4513 private void destroySurfaces(boolean cleanupOnResume) { 4514 boolean destroyedSomething = false; 4515 4516 // Copying to a different list as multiple children can be removed. 4517 final ArrayList<WindowState> children = new ArrayList<>(mChildren); 4518 for (int i = children.size() - 1; i >= 0; i--) { 4519 final WindowState win = children.get(i); 4520 destroyedSomething |= win.destroySurface(cleanupOnResume, mAppStopped); 4521 } 4522 if (destroyedSomething) { 4523 final DisplayContent dc = getDisplayContent(); 4524 dc.assignWindowLayers(true /*setLayoutNeeded*/); 4525 updateLetterboxSurface(null); 4526 } 4527 } 4528 notifyAppResumed(boolean wasStopped)4529 void notifyAppResumed(boolean wasStopped) { 4530 if (getParent() == null) { 4531 Slog.w(TAG_WM, "Attempted to notify resumed of non-existing app token: " 4532 + appToken); 4533 return; 4534 } 4535 ProtoLog.v(WM_DEBUG_ADD_REMOVE, "notifyAppResumed: wasStopped=%b %s", 4536 wasStopped, this); 4537 mAppStopped = false; 4538 // Allow the window to turn the screen on once the app is resumed again. 4539 setCurrentLaunchCanTurnScreenOn(true); 4540 if (!wasStopped) { 4541 destroySurfaces(true /*cleanupOnResume*/); 4542 } 4543 } 4544 4545 /** 4546 * Notify that the app has stopped, and it is okay to destroy any surfaces which were 4547 * keeping alive in case they were still being used. 4548 */ notifyAppStopped()4549 void notifyAppStopped() { 4550 ProtoLog.v(WM_DEBUG_ADD_REMOVE, "notifyAppStopped: %s", this); 4551 mAppStopped = true; 4552 // Reset the last saved PiP snap fraction on app stop. 4553 mDisplayContent.mPinnedStackControllerLocked.onActivityHidden(mActivityComponent); 4554 destroySurfaces(); 4555 // Remove any starting window that was added for this app if they are still around. 4556 removeStartingWindow(); 4557 } 4558 4559 /** 4560 * Suppress transition until the new activity becomes ready, otherwise the keyguard can appear 4561 * for a short amount of time before the new process with the new activity had the ability to 4562 * set its showWhenLocked flags. 4563 */ notifyUnknownVisibilityLaunchedForKeyguardTransition()4564 void notifyUnknownVisibilityLaunchedForKeyguardTransition() { 4565 // No display activities never add a window, so there is no point in waiting them for 4566 // relayout. 4567 if (noDisplay || !mStackSupervisor.getKeyguardController().isKeyguardLocked()) { 4568 return; 4569 } 4570 4571 mDisplayContent.mUnknownAppVisibilityController.notifyLaunched(this); 4572 } 4573 4574 /** @return {@code true} if this activity should be made visible. */ shouldBeVisible(boolean behindFullscreenActivity, boolean ignoringKeyguard)4575 boolean shouldBeVisible(boolean behindFullscreenActivity, boolean ignoringKeyguard) { 4576 // Check whether activity should be visible without Keyguard influence 4577 visibleIgnoringKeyguard = (!behindFullscreenActivity || mLaunchTaskBehind) 4578 && okToShowLocked(); 4579 4580 if (ignoringKeyguard) { 4581 return visibleIgnoringKeyguard; 4582 } 4583 4584 final ActivityStack stack = getRootTask(); 4585 if (stack == null) { 4586 return false; 4587 } 4588 4589 // Activity in a pinned stack should not be visible if the stack is in force hidden state. 4590 // Typically due to the FLAG_FORCE_HIDDEN_FOR_PINNED_TASK set on the stack, which is a 4591 // work around to send onStop before windowing mode change callbacks. 4592 // See also ActivityStackSupervisor#removePinnedStackInSurfaceTransaction 4593 // TODO: Should we ever be visible if the stack/task is invisible? 4594 if (inPinnedWindowingMode() && stack.isForceHidden()) { 4595 return false; 4596 } 4597 4598 // Now check whether it's really visible depending on Keyguard state, and update 4599 // {@link ActivityStack} internal states. 4600 // Inform the method if this activity is the top activity of this stack, but exclude the 4601 // case where this is the top activity in a pinned stack. 4602 final boolean isTop = this == stack.getTopNonFinishingActivity(); 4603 final boolean isTopNotPinnedStack = stack.isAttached() 4604 && stack.getDisplayArea().isTopNotPinnedStack(stack); 4605 final boolean visibleIgnoringDisplayStatus = stack.checkKeyguardVisibility(this, 4606 visibleIgnoringKeyguard, isTop && isTopNotPinnedStack); 4607 4608 // Check if the activity is on a sleeping display, and if it can turn it ON. 4609 // TODO(b/163993448): Do not make activity visible before display awake. 4610 if (visibleIgnoringDisplayStatus && getDisplay().isSleeping()) { 4611 return !mSetToSleep || canTurnScreenOn(); 4612 } 4613 4614 return visibleIgnoringDisplayStatus; 4615 } 4616 shouldBeVisible()4617 boolean shouldBeVisible() { 4618 final ActivityStack stack = getRootTask(); 4619 if (stack == null) { 4620 return false; 4621 } 4622 4623 final boolean behindFullscreenActivity = stack.checkBehindFullscreenActivity( 4624 this, null /* handleBehindFullscreenActivity */); 4625 return shouldBeVisible(behindFullscreenActivity, false /* ignoringKeyguard */); 4626 } 4627 makeVisibleIfNeeded(ActivityRecord starting, boolean reportToClient)4628 void makeVisibleIfNeeded(ActivityRecord starting, boolean reportToClient) { 4629 // This activity is not currently visible, but is running. Tell it to become visible. 4630 if (mState == RESUMED || this == starting) { 4631 if (DEBUG_VISIBILITY) Slog.d(TAG_VISIBILITY, 4632 "Not making visible, r=" + this + " state=" + mState + " starting=" + starting); 4633 return; 4634 } 4635 4636 // If this activity is paused, tell it to now show its window. 4637 if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, 4638 "Making visible and scheduling visibility: " + this); 4639 final ActivityStack stack = getRootTask(); 4640 try { 4641 if (stack.mTranslucentActivityWaiting != null) { 4642 updateOptionsLocked(returningOptions); 4643 stack.mUndrawnActivitiesBelowTopTranslucent.add(this); 4644 } 4645 setVisibility(true); 4646 mSetToSleep = false; 4647 app.postPendingUiCleanMsg(true); 4648 if (reportToClient) { 4649 mClientVisibilityDeferred = false; 4650 makeActiveIfNeeded(starting); 4651 } else { 4652 mClientVisibilityDeferred = true; 4653 } 4654 // The activity may be waiting for stop, but that is no longer appropriate for it. 4655 mStackSupervisor.mStoppingActivities.remove(this); 4656 } catch (Exception e) { 4657 // Just skip on any failure; we'll make it visible when it next restarts. 4658 Slog.w(TAG, "Exception thrown making visible: " + intent.getComponent(), e); 4659 } 4660 handleAlreadyVisible(); 4661 } 4662 makeInvisible()4663 void makeInvisible() { 4664 if (!mVisibleRequested) { 4665 if (DEBUG_VISIBILITY) Slog.v(TAG_VISIBILITY, "Already invisible: " + this); 4666 return; 4667 } 4668 // Now for any activities that aren't visible to the user, make sure they no longer are 4669 // keeping the screen frozen. 4670 if (DEBUG_VISIBILITY) { 4671 Slog.v(TAG_VISIBILITY, "Making invisible: " + this + ", state=" + getState()); 4672 } 4673 try { 4674 final boolean canEnterPictureInPicture = checkEnterPictureInPictureState( 4675 "makeInvisible", true /* beforeStopping */); 4676 // Defer telling the client it is hidden if it can enter Pip and isn't current paused, 4677 // stopped or stopping. This gives it a chance to enter Pip in onPause(). 4678 // TODO: There is still a question surrounding activities in multi-window mode that want 4679 // to enter Pip after they are paused, but are still visible. I they should be okay to 4680 // enter Pip in those cases, but not "auto-Pip" which is what this condition covers and 4681 // the current contract for "auto-Pip" is that the app should enter it before onPause 4682 // returns. Just need to confirm this reasoning makes sense. 4683 final boolean deferHidingClient = canEnterPictureInPicture 4684 && !isState(STARTED, STOPPING, STOPPED, PAUSED); 4685 setDeferHidingClient(deferHidingClient); 4686 setVisibility(false); 4687 4688 switch (getState()) { 4689 case STOPPING: 4690 case STOPPED: 4691 // Reset the flag indicating that an app can enter picture-in-picture once the 4692 // activity is hidden 4693 supportsEnterPipOnTaskSwitch = false; 4694 break; 4695 case RESUMED: 4696 // If the app is capable of entering PIP, we should try pausing it now 4697 // so it can PIP correctly. 4698 if (deferHidingClient) { 4699 getRootTask().startPausingLocked( 4700 mStackSupervisor.mUserLeaving /* userLeaving */, 4701 false /* uiSleeping */, null /* resuming */); 4702 break; 4703 } 4704 case INITIALIZING: 4705 case PAUSING: 4706 case PAUSED: 4707 case STARTED: 4708 addToStopping(true /* scheduleIdle */, 4709 canEnterPictureInPicture /* idleDelayed */, "makeInvisible"); 4710 break; 4711 4712 default: 4713 break; 4714 } 4715 } catch (Exception e) { 4716 // Just skip on any failure; we'll make it visible when it next restarts. 4717 Slog.w(TAG, "Exception thrown making hidden: " + intent.getComponent(), e); 4718 } 4719 } 4720 4721 /** 4722 * Make activity resumed or paused if needed. 4723 * @param activeActivity an activity that is resumed or just completed pause action. 4724 * We won't change the state of this activity. 4725 */ makeActiveIfNeeded(ActivityRecord activeActivity)4726 boolean makeActiveIfNeeded(ActivityRecord activeActivity) { 4727 if (shouldResumeActivity(activeActivity)) { 4728 if (DEBUG_VISIBILITY) { 4729 Slog.v(TAG_VISIBILITY, "Resume visible activity, " + this); 4730 } 4731 return getRootTask().resumeTopActivityUncheckedLocked(activeActivity /* prev */, 4732 null /* options */); 4733 } else if (shouldPauseActivity(activeActivity)) { 4734 if (DEBUG_VISIBILITY) { 4735 Slog.v(TAG_VISIBILITY, "Pause visible activity, " + this); 4736 } 4737 // An activity must be in the {@link PAUSING} state for the system to validate 4738 // the move to {@link PAUSED}. 4739 setState(PAUSING, "makeActiveIfNeeded"); 4740 try { 4741 mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, 4742 PauseActivityItem.obtain(finishing, false /* userLeaving */, 4743 configChangeFlags, false /* dontReport */)); 4744 } catch (Exception e) { 4745 Slog.w(TAG, "Exception thrown sending pause: " + intent.getComponent(), e); 4746 } 4747 } else if (shouldStartActivity()) { 4748 if (DEBUG_VISIBILITY) { 4749 Slog.v(TAG_VISIBILITY, "Start visible activity, " + this); 4750 } 4751 setState(STARTED, "makeActiveIfNeeded"); 4752 4753 // Update process info while making an activity from invisible to visible, to make 4754 // sure the process state is updated to foreground. 4755 if (app != null) { 4756 app.updateProcessInfo(false /* updateServiceConnectionActivities */, 4757 true /* activityChange */, true /* updateOomAdj */, 4758 true /* addPendingTopUid */); 4759 } 4760 4761 try { 4762 mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, 4763 StartActivityItem.obtain()); 4764 } catch (Exception e) { 4765 Slog.w(TAG, "Exception thrown sending start: " + intent.getComponent(), e); 4766 } 4767 // The activity may be waiting for stop, but that is no longer appropriate if we are 4768 // starting the activity again 4769 mStackSupervisor.mStoppingActivities.remove(this); 4770 } 4771 return false; 4772 } 4773 4774 /** 4775 * Check if activity should be moved to PAUSED state. The activity: 4776 * - should be eligible to be made active (see {@link #shouldMakeActive(ActivityRecord)}) 4777 * - should be non-focusable 4778 * - should not be currently pausing or paused 4779 * @param activeActivity the activity that is active or just completed pause action. We won't 4780 * resume if this activity is active. 4781 */ 4782 @VisibleForTesting shouldPauseActivity(ActivityRecord activeActivity)4783 boolean shouldPauseActivity(ActivityRecord activeActivity) { 4784 return shouldMakeActive(activeActivity) && !isFocusable() && !isState(PAUSING, PAUSED) 4785 // We will only allow pausing if results is null, otherwise it will cause this 4786 // activity to resume before getting result 4787 && (results == null); 4788 } 4789 4790 /** 4791 * Check if activity should be moved to RESUMED state. 4792 * See {@link #shouldBeResumed(ActivityRecord)} 4793 * @param activeActivity the activity that is active or just completed pause action. We won't 4794 * resume if this activity is active. 4795 */ 4796 @VisibleForTesting shouldResumeActivity(ActivityRecord activeActivity)4797 boolean shouldResumeActivity(ActivityRecord activeActivity) { 4798 return shouldBeResumed(activeActivity) && !isState(RESUMED); 4799 } 4800 4801 /** 4802 * Check if activity should be RESUMED now. The activity: 4803 * - should be eligible to be made active (see {@link #shouldMakeActive(ActivityRecord)}) 4804 * - should be focusable 4805 */ shouldBeResumed(ActivityRecord activeActivity)4806 private boolean shouldBeResumed(ActivityRecord activeActivity) { 4807 return shouldMakeActive(activeActivity) && isFocusable() 4808 && getTask().getVisibility(activeActivity) == STACK_VISIBILITY_VISIBLE 4809 && canResumeByCompat(); 4810 } 4811 4812 /** 4813 * Check if activity should be moved to STARTED state. 4814 * NOTE: This will not check if activity should be made paused or resumed first, so it must only 4815 * be called after checking with {@link #shouldResumeActivity(ActivityRecord)} 4816 * and {@link #shouldPauseActivity(ActivityRecord)}. 4817 */ shouldStartActivity()4818 private boolean shouldStartActivity() { 4819 return mVisibleRequested && (isState(STOPPED) || isState(STOPPING)); 4820 } 4821 4822 /** 4823 * Check if activity is eligible to be made active (resumed of paused). The activity: 4824 * - should be paused, stopped or stopping 4825 * - should not be the currently active one or launching behind other tasks 4826 * - should be either the topmost in task, or right below the top activity that is finishing 4827 * If all of these conditions are not met at the same time, the activity cannot be made active. 4828 */ 4829 @VisibleForTesting shouldMakeActive(ActivityRecord activeActivity)4830 boolean shouldMakeActive(ActivityRecord activeActivity) { 4831 // If the activity is stopped, stopping, cycle to an active state. We avoid doing 4832 // this when there is an activity waiting to become translucent as the extra binder 4833 // calls will lead to noticeable jank. A later call to 4834 // ActivityStack#ensureActivitiesVisible will bring the activity to a proper 4835 // active state. 4836 if (!isState(STARTED, RESUMED, PAUSED, STOPPED, STOPPING) 4837 || getRootTask().mTranslucentActivityWaiting != null) { 4838 return false; 4839 } 4840 4841 if (this == activeActivity) { 4842 return false; 4843 } 4844 4845 if (!mStackSupervisor.readyToResume()) { 4846 // Making active is currently deferred (e.g. because an activity launch is in progress). 4847 return false; 4848 } 4849 4850 if (this.mLaunchTaskBehind) { 4851 // This activity is being launched from behind, which means that it's not intended to be 4852 // presented to user right now, even if it's set to be visible. 4853 return false; 4854 } 4855 4856 // Check if position in task allows to become paused 4857 if (!task.hasChild(this)) { 4858 throw new IllegalStateException("Activity not found in its task"); 4859 } 4860 return task.topRunningActivity() == this; 4861 } 4862 handleAlreadyVisible()4863 void handleAlreadyVisible() { 4864 stopFreezingScreenLocked(false); 4865 try { 4866 if (returningOptions != null) { 4867 app.getThread().scheduleOnNewActivityOptions(appToken, returningOptions.toBundle()); 4868 } 4869 } catch(RemoteException e) { 4870 } 4871 } 4872 activityResumedLocked(IBinder token)4873 static void activityResumedLocked(IBinder token) { 4874 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 4875 if (DEBUG_SAVED_STATE) Slog.i(TAG_STATES, "Resumed activity; dropping state of: " + r); 4876 if (r == null) { 4877 // If an app reports resumed after a long delay, the record on server side might have 4878 // been removed (e.g. destroy timeout), so the token could be null. 4879 return; 4880 } 4881 r.setSavedState(null /* savedState */); 4882 4883 final DisplayContent display = r.getDisplay(); 4884 if (display != null) { 4885 display.handleActivitySizeCompatModeIfNeeded(r); 4886 } 4887 4888 r.getDisplayContent().mUnknownAppVisibilityController.notifyAppResumedFinished(r); 4889 } 4890 4891 /** 4892 * Once we know that we have asked an application to put an activity in the resumed state 4893 * (either by launching it or explicitly telling it), this function updates the rest of our 4894 * state to match that fact. 4895 */ completeResumeLocked()4896 void completeResumeLocked() { 4897 final boolean wasVisible = mVisibleRequested; 4898 setVisibility(true); 4899 if (!wasVisible) { 4900 // Visibility has changed, so take a note of it so we call the TaskStackChangedListener 4901 mStackSupervisor.mAppVisibilitiesChangedSinceLastPause = true; 4902 } 4903 idle = false; 4904 results = null; 4905 if (newIntents != null && newIntents.size() > 0) { 4906 mLastNewIntent = newIntents.get(newIntents.size() - 1); 4907 } 4908 newIntents = null; 4909 stopped = false; 4910 4911 if (isActivityTypeHome()) { 4912 mStackSupervisor.updateHomeProcess(task.getBottomMostActivity().app); 4913 } 4914 4915 if (nowVisible) { 4916 mStackSupervisor.stopWaitingForActivityVisible(this); 4917 } 4918 4919 // Schedule an idle timeout in case the app doesn't do it for us. 4920 mStackSupervisor.scheduleIdleTimeout(this); 4921 4922 mStackSupervisor.reportResumedActivityLocked(this); 4923 4924 resumeKeyDispatchingLocked(); 4925 final ActivityStack stack = getRootTask(); 4926 mStackSupervisor.mNoAnimActivities.clear(); 4927 4928 // Mark the point when the activity is resuming 4929 // TODO: To be more accurate, the mark should be before the onCreate, 4930 // not after the onResume. But for subsequent starts, onResume is fine. 4931 if (hasProcess()) { 4932 cpuTimeAtResume = app.getCpuTime(); 4933 } else { 4934 cpuTimeAtResume = 0; // Couldn't get the cpu time of process 4935 } 4936 4937 returningOptions = null; 4938 4939 if (canTurnScreenOn()) { 4940 mStackSupervisor.wakeUp("turnScreenOnFlag"); 4941 } else { 4942 // If the screen is going to turn on because the caller explicitly requested it and 4943 // the keyguard is not showing don't attempt to sleep. Otherwise the Activity will 4944 // pause and then resume again later, which will result in a double life-cycle event. 4945 stack.checkReadyForSleep(); 4946 } 4947 } 4948 activityPaused(boolean timeout)4949 void activityPaused(boolean timeout) { 4950 if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, 4951 "Activity paused: token=" + appToken + ", timeout=" + timeout); 4952 4953 final ActivityStack stack = getStack(); 4954 4955 if (stack != null) { 4956 removePauseTimeout(); 4957 4958 if (stack.mPausingActivity == this) { 4959 if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to PAUSED: " + this 4960 + (timeout ? " (due to timeout)" : " (pause complete)")); 4961 mAtmService.deferWindowLayout(); 4962 try { 4963 stack.completePauseLocked(true /* resumeNext */, null /* resumingActivity */); 4964 } finally { 4965 mAtmService.continueWindowLayout(); 4966 } 4967 return; 4968 } else { 4969 EventLogTags.writeWmFailedToPause(mUserId, System.identityHashCode(this), 4970 shortComponentName, stack.mPausingActivity != null 4971 ? stack.mPausingActivity.shortComponentName : "(none)"); 4972 if (isState(PAUSING)) { 4973 setState(PAUSED, "activityPausedLocked"); 4974 if (finishing) { 4975 if (DEBUG_PAUSE) Slog.v(TAG, 4976 "Executing finish of failed to pause activity: " + this); 4977 completeFinishing("activityPausedLocked"); 4978 } 4979 } 4980 } 4981 } 4982 4983 mRootWindowContainer.ensureActivitiesVisible(null, 0, !PRESERVE_WINDOWS); 4984 } 4985 4986 /** 4987 * Schedule a pause timeout in case the app doesn't respond. We don't give it much time because 4988 * this directly impacts the responsiveness seen by the user. 4989 */ schedulePauseTimeout()4990 void schedulePauseTimeout() { 4991 pauseTime = SystemClock.uptimeMillis(); 4992 mAtmService.mH.postDelayed(mPauseTimeoutRunnable, PAUSE_TIMEOUT); 4993 if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Waiting for pause to complete..."); 4994 } 4995 removePauseTimeout()4996 private void removePauseTimeout() { 4997 mAtmService.mH.removeCallbacks(mPauseTimeoutRunnable); 4998 } 4999 removeDestroyTimeout()5000 private void removeDestroyTimeout() { 5001 mAtmService.mH.removeCallbacks(mDestroyTimeoutRunnable); 5002 } 5003 removeStopTimeout()5004 private void removeStopTimeout() { 5005 mAtmService.mH.removeCallbacks(mStopTimeoutRunnable); 5006 } 5007 removeTimeouts()5008 void removeTimeouts() { 5009 mStackSupervisor.removeIdleTimeoutForActivity(this); 5010 removePauseTimeout(); 5011 removeStopTimeout(); 5012 removeDestroyTimeout(); 5013 finishLaunchTickingLocked(); 5014 } 5015 stopIfPossible()5016 void stopIfPossible() { 5017 if (DEBUG_SWITCH) Slog.d(TAG_SWITCH, "Stopping: " + this); 5018 final ActivityStack stack = getRootTask(); 5019 if (isNoHistory()) { 5020 if (!finishing) { 5021 if (!stack.shouldSleepActivities()) { 5022 if (DEBUG_STATES) Slog.d(TAG_STATES, "no-history finish of " + this); 5023 if (finishIfPossible("stop-no-history", false /* oomAdj */) 5024 != FINISH_RESULT_CANCELLED) { 5025 resumeKeyDispatchingLocked(); 5026 return; 5027 } 5028 } else { 5029 if (DEBUG_STATES) { 5030 Slog.d(TAG_STATES, "Not finishing noHistory " + this 5031 + " on stop because we're just sleeping"); 5032 } 5033 } 5034 } 5035 } 5036 5037 if (!attachedToProcess()) { 5038 return; 5039 } 5040 resumeKeyDispatchingLocked(); 5041 try { 5042 stopped = false; 5043 if (DEBUG_STATES) { 5044 Slog.v(TAG_STATES, "Moving to STOPPING: " + this + " (stop requested)"); 5045 } 5046 setState(STOPPING, "stopIfPossible"); 5047 if (DEBUG_VISIBILITY) { 5048 Slog.v(TAG_VISIBILITY, "Stopping:" + this); 5049 } 5050 EventLogTags.writeWmStopActivity( 5051 mUserId, System.identityHashCode(this), shortComponentName); 5052 mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, 5053 StopActivityItem.obtain(configChangeFlags)); 5054 5055 if (stack.shouldSleepOrShutDownActivities()) { 5056 setSleeping(true); 5057 } 5058 mAtmService.mH.postDelayed(mStopTimeoutRunnable, STOP_TIMEOUT); 5059 } catch (Exception e) { 5060 // Maybe just ignore exceptions here... if the process has crashed, our death 5061 // notification will clean things up. 5062 Slog.w(TAG, "Exception thrown during pause", e); 5063 // Just in case, assume it to be stopped. 5064 stopped = true; 5065 if (DEBUG_STATES) Slog.v(TAG_STATES, "Stop failed; moving to STOPPED: " + this); 5066 setState(STOPPED, "stopIfPossible"); 5067 if (deferRelaunchUntilPaused) { 5068 destroyImmediately(true /* removeFromApp */, "stop-except"); 5069 } 5070 } 5071 } 5072 activityStopped(Bundle newIcicle, PersistableBundle newPersistentState, CharSequence description)5073 void activityStopped(Bundle newIcicle, PersistableBundle newPersistentState, 5074 CharSequence description) { 5075 final ActivityStack stack = getRootTask(); 5076 final boolean isStopping = mState == STOPPING; 5077 if (!isStopping && mState != RESTARTING_PROCESS) { 5078 Slog.i(TAG, "Activity reported stop, but no longer stopping: " + this); 5079 removeStopTimeout(); 5080 return; 5081 } 5082 if (newPersistentState != null) { 5083 mPersistentState = newPersistentState; 5084 mAtmService.notifyTaskPersisterLocked(task, false); 5085 } 5086 5087 if (newIcicle != null) { 5088 // If icicle is null, this is happening due to a timeout, so we haven't really saved 5089 // the state. 5090 setSavedState(newIcicle); 5091 launchCount = 0; 5092 updateTaskDescription(description); 5093 } 5094 if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE, "Saving icicle of " + this + ": " + mIcicle); 5095 if (!stopped) { 5096 if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to STOPPED: " + this + " (stop complete)"); 5097 removeStopTimeout(); 5098 stopped = true; 5099 if (isStopping) { 5100 setState(STOPPED, "activityStoppedLocked"); 5101 } 5102 5103 notifyAppStopped(); 5104 5105 if (finishing) { 5106 clearOptionsLocked(); 5107 } else { 5108 if (deferRelaunchUntilPaused) { 5109 destroyImmediately(true /* removeFromApp */, "stop-config"); 5110 mRootWindowContainer.resumeFocusedStacksTopActivities(); 5111 } else { 5112 mRootWindowContainer.updatePreviousProcess(this); 5113 } 5114 } 5115 } 5116 } 5117 addToStopping(boolean scheduleIdle, boolean idleDelayed, String reason)5118 void addToStopping(boolean scheduleIdle, boolean idleDelayed, String reason) { 5119 if (!mStackSupervisor.mStoppingActivities.contains(this)) { 5120 EventLogTags.writeWmAddToStopping(mUserId, System.identityHashCode(this), 5121 shortComponentName, reason); 5122 mStackSupervisor.mStoppingActivities.add(this); 5123 } 5124 5125 final ActivityStack stack = getRootTask(); 5126 // If we already have a few activities waiting to stop, then give up on things going idle 5127 // and start clearing them out. Or if r is the last of activity of the last task the stack 5128 // will be empty and must be cleared immediately. 5129 boolean forceIdle = mStackSupervisor.mStoppingActivities.size() > MAX_STOPPING_TO_FORCE 5130 || (isRootOfTask() && stack.getChildCount() <= 1); 5131 if (scheduleIdle || forceIdle) { 5132 if (DEBUG_PAUSE) { 5133 Slog.v(TAG_PAUSE, "Scheduling idle now: forceIdle=" + forceIdle 5134 + "immediate=" + !idleDelayed); 5135 } 5136 if (!idleDelayed) { 5137 mStackSupervisor.scheduleIdle(); 5138 } else { 5139 mStackSupervisor.scheduleIdleTimeout(this); 5140 } 5141 } else { 5142 stack.checkReadyForSleep(); 5143 } 5144 } 5145 startLaunchTickingLocked()5146 void startLaunchTickingLocked() { 5147 if (Build.IS_USER) { 5148 return; 5149 } 5150 if (launchTickTime == 0) { 5151 launchTickTime = SystemClock.uptimeMillis(); 5152 continueLaunchTicking(); 5153 } 5154 } 5155 continueLaunchTicking()5156 private boolean continueLaunchTicking() { 5157 if (launchTickTime == 0) { 5158 return false; 5159 } 5160 5161 final ActivityStack stack = getRootTask(); 5162 if (stack == null) { 5163 return false; 5164 } 5165 5166 stack.removeLaunchTickMessages(); 5167 mAtmService.mH.postDelayed(mLaunchTickRunnable, LAUNCH_TICK); 5168 return true; 5169 } 5170 removeLaunchTickRunnable()5171 void removeLaunchTickRunnable() { 5172 mAtmService.mH.removeCallbacks(mLaunchTickRunnable); 5173 } 5174 finishLaunchTickingLocked()5175 void finishLaunchTickingLocked() { 5176 launchTickTime = 0; 5177 final ActivityStack stack = getRootTask(); 5178 if (stack == null) { 5179 return; 5180 } 5181 stack.removeLaunchTickMessages(); 5182 } 5183 mayFreezeScreenLocked()5184 boolean mayFreezeScreenLocked() { 5185 return mayFreezeScreenLocked(app); 5186 } 5187 mayFreezeScreenLocked(WindowProcessController app)5188 private boolean mayFreezeScreenLocked(WindowProcessController app) { 5189 // Only freeze the screen if this activity is currently attached to 5190 // an application, and that application is not blocked or unresponding. 5191 // In any other case, we can't count on getting the screen unfrozen, 5192 // so it is best to leave as-is. 5193 return hasProcess() && !app.isCrashing() && !app.isNotResponding(); 5194 } 5195 startFreezingScreenLocked(int configChanges)5196 void startFreezingScreenLocked(int configChanges) { 5197 startFreezingScreenLocked(app, configChanges); 5198 } 5199 startFreezingScreenLocked(WindowProcessController app, int configChanges)5200 void startFreezingScreenLocked(WindowProcessController app, int configChanges) { 5201 if (mayFreezeScreenLocked(app)) { 5202 if (getParent() == null) { 5203 Slog.w(TAG_WM, 5204 "Attempted to freeze screen with non-existing app token: " + appToken); 5205 return; 5206 } 5207 5208 // Window configuration changes only effect windows, so don't require a screen freeze. 5209 int freezableConfigChanges = configChanges & ~(CONFIG_WINDOW_CONFIGURATION); 5210 if (freezableConfigChanges == 0 && okToDisplay()) { 5211 ProtoLog.v(WM_DEBUG_ORIENTATION, "Skipping set freeze of %s", appToken); 5212 return; 5213 } 5214 5215 startFreezingScreen(); 5216 } 5217 } 5218 startFreezingScreen()5219 void startFreezingScreen() { 5220 startFreezingScreen(ROTATION_UNDEFINED /* overrideOriginalDisplayRotation */); 5221 } 5222 startFreezingScreen(int overrideOriginalDisplayRotation)5223 void startFreezingScreen(int overrideOriginalDisplayRotation) { 5224 ProtoLog.i(WM_DEBUG_ORIENTATION, 5225 "Set freezing of %s: visible=%b freezing=%b visibleRequested=%b. %s", 5226 appToken, isVisible(), mFreezingScreen, mVisibleRequested, 5227 new RuntimeException().fillInStackTrace()); 5228 if (!mVisibleRequested) { 5229 return; 5230 } 5231 5232 // If the override is given, the rotation of display doesn't change but we still want to 5233 // cover the activity whose configuration is changing by freezing the display and running 5234 // the rotation animation. 5235 final boolean forceRotation = overrideOriginalDisplayRotation != ROTATION_UNDEFINED; 5236 if (!mFreezingScreen) { 5237 mFreezingScreen = true; 5238 mWmService.registerAppFreezeListener(this); 5239 mWmService.mAppsFreezingScreen++; 5240 if (mWmService.mAppsFreezingScreen == 1) { 5241 if (forceRotation) { 5242 // Make sure normal rotation animation will be applied. 5243 mDisplayContent.getDisplayRotation().cancelSeamlessRotation(); 5244 } 5245 mWmService.startFreezingDisplay(0 /* exitAnim */, 0 /* enterAnim */, 5246 mDisplayContent, overrideOriginalDisplayRotation); 5247 mWmService.mH.removeMessages(H.APP_FREEZE_TIMEOUT); 5248 mWmService.mH.sendEmptyMessageDelayed(H.APP_FREEZE_TIMEOUT, 2000); 5249 } 5250 } 5251 if (forceRotation) { 5252 // The rotation of the real display won't change, so in order to unfreeze the screen 5253 // via {@link #checkAppWindowsReadyToShow}, the windows have to be able to call 5254 // {@link WindowState#reportResized} (it is skipped if the window is freezing) to update 5255 // the drawn state. 5256 return; 5257 } 5258 final int count = mChildren.size(); 5259 for (int i = 0; i < count; i++) { 5260 final WindowState w = mChildren.get(i); 5261 w.onStartFreezingScreen(); 5262 } 5263 } 5264 isFreezingScreen()5265 boolean isFreezingScreen() { 5266 return mFreezingScreen; 5267 } 5268 5269 @Override onAppFreezeTimeout()5270 public void onAppFreezeTimeout() { 5271 Slog.w(TAG_WM, "Force clearing freeze: " + this); 5272 stopFreezingScreen(true, true); 5273 } 5274 stopFreezingScreenLocked(boolean force)5275 void stopFreezingScreenLocked(boolean force) { 5276 if (force || frozenBeforeDestroy) { 5277 frozenBeforeDestroy = false; 5278 if (getParent() == null) { 5279 return; 5280 } 5281 ProtoLog.v(WM_DEBUG_ORIENTATION, 5282 "Clear freezing of %s: visible=%b freezing=%b", appToken, 5283 isVisible(), isFreezingScreen()); 5284 stopFreezingScreen(true, force); 5285 } 5286 } 5287 stopFreezingScreen(boolean unfreezeSurfaceNow, boolean force)5288 void stopFreezingScreen(boolean unfreezeSurfaceNow, boolean force) { 5289 if (!mFreezingScreen) { 5290 return; 5291 } 5292 ProtoLog.v(WM_DEBUG_ORIENTATION, 5293 "Clear freezing of %s force=%b", this, force); 5294 final int count = mChildren.size(); 5295 boolean unfrozeWindows = false; 5296 for (int i = 0; i < count; i++) { 5297 final WindowState w = mChildren.get(i); 5298 unfrozeWindows |= w.onStopFreezingScreen(); 5299 } 5300 if (force || unfrozeWindows) { 5301 ProtoLog.v(WM_DEBUG_ORIENTATION, "No longer freezing: %s", this); 5302 mFreezingScreen = false; 5303 mWmService.unregisterAppFreezeListener(this); 5304 mWmService.mAppsFreezingScreen--; 5305 mWmService.mLastFinishedFreezeSource = this; 5306 } 5307 if (unfreezeSurfaceNow) { 5308 if (unfrozeWindows) { 5309 mWmService.mWindowPlacerLocked.performSurfacePlacement(); 5310 } 5311 mWmService.stopFreezingDisplayLocked(); 5312 } 5313 } 5314 reportFullyDrawnLocked(boolean restoredFromBundle)5315 void reportFullyDrawnLocked(boolean restoredFromBundle) { 5316 final TransitionInfoSnapshot info = mStackSupervisor 5317 .getActivityMetricsLogger().logAppTransitionReportedDrawn(this, restoredFromBundle); 5318 if (info != null) { 5319 mStackSupervisor.reportActivityLaunchedLocked(false /* timeout */, this, 5320 info.windowsFullyDrawnDelayMs, info.getLaunchState()); 5321 } 5322 } 5323 onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator)5324 void onFirstWindowDrawn(WindowState win, WindowStateAnimator winAnimator) { 5325 firstWindowDrawn = true; 5326 5327 // We now have a good window to show, remove dead placeholders 5328 removeDeadWindows(); 5329 5330 if (startingWindow != null) { 5331 ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Finish starting %s" 5332 + ": first real window is shown, no animation", win.mToken); 5333 // If this initial window is animating, stop it -- we will do an animation to reveal 5334 // it from behind the starting window, so there is no need for it to also be doing its 5335 // own stuff. 5336 win.cancelAnimation(); 5337 } 5338 removeStartingWindow(); 5339 updateReportedVisibilityLocked(); 5340 } 5341 onStartingWindowDrawn()5342 void onStartingWindowDrawn() { 5343 if (task != null) { 5344 task.setHasBeenVisible(true); 5345 } 5346 } 5347 5348 /** Called when the windows associated app window container are drawn. */ onWindowsDrawn(boolean drawn, long timestampNs)5349 void onWindowsDrawn(boolean drawn, long timestampNs) { 5350 mDrawn = drawn; 5351 if (!drawn) { 5352 return; 5353 } 5354 final TransitionInfoSnapshot info = mStackSupervisor 5355 .getActivityMetricsLogger().notifyWindowsDrawn(this, timestampNs); 5356 final boolean validInfo = info != null; 5357 final int windowsDrawnDelayMs = validInfo ? info.windowsDrawnDelayMs : INVALID_DELAY; 5358 final @LaunchState int launchState = validInfo ? info.getLaunchState() : -1; 5359 // The activity may have been requested to be invisible (another activity has been launched) 5360 // so there is no valid info. But if it is the current top activity (e.g. sleeping), the 5361 // invalid state is still reported to make sure the waiting result is notified. 5362 if (validInfo || this == getDisplayArea().topRunningActivity()) { 5363 mStackSupervisor.reportActivityLaunchedLocked(false /* timeout */, this, 5364 windowsDrawnDelayMs, launchState); 5365 mStackSupervisor.stopWaitingForActivityVisible(this, windowsDrawnDelayMs); 5366 } 5367 finishLaunchTickingLocked(); 5368 if (task != null) { 5369 task.setHasBeenVisible(true); 5370 } 5371 } 5372 5373 /** Called when the windows associated app window container are visible. */ onWindowsVisible()5374 void onWindowsVisible() { 5375 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting visible in " + appToken); 5376 mStackSupervisor.stopWaitingForActivityVisible(this); 5377 if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsVisibleLocked(): " + this); 5378 if (!nowVisible) { 5379 nowVisible = true; 5380 lastVisibleTime = SystemClock.uptimeMillis(); 5381 mAtmService.scheduleAppGcsLocked(); 5382 } 5383 } 5384 5385 /** Called when the windows associated app window container are no longer visible. */ onWindowsGone()5386 void onWindowsGone() { 5387 if (DEBUG_VISIBILITY) Slog.v(TAG_WM, "Reporting gone in " + appToken); 5388 if (DEBUG_SWITCH) Log.v(TAG_SWITCH, "windowsGone(): " + this); 5389 nowVisible = false; 5390 } 5391 5392 @Override checkAppWindowsReadyToShow()5393 void checkAppWindowsReadyToShow() { 5394 if (allDrawn == mLastAllDrawn) { 5395 return; 5396 } 5397 5398 mLastAllDrawn = allDrawn; 5399 if (!allDrawn) { 5400 return; 5401 } 5402 5403 // The token has now changed state to having all windows shown... what to do, what to do? 5404 if (mFreezingScreen) { 5405 showAllWindowsLocked(); 5406 stopFreezingScreen(false, true); 5407 ProtoLog.i(WM_DEBUG_ORIENTATION, 5408 "Setting mOrientationChangeComplete=true because wtoken %s " 5409 + "numInteresting=%d numDrawn=%d", 5410 this, mNumInterestingWindows, mNumDrawnWindows); 5411 // This will set mOrientationChangeComplete and cause a pass through layout. 5412 setAppLayoutChanges(FINISH_LAYOUT_REDO_WALLPAPER, 5413 "checkAppWindowsReadyToShow: freezingScreen"); 5414 } else { 5415 setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM, "checkAppWindowsReadyToShow"); 5416 5417 // We can now show all of the drawn windows! 5418 if (!getDisplayContent().mOpeningApps.contains(this) && canShowWindows()) { 5419 showAllWindowsLocked(); 5420 } 5421 } 5422 } 5423 5424 /** 5425 * This must be called while inside a transaction. 5426 */ showAllWindowsLocked()5427 void showAllWindowsLocked() { 5428 forAllWindows(windowState -> { 5429 if (DEBUG_VISIBILITY) Slog.v(TAG, "performing show on: " + windowState); 5430 windowState.performShowLocked(); 5431 }, false /* traverseTopToBottom */); 5432 } 5433 updateReportedVisibilityLocked()5434 void updateReportedVisibilityLocked() { 5435 if (appToken == null) { 5436 return; 5437 } 5438 5439 if (DEBUG_VISIBILITY) Slog.v(TAG, "Update reported visibility: " + this); 5440 final int count = mChildren.size(); 5441 5442 mReportedVisibilityResults.reset(); 5443 5444 for (int i = 0; i < count; i++) { 5445 final WindowState win = mChildren.get(i); 5446 win.updateReportedVisibility(mReportedVisibilityResults); 5447 } 5448 5449 int numInteresting = mReportedVisibilityResults.numInteresting; 5450 int numVisible = mReportedVisibilityResults.numVisible; 5451 int numDrawn = mReportedVisibilityResults.numDrawn; 5452 boolean nowGone = mReportedVisibilityResults.nowGone; 5453 5454 boolean nowDrawn = numInteresting > 0 && numDrawn >= numInteresting; 5455 boolean nowVisible = numInteresting > 0 && numVisible >= numInteresting && isVisible(); 5456 if (!nowGone) { 5457 // If the app is not yet gone, then it can only become visible/drawn. 5458 if (!nowDrawn) { 5459 nowDrawn = reportedDrawn; 5460 } 5461 if (!nowVisible) { 5462 nowVisible = reportedVisible; 5463 } 5464 } 5465 if (DEBUG_VISIBILITY) Slog.v(TAG, "VIS " + this + ": interesting=" 5466 + numInteresting + " visible=" + numVisible); 5467 if (nowDrawn != reportedDrawn) { 5468 onWindowsDrawn(nowDrawn, SystemClock.elapsedRealtimeNanos()); 5469 reportedDrawn = nowDrawn; 5470 } 5471 if (nowVisible != reportedVisible) { 5472 if (DEBUG_VISIBILITY) Slog.v(TAG, 5473 "Visibility changed in " + this + ": vis=" + nowVisible); 5474 reportedVisible = nowVisible; 5475 if (nowVisible) { 5476 onWindowsVisible(); 5477 } else { 5478 onWindowsGone(); 5479 } 5480 } 5481 } 5482 isClientVisible()5483 boolean isClientVisible() { 5484 return mClientVisible; 5485 } 5486 setClientVisible(boolean clientVisible)5487 void setClientVisible(boolean clientVisible) { 5488 if (mClientVisible == clientVisible || (!clientVisible && mDeferHidingClient)) { 5489 return; 5490 } 5491 ProtoLog.v(WM_DEBUG_APP_TRANSITIONS, 5492 "setClientVisible: %s clientVisible=%b Callers=%s", this, clientVisible, 5493 Debug.getCallers(5)); 5494 mClientVisible = clientVisible; 5495 sendAppVisibilityToClients(); 5496 } 5497 5498 /** 5499 * Updated this app token tracking states for interesting and drawn windows based on the window. 5500 * 5501 * @return Returns true if the input window is considered interesting and drawn while all the 5502 * windows in this app token where not considered drawn as of the last pass. 5503 */ updateDrawnWindowStates(WindowState w)5504 boolean updateDrawnWindowStates(WindowState w) { 5505 w.setDrawnStateEvaluated(true /*evaluated*/); 5506 5507 if (DEBUG_STARTING_WINDOW_VERBOSE && w == startingWindow) { 5508 Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen=" + w.isOnScreen() 5509 + " allDrawn=" + allDrawn + " freezingScreen=" + mFreezingScreen); 5510 } 5511 5512 if (allDrawn && !mFreezingScreen) { 5513 return false; 5514 } 5515 5516 if (mLastTransactionSequence != mWmService.mTransactionSequence) { 5517 mLastTransactionSequence = mWmService.mTransactionSequence; 5518 mNumDrawnWindows = 0; 5519 startingDisplayed = false; 5520 5521 // There is the main base application window, even if it is exiting, wait for it 5522 mNumInterestingWindows = findMainWindow(false /* includeStartingApp */) != null ? 1 : 0; 5523 } 5524 5525 final WindowStateAnimator winAnimator = w.mWinAnimator; 5526 5527 boolean isInterestingAndDrawn = false; 5528 5529 if (!allDrawn && w.mightAffectAllDrawn()) { 5530 if (DEBUG_VISIBILITY || WM_DEBUG_ORIENTATION.isLogToLogcat()) { 5531 Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw() 5532 + ", isAnimationSet=" + isAnimating(TRANSITION | PARENTS)); 5533 if (!w.isDrawnLw()) { 5534 Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceController 5535 + " pv=" + w.isVisibleByPolicy() 5536 + " mDrawState=" + winAnimator.drawStateToString() 5537 + " ph=" + w.isParentWindowHidden() + " th=" + mVisibleRequested 5538 + " a=" + isAnimating(TRANSITION | PARENTS)); 5539 } 5540 } 5541 5542 if (w != startingWindow) { 5543 if (w.isInteresting()) { 5544 // Add non-main window as interesting since the main app has already been added 5545 if (findMainWindow(false /* includeStartingApp */) != w) { 5546 mNumInterestingWindows++; 5547 } 5548 if (w.isDrawnLw()) { 5549 mNumDrawnWindows++; 5550 5551 if (DEBUG_VISIBILITY || WM_DEBUG_ORIENTATION.isLogToLogcat()) { 5552 Slog.v(TAG, "tokenMayBeDrawn: " 5553 + this + " w=" + w + " numInteresting=" + mNumInterestingWindows 5554 + " freezingScreen=" + mFreezingScreen 5555 + " mAppFreezing=" + w.mAppFreezing); 5556 } 5557 5558 isInterestingAndDrawn = true; 5559 } 5560 } 5561 } else if (w.isDrawnLw()) { 5562 // The starting window for this container is drawn. 5563 mStackSupervisor.getActivityMetricsLogger().notifyStartingWindowDrawn(this); 5564 startingDisplayed = true; 5565 } 5566 } 5567 5568 return isInterestingAndDrawn; 5569 } 5570 5571 /** 5572 * Called when the key dispatching to a window associated with the app window container 5573 * timed-out. 5574 * 5575 * @param reason The reason for the key dispatching time out. 5576 * @param windowPid The pid of the window key dispatching timed out on. 5577 * @return True if input dispatching should be aborted. 5578 */ keyDispatchingTimedOut(String reason, int windowPid)5579 public boolean keyDispatchingTimedOut(String reason, int windowPid) { 5580 ActivityRecord anrActivity; 5581 WindowProcessController anrApp; 5582 boolean windowFromSameProcessAsActivity; 5583 synchronized (mAtmService.mGlobalLock) { 5584 anrActivity = getWaitingHistoryRecordLocked(); 5585 anrApp = app; 5586 windowFromSameProcessAsActivity = 5587 !hasProcess() || app.getPid() == windowPid || windowPid == INVALID_PID; 5588 } 5589 5590 if (windowFromSameProcessAsActivity) { 5591 return mAtmService.mAmInternal.inputDispatchingTimedOut(anrApp.mOwner, 5592 anrActivity.shortComponentName, anrActivity.info.applicationInfo, 5593 shortComponentName, app, false, reason); 5594 } else { 5595 // In this case another process added windows using this activity token. So, we call the 5596 // generic service input dispatch timed out method so that the right process is blamed. 5597 return mAtmService.mAmInternal.inputDispatchingTimedOut( 5598 windowPid, false /* aboveSystem */, reason) < 0; 5599 } 5600 } 5601 getWaitingHistoryRecordLocked()5602 private ActivityRecord getWaitingHistoryRecordLocked() { 5603 // First find the real culprit... if this activity has stopped, then the key dispatching 5604 // timeout should not be caused by this. 5605 if (stopped) { 5606 final ActivityStack stack = mRootWindowContainer.getTopDisplayFocusedStack(); 5607 if (stack == null) { 5608 return this; 5609 } 5610 // Try to use the one which is closest to top. 5611 ActivityRecord r = stack.getResumedActivity(); 5612 if (r == null) { 5613 r = stack.mPausingActivity; 5614 } 5615 if (r != null) { 5616 return r; 5617 } 5618 } 5619 return this; 5620 } 5621 5622 /** Checks whether the activity should be shown for current user. */ okToShowLocked()5623 public boolean okToShowLocked() { 5624 // We cannot show activities when the device is locked and the application is not 5625 // encryption aware. 5626 if (!StorageManager.isUserKeyUnlocked(mUserId) 5627 && !info.applicationInfo.isEncryptionAware()) { 5628 return false; 5629 } 5630 5631 return (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0 5632 || (mStackSupervisor.isCurrentProfileLocked(mUserId) 5633 && mAtmService.mAmInternal.isUserRunning(mUserId, 0 /* flags */)); 5634 } 5635 canBeTopRunning()5636 boolean canBeTopRunning() { 5637 return !finishing && okToShowLocked(); 5638 } 5639 5640 /** 5641 * This method will return true if the activity is either visible, is becoming visible, is 5642 * currently pausing, or is resumed. 5643 */ isInterestingToUserLocked()5644 public boolean isInterestingToUserLocked() { 5645 return mVisibleRequested || nowVisible || mState == PAUSING || mState == RESUMED; 5646 } 5647 setSleeping(boolean sleeping)5648 void setSleeping(boolean sleeping) { 5649 mSetToSleep = sleeping; 5650 } 5651 getTaskForActivityLocked(IBinder token, boolean onlyRoot)5652 static int getTaskForActivityLocked(IBinder token, boolean onlyRoot) { 5653 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 5654 if (r == null || r.getParent() == null) { 5655 return INVALID_TASK_ID; 5656 } 5657 final Task task = r.task; 5658 if (onlyRoot && r.compareTo(task.getRootActivity( 5659 false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/)) > 0) { 5660 return INVALID_TASK_ID; 5661 } 5662 return task.mTaskId; 5663 } 5664 isInStackLocked(IBinder token)5665 static ActivityRecord isInStackLocked(IBinder token) { 5666 final ActivityRecord r = ActivityRecord.forTokenLocked(token); 5667 return (r != null) ? r.getRootTask().isInTask(r) : null; 5668 } 5669 getStackLocked(IBinder token)5670 static ActivityStack getStackLocked(IBinder token) { 5671 final ActivityRecord r = ActivityRecord.isInStackLocked(token); 5672 if (r != null) { 5673 return r.getRootTask(); 5674 } 5675 return null; 5676 } 5677 5678 /** 5679 * @return display id to which this record is attached, 5680 * {@link android.view.Display#INVALID_DISPLAY} if not attached. 5681 */ getDisplayId()5682 int getDisplayId() { 5683 final ActivityStack stack = getRootTask(); 5684 if (stack == null) { 5685 return INVALID_DISPLAY; 5686 } 5687 return stack.getDisplayId(); 5688 } 5689 isDestroyable()5690 final boolean isDestroyable() { 5691 if (finishing || !hasProcess()) { 5692 // This would be redundant. 5693 return false; 5694 } 5695 final ActivityStack stack = getRootTask(); 5696 if (isState(RESUMED) || stack == null || this == stack.mPausingActivity || !mHaveState 5697 || !stopped) { 5698 // We're not ready for this kind of thing. 5699 return false; 5700 } 5701 if (mVisibleRequested) { 5702 // The user would notice this! 5703 return false; 5704 } 5705 return true; 5706 } 5707 createImageFilename(long createTime, int taskId)5708 private static String createImageFilename(long createTime, int taskId) { 5709 return String.valueOf(taskId) + ACTIVITY_ICON_SUFFIX + createTime + 5710 IMAGE_EXTENSION; 5711 } 5712 setTaskDescription(TaskDescription _taskDescription)5713 void setTaskDescription(TaskDescription _taskDescription) { 5714 Bitmap icon; 5715 if (_taskDescription.getIconFilename() == null && 5716 (icon = _taskDescription.getIcon()) != null) { 5717 final String iconFilename = createImageFilename(createTime, task.mTaskId); 5718 final File iconFile = new File(TaskPersister.getUserImagesDir(task.mUserId), 5719 iconFilename); 5720 final String iconFilePath = iconFile.getAbsolutePath(); 5721 mAtmService.getRecentTasks().saveImage(icon, iconFilePath); 5722 _taskDescription.setIconFilename(iconFilePath); 5723 } 5724 taskDescription = _taskDescription; 5725 getTask().updateTaskDescription(); 5726 } 5727 setVoiceSessionLocked(IVoiceInteractionSession session)5728 void setVoiceSessionLocked(IVoiceInteractionSession session) { 5729 voiceSession = session; 5730 pendingVoiceInteractionStart = false; 5731 } 5732 clearVoiceSessionLocked()5733 void clearVoiceSessionLocked() { 5734 voiceSession = null; 5735 pendingVoiceInteractionStart = false; 5736 } 5737 showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch)5738 void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch) { 5739 if (mTaskOverlay) { 5740 // We don't show starting window for overlay activities. 5741 return; 5742 } 5743 if (pendingOptions != null 5744 && pendingOptions.getAnimationType() == ActivityOptions.ANIM_SCENE_TRANSITION) { 5745 // Don't show starting window when using shared element transition. 5746 return; 5747 } 5748 5749 final CompatibilityInfo compatInfo = 5750 mAtmService.compatibilityInfoForPackageLocked(info.applicationInfo); 5751 final boolean shown = addStartingWindow(packageName, theme, 5752 compatInfo, nonLocalizedLabel, labelRes, icon, logo, windowFlags, 5753 prev != null ? prev.appToken : null, newTask, taskSwitch, isProcessRunning(), 5754 allowTaskSnapshot(), 5755 mState.ordinal() >= STARTED.ordinal() && mState.ordinal() <= STOPPED.ordinal()); 5756 if (shown) { 5757 mStartingWindowState = STARTING_WINDOW_SHOWN; 5758 } 5759 } 5760 5761 /** 5762 * If any activities below the top running one are in the INITIALIZING state and they have a 5763 * starting window displayed then remove that starting window. It is possible that the activity 5764 * in this state will never resumed in which case that starting window will be orphaned. 5765 * <p> 5766 * It should only be called if this activity is behind other fullscreen activity. 5767 */ cancelInitializing()5768 void cancelInitializing() { 5769 if (mStartingWindowState == STARTING_WINDOW_SHOWN) { 5770 // Remove orphaned starting window. 5771 if (DEBUG_VISIBILITY) Slog.w(TAG_VISIBILITY, "Found orphaned starting window " + this); 5772 mStartingWindowState = STARTING_WINDOW_REMOVED; 5773 removeStartingWindow(); 5774 } 5775 if (isState(INITIALIZING) && !shouldBeVisible( 5776 true /* behindFullscreenActivity */, true /* ignoringKeyguard */)) { 5777 // Remove the unknown visibility record because an invisible activity shouldn't block 5778 // the keyguard transition. 5779 mDisplayContent.mUnknownAppVisibilityController.appRemovedOrHidden(this); 5780 } 5781 } 5782 postWindowRemoveStartingWindowCleanup(WindowState win)5783 void postWindowRemoveStartingWindowCleanup(WindowState win) { 5784 // TODO: Something smells about the code below...Is there a better way? 5785 if (startingWindow == win) { 5786 ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Notify removed startingWindow %s", win); 5787 removeStartingWindow(); 5788 } else if (mChildren.size() == 0) { 5789 // If this is the last window and we had requested a starting transition window, 5790 // well there is no point now. 5791 ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Nulling last startingData"); 5792 mStartingData = null; 5793 if (mVisibleSetFromTransferredStartingWindow) { 5794 // We set the visible state to true for the token from a transferred starting 5795 // window. We now reset it back to false since the starting window was the last 5796 // window in the token. 5797 setVisible(false); 5798 } 5799 } else if (mChildren.size() == 1 && startingSurface != null && !isRelaunching()) { 5800 // If this is the last window except for a starting transition window, 5801 // we need to get rid of the starting transition. 5802 ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Last window, removing starting window %s", win); 5803 removeStartingWindow(); 5804 } 5805 } 5806 removeDeadWindows()5807 void removeDeadWindows() { 5808 for (int winNdx = mChildren.size() - 1; winNdx >= 0; --winNdx) { 5809 WindowState win = mChildren.get(winNdx); 5810 if (win.mAppDied) { 5811 ProtoLog.w(WM_DEBUG_ADD_REMOVE, 5812 "removeDeadWindows: %s", win); 5813 // Set mDestroying, we don't want any animation or delayed removal here. 5814 win.mDestroying = true; 5815 // Also removes child windows. 5816 win.removeIfPossible(); 5817 } 5818 } 5819 } 5820 hasWindowsAlive()5821 boolean hasWindowsAlive() { 5822 for (int i = mChildren.size() - 1; i >= 0; i--) { 5823 // No need to loop through child windows as the answer should be the same as that of the 5824 // parent window. 5825 if (!(mChildren.get(i)).mAppDied) { 5826 return true; 5827 } 5828 } 5829 return false; 5830 } 5831 setWillReplaceWindows(boolean animate)5832 void setWillReplaceWindows(boolean animate) { 5833 ProtoLog.d(WM_DEBUG_ADD_REMOVE, 5834 "Marking app token %s with replacing windows.", this); 5835 5836 for (int i = mChildren.size() - 1; i >= 0; i--) { 5837 final WindowState w = mChildren.get(i); 5838 w.setWillReplaceWindow(animate); 5839 } 5840 } 5841 setWillReplaceChildWindows()5842 void setWillReplaceChildWindows() { 5843 ProtoLog.d(WM_DEBUG_ADD_REMOVE, "Marking app token %s" 5844 + " with replacing child windows.", this); 5845 for (int i = mChildren.size() - 1; i >= 0; i--) { 5846 final WindowState w = mChildren.get(i); 5847 w.setWillReplaceChildWindows(); 5848 } 5849 } 5850 clearWillReplaceWindows()5851 void clearWillReplaceWindows() { 5852 ProtoLog.d(WM_DEBUG_ADD_REMOVE, 5853 "Resetting app token %s of replacing window marks.", this); 5854 5855 for (int i = mChildren.size() - 1; i >= 0; i--) { 5856 final WindowState w = mChildren.get(i); 5857 w.clearWillReplaceWindow(); 5858 } 5859 } 5860 requestUpdateWallpaperIfNeeded()5861 void requestUpdateWallpaperIfNeeded() { 5862 for (int i = mChildren.size() - 1; i >= 0; i--) { 5863 final WindowState w = mChildren.get(i); 5864 w.requestUpdateWallpaperIfNeeded(); 5865 } 5866 } 5867 5868 /** 5869 * @return The to top most child window for which {@link LayoutParams#isFullscreen()} returns 5870 * true and isn't fully transparent. 5871 */ getTopFullscreenOpaqueWindow()5872 WindowState getTopFullscreenOpaqueWindow() { 5873 for (int i = mChildren.size() - 1; i >= 0; i--) { 5874 final WindowState win = mChildren.get(i); 5875 if (win != null && win.mAttrs.isFullscreen() && !win.isFullyTransparent()) { 5876 return win; 5877 } 5878 } 5879 return null; 5880 } 5881 findMainWindow()5882 WindowState findMainWindow() { 5883 return findMainWindow(true); 5884 } 5885 5886 /** 5887 * Finds the main window that either has type base application or application starting if 5888 * requested. 5889 * 5890 * @param includeStartingApp Allow to search application-starting windows to also be returned. 5891 * @return The main window of type base application or application starting if requested. 5892 */ findMainWindow(boolean includeStartingApp)5893 WindowState findMainWindow(boolean includeStartingApp) { 5894 WindowState candidate = null; 5895 for (int j = mChildren.size() - 1; j >= 0; --j) { 5896 final WindowState win = mChildren.get(j); 5897 final int type = win.mAttrs.type; 5898 // No need to loop through child window as base application and starting types can't be 5899 // child windows. 5900 if (type == TYPE_BASE_APPLICATION 5901 || (includeStartingApp && type == TYPE_APPLICATION_STARTING)) { 5902 // In cases where there are multiple windows, we prefer the non-exiting window. This 5903 // happens for example when replacing windows during an activity relaunch. When 5904 // constructing the animation, we want the new window, not the exiting one. 5905 if (win.mAnimatingExit) { 5906 candidate = win; 5907 } else { 5908 return win; 5909 } 5910 } 5911 } 5912 return candidate; 5913 } 5914 getAppAnimationLayer()5915 SurfaceControl getAppAnimationLayer() { 5916 return getAppAnimationLayer(isActivityTypeHome() ? ANIMATION_LAYER_HOME 5917 : needsZBoost() ? ANIMATION_LAYER_BOOSTED 5918 : ANIMATION_LAYER_STANDARD); 5919 } 5920 5921 @Override needsZBoost()5922 boolean needsZBoost() { 5923 return mNeedsZBoost || super.needsZBoost(); 5924 } 5925 5926 @Override getAnimationLeashParent()5927 public SurfaceControl getAnimationLeashParent() { 5928 // For transitions in the pinned stack (menu activity) we just let them occur as a child 5929 // of the pinned stack. 5930 // All normal app transitions take place in an animation layer which is below the pinned 5931 // stack but may be above the parent stacks of the given animating apps by default. When 5932 // a new hierarchical animation is enabled, we just let them occur as a child of the parent 5933 // stack, i.e. the hierarchy of the surfaces is unchanged. 5934 if (inPinnedWindowingMode()) { 5935 return getStack().getSurfaceControl(); 5936 } else if (WindowManagerService.sHierarchicalAnimations) { 5937 return super.getAnimationLeashParent(); 5938 } else { 5939 return getAppAnimationLayer(); 5940 } 5941 } 5942 5943 @VisibleForTesting shouldAnimate()5944 boolean shouldAnimate() { 5945 return task == null || task.shouldAnimate(); 5946 } 5947 5948 /** 5949 * Creates a layer to apply crop to an animation. 5950 */ createAnimationBoundsLayer(Transaction t)5951 private SurfaceControl createAnimationBoundsLayer(Transaction t) { 5952 ProtoLog.i(WM_DEBUG_APP_TRANSITIONS_ANIM, "Creating animation bounds layer"); 5953 final SurfaceControl.Builder builder = makeAnimationLeash() 5954 .setParent(getAnimationLeashParent()) 5955 .setName(getSurfaceControl() + " - animation-bounds") 5956 .setCallsite("ActivityRecord.createAnimationBoundsLayer"); 5957 final SurfaceControl boundsLayer = builder.build(); 5958 t.show(boundsLayer); 5959 return boundsLayer; 5960 } 5961 5962 @Override shouldDeferAnimationFinish(Runnable endDeferFinishCallback)5963 public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) { 5964 return mAnimatingActivityRegistry != null 5965 && mAnimatingActivityRegistry.notifyAboutToFinish( 5966 this, endDeferFinishCallback); 5967 } 5968 5969 @Override isWaitingForTransitionStart()5970 boolean isWaitingForTransitionStart() { 5971 final DisplayContent dc = getDisplayContent(); 5972 return dc != null && dc.mAppTransition.isTransitionSet() 5973 && (dc.mOpeningApps.contains(this) 5974 || dc.mClosingApps.contains(this) 5975 || dc.mChangingContainers.contains(this)); 5976 } 5977 getAnimationLayer()5978 private int getAnimationLayer() { 5979 // The leash is parented to the animation layer. We need to preserve the z-order by using 5980 // the prefix order index, but we boost if necessary. 5981 int layer; 5982 if (!inPinnedWindowingMode()) { 5983 layer = getPrefixOrderIndex(); 5984 } else { 5985 // Pinned stacks have animations take place within themselves rather than an animation 5986 // layer so we need to preserve the order relative to the stack (e.g. the order of our 5987 // task/parent). 5988 layer = getParent().getPrefixOrderIndex(); 5989 } 5990 5991 if (mNeedsZBoost) { 5992 layer += Z_BOOST_BASE; 5993 } 5994 return layer; 5995 } 5996 5997 @Override onAnimationLeashCreated(Transaction t, SurfaceControl leash)5998 public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) { 5999 t.setLayer(leash, getAnimationLayer()); 6000 getDisplayContent().assignStackOrdering(); 6001 } 6002 6003 @Override onLeashAnimationStarting(Transaction t, SurfaceControl leash)6004 public void onLeashAnimationStarting(Transaction t, SurfaceControl leash) { 6005 if (mAnimatingActivityRegistry != null) { 6006 mAnimatingActivityRegistry.notifyStarting(this); 6007 } 6008 6009 // If the animation needs to be cropped then an animation bounds layer is created as a child 6010 // of the pinned stack or animation layer. The leash is then reparented to this new layer. 6011 if (mNeedsAnimationBoundsLayer) { 6012 mTmpRect.setEmpty(); 6013 if (getDisplayContent().mAppTransitionController.isTransitWithinTask( 6014 getTransit(), task)) { 6015 task.getBounds(mTmpRect); 6016 } else { 6017 final ActivityStack stack = getStack(); 6018 if (stack == null) { 6019 return; 6020 } 6021 // Set clip rect to stack bounds. 6022 stack.getBounds(mTmpRect); 6023 } 6024 mAnimationBoundsLayer = createAnimationBoundsLayer(t); 6025 6026 // Crop to stack bounds. 6027 if (!WindowManagerService.sHierarchicalAnimations) { 6028 // For Hierarchical animation, we don't need to set window crop since the leash 6029 // surface size has already same as the animating container. 6030 t.setWindowCrop(mAnimationBoundsLayer, mTmpRect); 6031 } 6032 t.setLayer(leash, 0); 6033 t.setLayer(mAnimationBoundsLayer, getAnimationLayer()); 6034 6035 // Reparent leash to animation bounds layer. 6036 t.reparent(leash, mAnimationBoundsLayer); 6037 } 6038 } 6039 6040 @Override prepareSurfaces()6041 void prepareSurfaces() { 6042 final boolean show = isVisible() || isAnimatingExcluding(PARENTS, 6043 ANIMATION_TYPE_SCREEN_ROTATION); 6044 6045 if (mSurfaceControl != null) { 6046 if (show && !mLastSurfaceShowing) { 6047 getSyncTransaction().show(mSurfaceControl); 6048 } else if (!show && mLastSurfaceShowing) { 6049 getSyncTransaction().hide(mSurfaceControl); 6050 } 6051 } 6052 if (mThumbnail != null) { 6053 mThumbnail.setShowing(getPendingTransaction(), show); 6054 } 6055 mLastSurfaceShowing = show; 6056 super.prepareSurfaces(); 6057 } 6058 6059 /** 6060 * @return Whether our {@link #getSurfaceControl} is currently showing. 6061 */ isSurfaceShowing()6062 boolean isSurfaceShowing() { 6063 return mLastSurfaceShowing; 6064 } 6065 attachThumbnailAnimation()6066 void attachThumbnailAnimation() { 6067 if (!isAnimating(PARENTS)) { 6068 return; 6069 } 6070 final GraphicBuffer thumbnailHeader = 6071 getDisplayContent().mAppTransition.getAppTransitionThumbnailHeader(task); 6072 if (thumbnailHeader == null) { 6073 ProtoLog.d(WM_DEBUG_APP_TRANSITIONS, "No thumbnail header bitmap for: %s", task); 6074 return; 6075 } 6076 clearThumbnail(); 6077 final Transaction transaction = getAnimatingContainer().getPendingTransaction(); 6078 mThumbnail = new WindowContainerThumbnail(mWmService.mSurfaceFactory, 6079 transaction, getAnimatingContainer(), thumbnailHeader); 6080 mThumbnail.startAnimation(transaction, loadThumbnailAnimation(thumbnailHeader)); 6081 } 6082 6083 /** 6084 * Attaches a surface with a thumbnail for the 6085 * {@link android.app.ActivityOptions#ANIM_OPEN_CROSS_PROFILE_APPS} animation. 6086 */ attachCrossProfileAppsThumbnailAnimation()6087 void attachCrossProfileAppsThumbnailAnimation() { 6088 if (!isAnimating(PARENTS)) { 6089 return; 6090 } 6091 clearThumbnail(); 6092 6093 final WindowState win = findMainWindow(); 6094 if (win == null) { 6095 return; 6096 } 6097 final Rect frame = win.getRelativeFrameLw(); 6098 final int thumbnailDrawableRes = task.mUserId == mWmService.mCurrentUserId 6099 ? R.drawable.ic_account_circle 6100 : R.drawable.ic_corp_badge; 6101 final GraphicBuffer thumbnail = 6102 getDisplayContent().mAppTransition 6103 .createCrossProfileAppsThumbnail(thumbnailDrawableRes, frame); 6104 if (thumbnail == null) { 6105 return; 6106 } 6107 final Transaction transaction = getPendingTransaction(); 6108 mThumbnail = new WindowContainerThumbnail(mWmService.mSurfaceFactory, 6109 transaction, getTask(), thumbnail); 6110 final Animation animation = 6111 getDisplayContent().mAppTransition.createCrossProfileAppsThumbnailAnimationLocked( 6112 frame); 6113 mThumbnail.startAnimation(transaction, animation, new Point(frame.left, frame.top)); 6114 } 6115 loadThumbnailAnimation(GraphicBuffer thumbnailHeader)6116 private Animation loadThumbnailAnimation(GraphicBuffer thumbnailHeader) { 6117 final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo(); 6118 6119 // If this is a multi-window scenario, we use the windows frame as 6120 // destination of the thumbnail header animation. If this is a full screen 6121 // window scenario, we use the whole display as the target. 6122 WindowState win = findMainWindow(); 6123 Rect appRect = win != null ? win.getContentFrameLw() : 6124 new Rect(0, 0, displayInfo.appWidth, displayInfo.appHeight); 6125 final Rect insets = win != null ? win.getContentInsets() : null; 6126 final Configuration displayConfig = mDisplayContent.getConfiguration(); 6127 return getDisplayContent().mAppTransition.createThumbnailAspectScaleAnimationLocked( 6128 appRect, insets, thumbnailHeader, task, displayConfig.uiMode, 6129 displayConfig.orientation); 6130 } 6131 6132 @Override onAnimationLeashLost(Transaction t)6133 public void onAnimationLeashLost(Transaction t) { 6134 super.onAnimationLeashLost(t); 6135 if (mAnimationBoundsLayer != null) { 6136 t.remove(mAnimationBoundsLayer); 6137 mAnimationBoundsLayer = null; 6138 } 6139 6140 if (mAnimatingActivityRegistry != null) { 6141 mAnimatingActivityRegistry.notifyFinished(this); 6142 } 6143 } 6144 6145 @Override onAnimationFinished(@nimationType int type, AnimationAdapter anim)6146 protected void onAnimationFinished(@AnimationType int type, AnimationAdapter anim) { 6147 super.onAnimationFinished(type, anim); 6148 6149 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AR#onAnimationFinished"); 6150 mTransit = TRANSIT_UNSET; 6151 mTransitFlags = 0; 6152 mNeedsAnimationBoundsLayer = false; 6153 6154 setAppLayoutChanges(FINISH_LAYOUT_REDO_ANIM | FINISH_LAYOUT_REDO_WALLPAPER, 6155 "ActivityRecord"); 6156 6157 clearThumbnail(); 6158 setClientVisible(isVisible() || mVisibleRequested); 6159 6160 getDisplayContent().computeImeTargetIfNeeded(this); 6161 6162 if (DEBUG_ANIM) Slog.v(TAG, "Animation done in " + this 6163 + ": reportedVisible=" + reportedVisible 6164 + " okToDisplay=" + okToDisplay() 6165 + " okToAnimate=" + okToAnimate() 6166 + " startingDisplayed=" + startingDisplayed); 6167 6168 // clean up thumbnail window 6169 if (mThumbnail != null) { 6170 mThumbnail.destroy(); 6171 mThumbnail = null; 6172 } 6173 6174 // WindowState.onExitAnimationDone might modify the children list, so make a copy and then 6175 // traverse the copy. 6176 final ArrayList<WindowState> children = new ArrayList<>(mChildren); 6177 children.forEach(WindowState::onExitAnimationDone); 6178 6179 getDisplayContent().mAppTransition.notifyAppTransitionFinishedLocked(token); 6180 scheduleAnimation(); 6181 6182 if (!mStackSupervisor.mStoppingActivities.isEmpty() 6183 || !mStackSupervisor.mFinishingActivities.isEmpty()) { 6184 if (mRootWindowContainer.allResumedActivitiesIdle()) { 6185 // If all activities are already idle then we now need to make sure we perform 6186 // the full stop of this activity. This is because we won't do that while they 6187 // are still waiting for the animation to finish. 6188 mStackSupervisor.scheduleIdle(); 6189 } else if (mRootWindowContainer.allResumedActivitiesVisible()) { 6190 // If all resumed activities are already visible (and should be drawn, see 6191 // updateReportedVisibility ~ nowVisible) but not idle, we still schedule to 6192 // process the stopping and finishing activities because the transition is done. 6193 // This also avoids if the next activity never reports idle (e.g. animating view), 6194 // the previous will need to wait until idle timeout to be stopped or destroyed. 6195 mStackSupervisor.scheduleProcessStoppingAndFinishingActivities(); 6196 } 6197 } 6198 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); 6199 } 6200 clearAnimatingFlags()6201 void clearAnimatingFlags() { 6202 boolean wallpaperMightChange = false; 6203 for (int i = mChildren.size() - 1; i >= 0; i--) { 6204 final WindowState win = mChildren.get(i); 6205 wallpaperMightChange |= win.clearAnimatingFlags(); 6206 } 6207 if (wallpaperMightChange) { 6208 requestUpdateWallpaperIfNeeded(); 6209 } 6210 } 6211 6212 @Override cancelAnimation()6213 void cancelAnimation() { 6214 super.cancelAnimation(); 6215 clearThumbnail(); 6216 } 6217 6218 @VisibleForTesting getThumbnail()6219 WindowContainerThumbnail getThumbnail() { 6220 return mThumbnail; 6221 } 6222 clearThumbnail()6223 private void clearThumbnail() { 6224 if (mThumbnail == null) { 6225 return; 6226 } 6227 mThumbnail.destroy(); 6228 mThumbnail = null; 6229 } 6230 getTransit()6231 public int getTransit() { 6232 return mTransit; 6233 } 6234 getTransitFlags()6235 int getTransitFlags() { 6236 return mTransitFlags; 6237 } 6238 registerRemoteAnimations(RemoteAnimationDefinition definition)6239 void registerRemoteAnimations(RemoteAnimationDefinition definition) { 6240 mRemoteAnimationDefinition = definition; 6241 if (definition != null) { 6242 definition.linkToDeath(this::unregisterRemoteAnimations); 6243 } 6244 } 6245 unregisterRemoteAnimations()6246 void unregisterRemoteAnimations() { 6247 mRemoteAnimationDefinition = null; 6248 } 6249 6250 @Override getRemoteAnimationDefinition()6251 RemoteAnimationDefinition getRemoteAnimationDefinition() { 6252 return mRemoteAnimationDefinition; 6253 } 6254 6255 @Override applyFixedRotationTransform(DisplayInfo info, DisplayFrames displayFrames, Configuration config)6256 void applyFixedRotationTransform(DisplayInfo info, DisplayFrames displayFrames, 6257 Configuration config) { 6258 super.applyFixedRotationTransform(info, displayFrames, config); 6259 ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */); 6260 } 6261 6262 @Override onCancelFixedRotationTransform(int originalDisplayRotation)6263 void onCancelFixedRotationTransform(int originalDisplayRotation) { 6264 if (this != mDisplayContent.getLastOrientationSource() 6265 || getRequestedConfigurationOrientation() != ORIENTATION_UNDEFINED) { 6266 // Only need to handle the activity that should be rotated with display. 6267 return; 6268 } 6269 6270 // Perform rotation animation according to the rotation of this activity. 6271 startFreezingScreen(originalDisplayRotation); 6272 // This activity may relaunch or perform configuration change so once it has reported drawn, 6273 // the screen can be unfrozen. 6274 ensureActivityConfiguration(0 /* globalChanges */, !PRESERVE_WINDOWS); 6275 } 6276 setRequestedOrientation(int requestedOrientation)6277 void setRequestedOrientation(int requestedOrientation) { 6278 setOrientation(requestedOrientation, mayFreezeScreenLocked()); 6279 mAtmService.getTaskChangeNotificationController().notifyActivityRequestedOrientationChanged( 6280 task.mTaskId, requestedOrientation); 6281 } 6282 setOrientation(int requestedOrientation, boolean freezeScreenIfNeeded)6283 private void setOrientation(int requestedOrientation, boolean freezeScreenIfNeeded) { 6284 final IBinder binder = 6285 (freezeScreenIfNeeded && appToken != null) ? appToken.asBinder() : null; 6286 setOrientation(requestedOrientation, binder, this); 6287 6288 // Push the new configuration to the requested app in case where it's not pushed, e.g. when 6289 // the request is handled at task level with letterbox. 6290 if (!getMergedOverrideConfiguration().equals( 6291 mLastReportedConfiguration.getMergedConfiguration())) { 6292 ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */); 6293 } 6294 } 6295 reportDescendantOrientationChangeIfNeeded()6296 void reportDescendantOrientationChangeIfNeeded() { 6297 // Orientation request is exposed only when we're visible. Therefore visibility change 6298 // will change requested orientation. Notify upward the hierarchy ladder to adjust 6299 // configuration. This is important to cases where activities with incompatible 6300 // orientations launch, or user goes back from an activity of bi-orientation to an 6301 // activity with specified orientation. 6302 if (getRequestedOrientation() == SCREEN_ORIENTATION_UNSET) { 6303 return; 6304 } 6305 6306 final IBinder freezeToken = mayFreezeScreenLocked() ? appToken : null; 6307 onDescendantOrientationChanged(freezeToken, this); 6308 } 6309 6310 /** 6311 * We override because this class doesn't want its children affecting its reported orientation 6312 * in anyway. 6313 */ 6314 @Override getOrientation(int candidate)6315 int getOrientation(int candidate) { 6316 if (candidate == SCREEN_ORIENTATION_BEHIND) { 6317 // Allow app to specify orientation regardless of its visibility state if the current 6318 // candidate want us to use orientation behind. I.e. the visible app on-top of this one 6319 // wants us to use the orientation of the app behind it. 6320 return mOrientation; 6321 } 6322 6323 // The {@link ActivityRecord} should only specify an orientation when it is not closing. 6324 // Allowing closing {@link ActivityRecord} to participate can lead to an Activity in another 6325 // task being started in the wrong orientation during the transition. 6326 if (!getDisplayContent().mClosingApps.contains(this) 6327 && (isVisible() || getDisplayContent().mOpeningApps.contains(this))) { 6328 return mOrientation; 6329 } 6330 6331 return SCREEN_ORIENTATION_UNSET; 6332 } 6333 6334 /** Returns the app's preferred orientation regardless of its currently visibility state. */ getRequestedOrientation()6335 int getRequestedOrientation() { 6336 return mOrientation; 6337 } 6338 6339 /** 6340 * Set the last reported global configuration to the client. Should be called whenever a new 6341 * global configuration is sent to the client for this activity. 6342 */ setLastReportedGlobalConfiguration(@onNull Configuration config)6343 void setLastReportedGlobalConfiguration(@NonNull Configuration config) { 6344 mLastReportedConfiguration.setGlobalConfiguration(config); 6345 } 6346 6347 /** 6348 * Set the last reported configuration to the client. Should be called whenever 6349 * a new merged configuration is sent to the client for this activity. 6350 */ setLastReportedConfiguration(@onNull MergedConfiguration config)6351 void setLastReportedConfiguration(@NonNull MergedConfiguration config) { 6352 setLastReportedConfiguration(config.getGlobalConfiguration(), 6353 config.getOverrideConfiguration()); 6354 } 6355 setLastReportedConfiguration(Configuration global, Configuration override)6356 private void setLastReportedConfiguration(Configuration global, Configuration override) { 6357 mLastReportedConfiguration.setConfiguration(global, override); 6358 } 6359 6360 /** 6361 * @return {@code true} if this activity is in size compatibility mode that uses the different 6362 * density than its parent or its bounds don't fit in parent naturally. 6363 */ inSizeCompatMode()6364 boolean inSizeCompatMode() { 6365 if (mCompatDisplayInsets == null || !shouldUseSizeCompatMode() 6366 // The orientation is different from parent when transforming. 6367 || isFixedRotationTransforming()) { 6368 return false; 6369 } 6370 final Rect appBounds = getConfiguration().windowConfiguration.getAppBounds(); 6371 if (appBounds == null) { 6372 // The app bounds hasn't been computed yet. 6373 return false; 6374 } 6375 6376 final Configuration parentConfig = getParent().getConfiguration(); 6377 // Although colorMode, screenLayout, smallestScreenWidthDp are also fixed, generally these 6378 // fields should be changed with density and bounds, so here only compares the most 6379 // significant field. 6380 if (parentConfig.densityDpi != getConfiguration().densityDpi) { 6381 return true; 6382 } 6383 6384 final Rect parentAppBounds = parentConfig.windowConfiguration.getAppBounds(); 6385 final int appWidth = appBounds.width(); 6386 final int appHeight = appBounds.height(); 6387 final int parentAppWidth = parentAppBounds.width(); 6388 final int parentAppHeight = parentAppBounds.height(); 6389 if (parentAppWidth == appWidth && parentAppHeight == appHeight) { 6390 // Matched the parent bounds. 6391 return false; 6392 } 6393 if (parentAppWidth > appWidth && parentAppHeight > appHeight) { 6394 // Both sides are smaller than the parent. 6395 return true; 6396 } 6397 if (parentAppWidth < appWidth || parentAppHeight < appHeight) { 6398 // One side is larger than the parent. 6399 return true; 6400 } 6401 6402 // The rest of the condition is that only one side is smaller than the parent, but it still 6403 // needs to exclude the cases where the size is limited by the fixed aspect ratio. 6404 if (info.maxAspectRatio > 0) { 6405 final float aspectRatio = (0.5f + Math.max(appWidth, appHeight)) 6406 / Math.min(appWidth, appHeight); 6407 if (aspectRatio >= info.maxAspectRatio) { 6408 // The current size has reached the max aspect ratio. 6409 return false; 6410 } 6411 } 6412 if (info.minAspectRatio > 0) { 6413 // The activity should have at least the min aspect ratio, so this checks if the parent 6414 // still has available space to provide larger aspect ratio. 6415 final float parentAspectRatio = (0.5f + Math.max(parentAppWidth, parentAppHeight)) 6416 / Math.min(parentAppWidth, parentAppHeight); 6417 if (parentAspectRatio <= info.minAspectRatio) { 6418 // The long side has reached the parent. 6419 return false; 6420 } 6421 } 6422 return true; 6423 } 6424 6425 /** 6426 * Indicates the activity will keep the bounds and screen configuration when it was first 6427 * launched, no matter how its parent changes. 6428 * 6429 * @return {@code true} if this activity is declared as non-resizable and fixed orientation or 6430 * aspect ratio. 6431 */ shouldUseSizeCompatMode()6432 boolean shouldUseSizeCompatMode() { 6433 if (info.supportsSizeChanges) { 6434 return false; 6435 } 6436 if (inMultiWindowMode() || getWindowConfiguration().hasWindowDecorCaption()) { 6437 final ActivityRecord root = task != null ? task.getRootActivity() : null; 6438 if (root != null && root != this && !root.shouldUseSizeCompatMode()) { 6439 // If the root activity doesn't use size compatibility mode, the activities above 6440 // are forced to be the same for consistent visual appearance. 6441 return false; 6442 } 6443 } 6444 return !isResizeable() && (info.isFixedOrientation() || info.hasFixedAspectRatio()) 6445 // The configuration of non-standard type should be enforced by system. 6446 && isActivityTypeStandard() 6447 && !mAtmService.mForceResizableActivities; 6448 } 6449 hasSizeCompatBounds()6450 boolean hasSizeCompatBounds() { 6451 return mSizeCompatBounds != null; 6452 } 6453 6454 // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer. updateSizeCompatMode()6455 private void updateSizeCompatMode() { 6456 if (mCompatDisplayInsets != null || !shouldUseSizeCompatMode()) { 6457 // The override configuration is set only once in size compatibility mode. 6458 return; 6459 } 6460 final Configuration parentConfig = getParent().getConfiguration(); 6461 if (!hasProcess() && !isConfigurationCompatible(parentConfig)) { 6462 // Don't compute when launching in fullscreen and the fixed orientation is not the 6463 // current orientation. It is more accurately to compute the override bounds from 6464 // the updated configuration after the fixed orientation is applied. 6465 return; 6466 } 6467 6468 Configuration overrideConfig = getRequestedOverrideConfiguration(); 6469 final Configuration fullConfig = getConfiguration(); 6470 6471 // Ensure the screen related fields are set. It is used to prevent activity relaunch 6472 // when moving between displays. For screenWidthDp and screenWidthDp, because they 6473 // are relative to bounds and density, they will be calculated in 6474 // {@link Task#computeConfigResourceOverrides} and the result will also be 6475 // relatively fixed. 6476 overrideConfig.colorMode = fullConfig.colorMode; 6477 overrideConfig.densityDpi = fullConfig.densityDpi; 6478 // The smallest screen width is the short side of screen bounds. Because the bounds 6479 // and density won't be changed, smallestScreenWidthDp is also fixed. 6480 overrideConfig.smallestScreenWidthDp = fullConfig.smallestScreenWidthDp; 6481 if (info.isFixedOrientation()) { 6482 // lock rotation too. When in size-compat, onConfigurationChanged will watch for and 6483 // apply runtime rotation changes. 6484 overrideConfig.windowConfiguration.setRotation( 6485 fullConfig.windowConfiguration.getRotation()); 6486 } 6487 6488 // The role of CompatDisplayInsets is like the override bounds. 6489 mCompatDisplayInsets = new CompatDisplayInsets(mDisplayContent, this); 6490 } 6491 6492 @VisibleForTesting clearSizeCompatMode()6493 void clearSizeCompatMode() { 6494 mSizeCompatScale = 1f; 6495 mSizeCompatBounds = null; 6496 mCompatDisplayInsets = null; 6497 onRequestedOverrideConfigurationChanged(EMPTY); 6498 } 6499 6500 @Override matchParentBounds()6501 public boolean matchParentBounds() { 6502 final Rect overrideBounds = getResolvedOverrideBounds(); 6503 if (overrideBounds.isEmpty()) { 6504 return true; 6505 } 6506 // An activity in size compatibility mode may have override bounds which equals to its 6507 // parent bounds, so the exact bounds should also be checked to allow IME window to attach 6508 // to the activity. See {@link DisplayContent#isImeAttachedToApp}. 6509 final WindowContainer parent = getParent(); 6510 return parent == null || parent.getBounds().equals(overrideBounds); 6511 } 6512 6513 @Override getSizeCompatScale()6514 float getSizeCompatScale() { 6515 return hasSizeCompatBounds() ? mSizeCompatScale : super.getSizeCompatScale(); 6516 } 6517 6518 @Override resolveOverrideConfiguration(Configuration newParentConfiguration)6519 void resolveOverrideConfiguration(Configuration newParentConfiguration) { 6520 super.resolveOverrideConfiguration(newParentConfiguration); 6521 final Configuration resolvedConfig = getResolvedOverrideConfiguration(); 6522 if (isFixedRotationTransforming()) { 6523 // The resolved configuration is applied with rotated display configuration. If this 6524 // activity matches its parent (the following resolving procedures are no-op), then it 6525 // can use the resolved configuration directly. Otherwise (e.g. fixed aspect ratio), 6526 // the rotated configuration is used as parent configuration to compute the actual 6527 // resolved configuration. It is like putting the activity in a rotated container. 6528 mTmpConfig.setTo(newParentConfiguration); 6529 mTmpConfig.updateFrom(resolvedConfig); 6530 newParentConfiguration = mTmpConfig; 6531 } 6532 if (mCompatDisplayInsets != null) { 6533 resolveSizeCompatModeConfiguration(newParentConfiguration); 6534 } else { 6535 if (inMultiWindowMode()) { 6536 // We ignore activities' requested orientation in multi-window modes. Task level may 6537 // take them into consideration when calculating bounds. 6538 resolvedConfig.orientation = Configuration.ORIENTATION_UNDEFINED; 6539 // If the activity has requested override bounds, the configuration needs to be 6540 // computed accordingly. 6541 if (!matchParentBounds()) { 6542 task.computeConfigResourceOverrides(resolvedConfig, newParentConfiguration); 6543 } 6544 } else { 6545 resolveFullscreenConfiguration(newParentConfiguration); 6546 } 6547 } 6548 6549 // Assign configuration sequence number into hierarchy because there is a different way than 6550 // ensureActivityConfiguration() in this class that uses configuration in WindowState during 6551 // layout traversals. 6552 mConfigurationSeq = Math.max(++mConfigurationSeq, 1); 6553 getResolvedOverrideConfiguration().seq = mConfigurationSeq; 6554 } 6555 6556 /** 6557 * Resolves the configuration of activity in fullscreen mode. If the bounds are restricted by 6558 * aspect ratio, the position will be centered horizontally in parent's app bounds to balance 6559 * the visual appearance. The policy of aspect ratio has higher priority than the requested 6560 * override bounds. 6561 */ resolveFullscreenConfiguration(Configuration newParentConfiguration)6562 private void resolveFullscreenConfiguration(Configuration newParentConfiguration) { 6563 final Configuration resolvedConfig = getResolvedOverrideConfiguration(); 6564 final Rect parentAppBounds = newParentConfiguration.windowConfiguration.getAppBounds(); 6565 final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds(); 6566 final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds(); 6567 // Use tmp bounds to calculate aspect ratio so we can know whether the activity should use 6568 // restricted size (resolved bounds may be the requested override bounds). 6569 mTmpBounds.setEmpty(); 6570 applyAspectRatio(mTmpBounds, parentAppBounds, parentBounds); 6571 // If the out bounds is not empty, it means the activity cannot fill parent's app bounds, 6572 // then there is space to be centered. 6573 final boolean needToBeCentered = !mTmpBounds.isEmpty(); 6574 if (needToBeCentered) { 6575 resolvedBounds.set(mTmpBounds); 6576 // Exclude the horizontal decor area. 6577 resolvedBounds.left = parentAppBounds.left; 6578 } 6579 if (!resolvedBounds.isEmpty() && !resolvedBounds.equals(parentBounds)) { 6580 // Compute the configuration based on the resolved bounds. If aspect ratio doesn't 6581 // restrict, the bounds should be the requested override bounds. 6582 task.computeConfigResourceOverrides(resolvedConfig, newParentConfiguration, 6583 getFixedRotationTransformDisplayInfo()); 6584 } 6585 if (needToBeCentered) { 6586 // Offset to center relative to parent's app bounds. 6587 final int offsetX = getHorizontalCenterOffset( 6588 parentAppBounds.width(), resolvedBounds.width()); 6589 offsetBounds(resolvedConfig, offsetX, 0 /* offsetY */); 6590 } 6591 } 6592 6593 /** 6594 * Resolves consistent screen configuration for orientation and rotation changes without 6595 * inheriting the parent bounds. 6596 */ resolveSizeCompatModeConfiguration(Configuration newParentConfiguration)6597 private void resolveSizeCompatModeConfiguration(Configuration newParentConfiguration) { 6598 final Configuration resolvedConfig = getResolvedOverrideConfiguration(); 6599 final Rect resolvedBounds = resolvedConfig.windowConfiguration.getBounds(); 6600 final int requestedOrientation = getRequestedConfigurationOrientation(); 6601 final boolean orientationRequested = requestedOrientation != ORIENTATION_UNDEFINED 6602 && !mDisplayContent.ignoreRotationForApps(); 6603 final int orientation = orientationRequested 6604 ? requestedOrientation 6605 : newParentConfiguration.orientation; 6606 int rotation = newParentConfiguration.windowConfiguration.getRotation(); 6607 final boolean canChangeOrientation = handlesOrientationChangeFromDescendant(); 6608 if (canChangeOrientation && !mCompatDisplayInsets.mIsFloating) { 6609 // Use parent rotation because the original display can rotate by requested orientation. 6610 resolvedConfig.windowConfiguration.setRotation(rotation); 6611 } else { 6612 final int overrideRotation = resolvedConfig.windowConfiguration.getRotation(); 6613 if (overrideRotation != ROTATION_UNDEFINED) { 6614 rotation = overrideRotation; 6615 } 6616 } 6617 6618 // Use compat insets to lock width and height. We should not use the parent width and height 6619 // because apps in compat mode should have a constant width and height. The compat insets 6620 // are locked when the app is first launched and are never changed after that, so we can 6621 // rely on them to contain the original and unchanging width and height of the app. 6622 final Rect containingAppBounds = new Rect(); 6623 final Rect containingBounds = mTmpBounds; 6624 mCompatDisplayInsets.getContainerBounds(containingAppBounds, containingBounds, rotation, 6625 orientation, orientationRequested, canChangeOrientation); 6626 resolvedBounds.set(containingBounds); 6627 // The size of floating task is fixed (only swap), so the aspect ratio is already correct. 6628 if (!mCompatDisplayInsets.mIsFloating) { 6629 applyAspectRatio(resolvedBounds, containingAppBounds, containingBounds); 6630 } 6631 // If the bounds are restricted by fixed aspect ratio, the resolved bounds should be put in 6632 // the container app bounds. Otherwise the entire container bounds are available. 6633 final boolean fillContainer = resolvedBounds.equals(containingBounds); 6634 if (!fillContainer) { 6635 // The horizontal position should not cover insets. 6636 resolvedBounds.left = containingAppBounds.left; 6637 } 6638 6639 // Use resolvedBounds to compute other override configurations such as appBounds. The bounds 6640 // are calculated in compat container space. The actual position on screen will be applied 6641 // later, so the calculation is simpler that doesn't need to involve offset from parent. 6642 task.computeConfigResourceOverrides(resolvedConfig, newParentConfiguration, 6643 mCompatDisplayInsets); 6644 // Use current screen layout as source because the size of app is independent to parent. 6645 resolvedConfig.screenLayout = Task.computeScreenLayoutOverride( 6646 getConfiguration().screenLayout, resolvedConfig.screenWidthDp, 6647 resolvedConfig.screenHeightDp); 6648 6649 // Use parent orientation if it cannot be decided by bounds, so the activity can fit inside 6650 // the parent bounds appropriately. 6651 if (resolvedConfig.screenWidthDp == resolvedConfig.screenHeightDp) { 6652 resolvedConfig.orientation = newParentConfiguration.orientation; 6653 } 6654 6655 // Below figure is an example that puts an activity which was launched in a larger container 6656 // into a smaller container. 6657 // The outermost rectangle is the real display bounds. 6658 // "@" is the parent app bounds. 6659 // "#" is the {@code resolvedBounds} that applies to application. 6660 // "*" is the {@code mSizeCompatBounds} that used to show on screen if scaled. 6661 // ------------------------------ 6662 // | | 6663 // | @@@@*********@@@@### | 6664 // | @ * * @ # | 6665 // | @ * * @ # | 6666 // | @ * * @ # | 6667 // | @@@@*********@@@@ # | 6668 // ---------#--------------#----- 6669 // # # 6670 // ################ 6671 // The application is still layouted in "#" since it was launched, and it will be visually 6672 // scaled and positioned to "*". 6673 6674 // Calculates the scale and offset to horizontal center the size compatibility bounds into 6675 // the region which is available to application. 6676 final Rect parentBounds = newParentConfiguration.windowConfiguration.getBounds(); 6677 final Rect parentAppBounds = newParentConfiguration.windowConfiguration.getAppBounds(); 6678 final Rect resolvedAppBounds = resolvedConfig.windowConfiguration.getAppBounds(); 6679 final int contentW = resolvedAppBounds.width(); 6680 final int contentH = resolvedAppBounds.height(); 6681 final int viewportW = parentAppBounds.width(); 6682 final int viewportH = parentAppBounds.height(); 6683 // Only allow to scale down. 6684 mSizeCompatScale = (contentW <= viewportW && contentH <= viewportH) 6685 ? 1f : Math.min((float) viewportW / contentW, (float) viewportH / contentH); 6686 final int screenTopInset = parentAppBounds.top - parentBounds.top; 6687 final boolean topNotAligned = screenTopInset != resolvedAppBounds.top - resolvedBounds.top; 6688 if (mSizeCompatScale != 1f || topNotAligned) { 6689 if (mSizeCompatBounds == null) { 6690 mSizeCompatBounds = new Rect(); 6691 } 6692 mSizeCompatBounds.set(resolvedAppBounds); 6693 mSizeCompatBounds.offsetTo(0, 0); 6694 mSizeCompatBounds.scale(mSizeCompatScale); 6695 // The insets are included in height, e.g. the area of real cutout shouldn't be scaled. 6696 mSizeCompatBounds.bottom += screenTopInset; 6697 } else { 6698 mSizeCompatBounds = null; 6699 } 6700 6701 // Center horizontally in parent (app bounds) and align to top of parent (bounds) 6702 // - this is a UX choice. 6703 final int offsetX = getHorizontalCenterOffset( 6704 (int) viewportW, (int) (contentW * mSizeCompatScale)); 6705 // Above coordinates are in "@" space, now place "*" and "#" to screen space. 6706 final int screenPosX = (fillContainer ? parentBounds.left : parentAppBounds.left) + offsetX; 6707 final int screenPosY = parentBounds.top; 6708 if (screenPosX != 0 || screenPosY != 0) { 6709 if (mSizeCompatBounds != null) { 6710 mSizeCompatBounds.offset(screenPosX, screenPosY); 6711 } 6712 // Add the global coordinates and remove the local coordinates. 6713 final int dx = screenPosX - resolvedBounds.left; 6714 final int dy = screenPosY - resolvedBounds.top; 6715 offsetBounds(resolvedConfig, dx, dy); 6716 } 6717 } 6718 6719 /** @return The horizontal offset of putting the content in the center of viewport. */ getHorizontalCenterOffset(int viewportW, int contentW)6720 private static int getHorizontalCenterOffset(int viewportW, int contentW) { 6721 return (int) ((viewportW - contentW + 1) * 0.5f); 6722 } 6723 offsetBounds(Configuration inOutConfig, int offsetX, int offsetY)6724 private static void offsetBounds(Configuration inOutConfig, int offsetX, int offsetY) { 6725 inOutConfig.windowConfiguration.getBounds().offset(offsetX, offsetY); 6726 inOutConfig.windowConfiguration.getAppBounds().offset(offsetX, offsetY); 6727 } 6728 6729 @Override getBounds()6730 public Rect getBounds() { 6731 if (mSizeCompatBounds != null) { 6732 return mSizeCompatBounds; 6733 } 6734 return super.getBounds(); 6735 } 6736 6737 @VisibleForTesting 6738 @Override getAnimationBounds(int appStackClipMode)6739 Rect getAnimationBounds(int appStackClipMode) { 6740 if (appStackClipMode == STACK_CLIP_BEFORE_ANIM && getStack() != null) { 6741 // Using the stack bounds here effectively applies the clipping before animation. 6742 return getStack().getBounds(); 6743 } 6744 // Use task-bounds if available so that activity-level letterbox (maxAspectRatio) is 6745 // included in the animation. 6746 return task != null ? task.getBounds() : getBounds(); 6747 } 6748 6749 @Override getAnimationPosition(Point outPosition)6750 void getAnimationPosition(Point outPosition) { 6751 // Always animate from zero because if the activity doesn't fill the task, the letterbox 6752 // will fill the remaining area that should be included in the animation. 6753 outPosition.set(0, 0); 6754 } 6755 6756 @Override onConfigurationChanged(Configuration newParentConfig)6757 public void onConfigurationChanged(Configuration newParentConfig) { 6758 if (mCompatDisplayInsets != null) { 6759 Configuration overrideConfig = getRequestedOverrideConfiguration(); 6760 // Adapt to changes in orientation locking. The app is still non-resizable, but 6761 // it can change which orientation is fixed. If the fixed orientation changes, 6762 // update the rotation used on the "compat" display 6763 boolean wasFixedOrient = 6764 overrideConfig.windowConfiguration.getRotation() != ROTATION_UNDEFINED; 6765 int requestedOrient = getRequestedConfigurationOrientation(); 6766 if (requestedOrient != ORIENTATION_UNDEFINED 6767 && requestedOrient != getConfiguration().orientation 6768 // The task orientation depends on the top activity orientation, so it 6769 // should match. If it doesn't, just wait until it does. 6770 && requestedOrient == getParent().getConfiguration().orientation 6771 && (overrideConfig.windowConfiguration.getRotation() 6772 != getParent().getWindowConfiguration().getRotation())) { 6773 overrideConfig.windowConfiguration.setRotation( 6774 getParent().getWindowConfiguration().getRotation()); 6775 onRequestedOverrideConfigurationChanged(overrideConfig); 6776 return; 6777 } else if (wasFixedOrient && requestedOrient == ORIENTATION_UNDEFINED 6778 && (overrideConfig.windowConfiguration.getRotation() 6779 != ROTATION_UNDEFINED)) { 6780 overrideConfig.windowConfiguration.setRotation(ROTATION_UNDEFINED); 6781 onRequestedOverrideConfigurationChanged(overrideConfig); 6782 return; 6783 } 6784 } 6785 super.onConfigurationChanged(newParentConfig); 6786 6787 // Configuration's equality doesn't consider seq so if only seq number changes in resolved 6788 // override configuration. Therefore ConfigurationContainer doesn't change merged override 6789 // configuration, but it's used to push configuration changes so explicitly update that. 6790 if (getMergedOverrideConfiguration().seq != getResolvedOverrideConfiguration().seq) { 6791 onMergedOverrideConfigurationChanged(); 6792 } 6793 6794 final DisplayContent display = getDisplay(); 6795 if (display == null) { 6796 return; 6797 } 6798 if (mVisibleRequested) { 6799 // It may toggle the UI for user to restart the size compatibility mode activity. 6800 display.handleActivitySizeCompatModeIfNeeded(this); 6801 } else if (mCompatDisplayInsets != null) { 6802 // The override changes can only be obtained from display, because we don't have the 6803 // difference of full configuration in each hierarchy. 6804 final int displayChanges = display.getCurrentOverrideConfigurationChanges(); 6805 final int orientationChanges = CONFIG_WINDOW_CONFIGURATION 6806 | CONFIG_SCREEN_SIZE | CONFIG_ORIENTATION; 6807 final boolean hasNonOrienSizeChanged = hasResizeChange(displayChanges) 6808 // Filter out the case of simple orientation change. 6809 && (displayChanges & orientationChanges) != orientationChanges; 6810 // For background activity that uses size compatibility mode, if the size or density of 6811 // the display is changed, then reset the override configuration and kill the activity's 6812 // process if its process state is not important to user. 6813 if (hasNonOrienSizeChanged || (displayChanges & ActivityInfo.CONFIG_DENSITY) != 0) { 6814 restartProcessIfVisible(); 6815 } 6816 } 6817 } 6818 6819 /** Returns true if the configuration is compatible with this activity. */ isConfigurationCompatible(Configuration config)6820 boolean isConfigurationCompatible(Configuration config) { 6821 final int orientation = getRequestedOrientation(); 6822 if (isFixedOrientationPortrait(orientation) 6823 && config.orientation != ORIENTATION_PORTRAIT) { 6824 return false; 6825 } 6826 if (isFixedOrientationLandscape(orientation) 6827 && config.orientation != ORIENTATION_LANDSCAPE) { 6828 return false; 6829 } 6830 return true; 6831 } 6832 6833 /** 6834 * Applies aspect ratio restrictions to outBounds. If no restrictions, then no change is 6835 * made to outBounds. 6836 */ 6837 // TODO(b/36505427): Consider moving this method and similar ones to ConfigurationContainer. applyAspectRatio(Rect outBounds, Rect containingAppBounds, Rect containingBounds)6838 private void applyAspectRatio(Rect outBounds, Rect containingAppBounds, 6839 Rect containingBounds) { 6840 final float maxAspectRatio = info.maxAspectRatio; 6841 final ActivityStack stack = getRootTask(); 6842 final float minAspectRatio = info.minAspectRatio; 6843 6844 if (task == null || stack == null || (inMultiWindowMode() && !shouldUseSizeCompatMode()) 6845 || (maxAspectRatio == 0 && minAspectRatio == 0) 6846 || isInVrUiMode(getConfiguration())) { 6847 // We don't enforce aspect ratio if the activity task is in multiwindow unless it 6848 // is in size-compat mode. We also don't set it if we are in VR mode. 6849 return; 6850 } 6851 6852 final int containingAppWidth = containingAppBounds.width(); 6853 final int containingAppHeight = containingAppBounds.height(); 6854 final float containingRatio = Math.max(containingAppWidth, containingAppHeight) 6855 / (float) Math.min(containingAppWidth, containingAppHeight); 6856 6857 int activityWidth = containingAppWidth; 6858 int activityHeight = containingAppHeight; 6859 6860 if (containingRatio > maxAspectRatio && maxAspectRatio != 0) { 6861 if (containingAppWidth < containingAppHeight) { 6862 // Width is the shorter side, so we use that to figure-out what the max. height 6863 // should be given the aspect ratio. 6864 activityHeight = (int) ((activityWidth * maxAspectRatio) + 0.5f); 6865 } else { 6866 // Height is the shorter side, so we use that to figure-out what the max. width 6867 // should be given the aspect ratio. 6868 activityWidth = (int) ((activityHeight * maxAspectRatio) + 0.5f); 6869 } 6870 } else if (containingRatio < minAspectRatio) { 6871 boolean adjustWidth; 6872 switch (getRequestedConfigurationOrientation()) { 6873 case ORIENTATION_LANDSCAPE: 6874 // Width should be the longer side for this landscape app, so we use the width 6875 // to figure-out what the max. height should be given the aspect ratio. 6876 adjustWidth = false; 6877 break; 6878 case ORIENTATION_PORTRAIT: 6879 // Height should be the longer side for this portrait app, so we use the height 6880 // to figure-out what the max. width should be given the aspect ratio. 6881 adjustWidth = true; 6882 break; 6883 default: 6884 // This app doesn't have a preferred orientation, so we keep the length of the 6885 // longer side, and use it to figure-out the length of the shorter side. 6886 if (containingAppWidth < containingAppHeight) { 6887 // Width is the shorter side, so we use the height to figure-out what the 6888 // max. width should be given the aspect ratio. 6889 adjustWidth = true; 6890 } else { 6891 // Height is the shorter side, so we use the width to figure-out what the 6892 // max. height should be given the aspect ratio. 6893 adjustWidth = false; 6894 } 6895 break; 6896 } 6897 if (adjustWidth) { 6898 activityWidth = (int) ((activityHeight / minAspectRatio) + 0.5f); 6899 } else { 6900 activityHeight = (int) ((activityWidth / minAspectRatio) + 0.5f); 6901 } 6902 } 6903 6904 if (containingAppWidth <= activityWidth && containingAppHeight <= activityHeight) { 6905 // The display matches or is less than the activity aspect ratio, so nothing else to do. 6906 return; 6907 } 6908 6909 // Compute configuration based on max supported width and height. 6910 // Also account for the left / top insets (e.g. from display cutouts), which will be clipped 6911 // away later in {@link Task#computeConfigResourceOverrides()}. Otherwise, the app 6912 // bounds would end up too small. 6913 outBounds.set(containingBounds.left, containingBounds.top, 6914 activityWidth + containingAppBounds.left, 6915 activityHeight + containingAppBounds.top); 6916 } 6917 6918 /** 6919 * @return {@code true} if this activity was reparented to another display but 6920 * {@link #ensureActivityConfiguration} is not called. 6921 */ shouldUpdateConfigForDisplayChanged()6922 boolean shouldUpdateConfigForDisplayChanged() { 6923 return mLastReportedDisplayId != getDisplayId(); 6924 } 6925 ensureActivityConfiguration(int globalChanges, boolean preserveWindow)6926 boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow) { 6927 return ensureActivityConfiguration(globalChanges, preserveWindow, 6928 false /* ignoreVisibility */); 6929 } 6930 6931 /** 6932 * Make sure the given activity matches the current configuration. Ensures the HistoryRecord 6933 * is updated with the correct configuration and all other bookkeeping is handled. 6934 * 6935 * @param globalChanges The changes to the global configuration. 6936 * @param preserveWindow If the activity window should be preserved on screen if the activity 6937 * is relaunched. 6938 * @param ignoreVisibility If we should try to relaunch the activity even if it is invisible 6939 * (stopped state). This is useful for the case where we know the 6940 * activity will be visible soon and we want to ensure its configuration 6941 * before we make it visible. 6942 * @return False if the activity was relaunched and true if it wasn't relaunched because we 6943 * can't or the app handles the specific configuration that is changing. 6944 */ ensureActivityConfiguration(int globalChanges, boolean preserveWindow, boolean ignoreVisibility)6945 boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow, 6946 boolean ignoreVisibility) { 6947 final ActivityStack stack = getRootTask(); 6948 if (stack.mConfigWillChange) { 6949 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, 6950 "Skipping config check (will change): " + this); 6951 return true; 6952 } 6953 6954 // We don't worry about activities that are finishing. 6955 if (finishing) { 6956 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, 6957 "Configuration doesn't matter in finishing " + this); 6958 stopFreezingScreenLocked(false); 6959 return true; 6960 } 6961 6962 if (!ignoreVisibility && (mState == STOPPING || mState == STOPPED || !shouldBeVisible())) { 6963 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, 6964 "Skipping config check invisible: " + this); 6965 return true; 6966 } 6967 6968 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, 6969 "Ensuring correct configuration: " + this); 6970 6971 final int newDisplayId = getDisplayId(); 6972 final boolean displayChanged = mLastReportedDisplayId != newDisplayId; 6973 if (displayChanged) { 6974 mLastReportedDisplayId = newDisplayId; 6975 } 6976 // TODO(b/36505427): Is there a better place to do this? 6977 updateSizeCompatMode(); 6978 6979 // Short circuit: if the two full configurations are equal (the common case), then there is 6980 // nothing to do. We test the full configuration instead of the global and merged override 6981 // configurations because there are cases (like moving a task to the pinned stack) where 6982 // the combine configurations are equal, but would otherwise differ in the override config 6983 mTmpConfig.setTo(mLastReportedConfiguration.getMergedConfiguration()); 6984 if (getConfiguration().equals(mTmpConfig) && !forceNewConfig && !displayChanged) { 6985 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, 6986 "Configuration & display unchanged in " + this); 6987 return true; 6988 } 6989 6990 // Okay we now are going to make this activity have the new config. 6991 // But then we need to figure out how it needs to deal with that. 6992 6993 // Find changes between last reported merged configuration and the current one. This is used 6994 // to decide whether to relaunch an activity or just report a configuration change. 6995 final int changes = getConfigurationChanges(mTmpConfig); 6996 6997 // Update last reported values. 6998 final Configuration newMergedOverrideConfig = getMergedOverrideConfiguration(); 6999 7000 setLastReportedConfiguration(getProcessGlobalConfiguration(), newMergedOverrideConfig); 7001 7002 if (mState == INITIALIZING) { 7003 // No need to relaunch or schedule new config for activity that hasn't been launched 7004 // yet. We do, however, return after applying the config to activity record, so that 7005 // it will use it for launch transaction. 7006 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, 7007 "Skipping config check for initializing activity: " + this); 7008 return true; 7009 } 7010 7011 if (changes == 0 && !forceNewConfig) { 7012 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, 7013 "Configuration no differences in " + this); 7014 // There are no significant differences, so we won't relaunch but should still deliver 7015 // the new configuration to the client process. 7016 if (displayChanged) { 7017 scheduleActivityMovedToDisplay(newDisplayId, newMergedOverrideConfig); 7018 } else { 7019 scheduleConfigurationChanged(newMergedOverrideConfig); 7020 } 7021 return true; 7022 } 7023 7024 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, 7025 "Configuration changes for " + this + ", allChanges=" 7026 + Configuration.configurationDiffToString(changes)); 7027 7028 // If the activity isn't currently running, just leave the new configuration and it will 7029 // pick that up next time it starts. 7030 if (!attachedToProcess()) { 7031 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, 7032 "Configuration doesn't matter not running " + this); 7033 stopFreezingScreenLocked(false); 7034 forceNewConfig = false; 7035 return true; 7036 } 7037 7038 // Figure out how to handle the changes between the configurations. 7039 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, 7040 "Checking to restart " + info.name + ": changed=0x" 7041 + Integer.toHexString(changes) + ", handles=0x" 7042 + Integer.toHexString(info.getRealConfigChanged()) 7043 + ", mLastReportedConfiguration=" + mLastReportedConfiguration); 7044 7045 if (shouldRelaunchLocked(changes, mTmpConfig) || forceNewConfig) { 7046 // Aha, the activity isn't handling the change, so DIE DIE DIE. 7047 configChangeFlags |= changes; 7048 startFreezingScreenLocked(globalChanges); 7049 forceNewConfig = false; 7050 preserveWindow &= isResizeOnlyChange(changes); 7051 final boolean hasResizeChange = hasResizeChange(changes & ~info.getRealConfigChanged()); 7052 if (hasResizeChange) { 7053 final boolean isDragResizing = task.isDragResizing(); 7054 mRelaunchReason = isDragResizing ? RELAUNCH_REASON_FREE_RESIZE 7055 : RELAUNCH_REASON_WINDOWING_MODE_RESIZE; 7056 } else { 7057 mRelaunchReason = RELAUNCH_REASON_NONE; 7058 } 7059 if (!attachedToProcess()) { 7060 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, 7061 "Config is destroying non-running " + this); 7062 destroyImmediately(true /* removeFromApp */, "config"); 7063 } else if (mState == PAUSING) { 7064 // A little annoying: we are waiting for this activity to finish pausing. Let's not 7065 // do anything now, but just flag that it needs to be restarted when done pausing. 7066 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, 7067 "Config is skipping already pausing " + this); 7068 deferRelaunchUntilPaused = true; 7069 preserveWindowOnDeferredRelaunch = preserveWindow; 7070 return true; 7071 } else { 7072 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, 7073 "Config is relaunching " + this); 7074 if (DEBUG_STATES && !mVisibleRequested) { 7075 Slog.v(TAG_STATES, "Config is relaunching invisible activity " + this 7076 + " called by " + Debug.getCallers(4)); 7077 } 7078 relaunchActivityLocked(preserveWindow); 7079 } 7080 7081 // All done... tell the caller we weren't able to keep this activity around. 7082 return false; 7083 } 7084 7085 // Default case: the activity can handle this new configuration, so hand it over. 7086 // NOTE: We only forward the override configuration as the system level configuration 7087 // changes is always sent to all processes when they happen so it can just use whatever 7088 // system level configuration it last got. 7089 if (displayChanged) { 7090 scheduleActivityMovedToDisplay(newDisplayId, newMergedOverrideConfig); 7091 } else { 7092 scheduleConfigurationChanged(newMergedOverrideConfig); 7093 } 7094 stopFreezingScreenLocked(false); 7095 7096 return true; 7097 } 7098 7099 /** Get process configuration, or global config if the process is not set. */ getProcessGlobalConfiguration()7100 private Configuration getProcessGlobalConfiguration() { 7101 return app != null ? app.getConfiguration() : mAtmService.getGlobalConfiguration(); 7102 } 7103 7104 /** 7105 * When assessing a configuration change, decide if the changes flags and the new configurations 7106 * should cause the Activity to relaunch. 7107 * 7108 * @param changes the changes due to the given configuration. 7109 * @param changesConfig the configuration that was used to calculate the given changes via a 7110 * call to getConfigurationChanges. 7111 */ shouldRelaunchLocked(int changes, Configuration changesConfig)7112 private boolean shouldRelaunchLocked(int changes, Configuration changesConfig) { 7113 int configChanged = info.getRealConfigChanged(); 7114 boolean onlyVrUiModeChanged = onlyVrUiModeChanged(changes, changesConfig); 7115 7116 // Override for apps targeting pre-O sdks 7117 // If a device is in VR mode, and we're transitioning into VR ui mode, add ignore ui mode 7118 // to the config change. 7119 // For O and later, apps will be required to add configChanges="uimode" to their manifest. 7120 if (info.applicationInfo.targetSdkVersion < O 7121 && requestedVrComponent != null 7122 && onlyVrUiModeChanged) { 7123 configChanged |= CONFIG_UI_MODE; 7124 } 7125 7126 return (changes&(~configChanged)) != 0; 7127 } 7128 7129 /** 7130 * Returns true if the configuration change is solely due to the UI mode switching into or out 7131 * of UI_MODE_TYPE_VR_HEADSET. 7132 */ onlyVrUiModeChanged(int changes, Configuration lastReportedConfig)7133 private boolean onlyVrUiModeChanged(int changes, Configuration lastReportedConfig) { 7134 final Configuration currentConfig = getConfiguration(); 7135 return changes == CONFIG_UI_MODE && (isInVrUiMode(currentConfig) 7136 != isInVrUiMode(lastReportedConfig)); 7137 } 7138 getConfigurationChanges(Configuration lastReportedConfig)7139 private int getConfigurationChanges(Configuration lastReportedConfig) { 7140 // Determine what has changed. May be nothing, if this is a config that has come back from 7141 // the app after going idle. In that case we just want to leave the official config object 7142 // now in the activity and do nothing else. 7143 final Configuration currentConfig = getConfiguration(); 7144 int changes = lastReportedConfig.diff(currentConfig); 7145 // We don't want to use size changes if they don't cross boundaries that are important to 7146 // the app. 7147 if ((changes & CONFIG_SCREEN_SIZE) != 0) { 7148 final boolean crosses = crossesHorizontalSizeThreshold(lastReportedConfig.screenWidthDp, 7149 currentConfig.screenWidthDp) 7150 || crossesVerticalSizeThreshold(lastReportedConfig.screenHeightDp, 7151 currentConfig.screenHeightDp); 7152 if (!crosses) { 7153 changes &= ~CONFIG_SCREEN_SIZE; 7154 } 7155 } 7156 if ((changes & CONFIG_SMALLEST_SCREEN_SIZE) != 0) { 7157 final int oldSmallest = lastReportedConfig.smallestScreenWidthDp; 7158 final int newSmallest = currentConfig.smallestScreenWidthDp; 7159 if (!crossesSmallestSizeThreshold(oldSmallest, newSmallest)) { 7160 changes &= ~CONFIG_SMALLEST_SCREEN_SIZE; 7161 } 7162 } 7163 // We don't want window configuration to cause relaunches. 7164 if ((changes & CONFIG_WINDOW_CONFIGURATION) != 0) { 7165 changes &= ~CONFIG_WINDOW_CONFIGURATION; 7166 } 7167 7168 return changes; 7169 } 7170 isResizeOnlyChange(int change)7171 private static boolean isResizeOnlyChange(int change) { 7172 return (change & ~(CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE | CONFIG_ORIENTATION 7173 | CONFIG_SCREEN_LAYOUT)) == 0; 7174 } 7175 hasResizeChange(int change)7176 private static boolean hasResizeChange(int change) { 7177 return (change & (CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE | CONFIG_ORIENTATION 7178 | CONFIG_SCREEN_LAYOUT)) != 0; 7179 } 7180 relaunchActivityLocked(boolean preserveWindow)7181 void relaunchActivityLocked(boolean preserveWindow) { 7182 if (mAtmService.mSuppressResizeConfigChanges && preserveWindow) { 7183 configChangeFlags = 0; 7184 return; 7185 } 7186 7187 final boolean andResume = shouldBeResumed(null /*activeActivity*/); 7188 List<ResultInfo> pendingResults = null; 7189 List<ReferrerIntent> pendingNewIntents = null; 7190 if (andResume) { 7191 pendingResults = results; 7192 pendingNewIntents = newIntents; 7193 } 7194 if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, 7195 "Relaunching: " + this + " with results=" + pendingResults 7196 + " newIntents=" + pendingNewIntents + " andResume=" + andResume 7197 + " preserveWindow=" + preserveWindow); 7198 if (andResume) { 7199 EventLogTags.writeWmRelaunchResumeActivity(mUserId, System.identityHashCode(this), 7200 task.mTaskId, shortComponentName); 7201 } else { 7202 EventLogTags.writeWmRelaunchActivity(mUserId, System.identityHashCode(this), 7203 task.mTaskId, shortComponentName); 7204 } 7205 7206 startFreezingScreenLocked(0); 7207 7208 try { 7209 if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH, 7210 "Moving to " + (andResume ? "RESUMED" : "PAUSED") + " Relaunching " + this 7211 + " callers=" + Debug.getCallers(6)); 7212 forceNewConfig = false; 7213 startRelaunching(); 7214 final ClientTransactionItem callbackItem = ActivityRelaunchItem.obtain(pendingResults, 7215 pendingNewIntents, configChangeFlags, 7216 new MergedConfiguration(getProcessGlobalConfiguration(), 7217 getMergedOverrideConfiguration()), 7218 preserveWindow); 7219 final ActivityLifecycleItem lifecycleItem; 7220 if (andResume) { 7221 lifecycleItem = ResumeActivityItem.obtain( 7222 getDisplay().mDisplayContent.isNextTransitionForward()); 7223 } else { 7224 lifecycleItem = PauseActivityItem.obtain(); 7225 } 7226 final ClientTransaction transaction = ClientTransaction.obtain(app.getThread(), appToken); 7227 transaction.addCallback(callbackItem); 7228 transaction.setLifecycleStateRequest(lifecycleItem); 7229 mAtmService.getLifecycleManager().scheduleTransaction(transaction); 7230 // Note: don't need to call pauseIfSleepingLocked() here, because the caller will only 7231 // request resume if this activity is currently resumed, which implies we aren't 7232 // sleeping. 7233 } catch (RemoteException e) { 7234 if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG_SWITCH, "Relaunch failed", e); 7235 } 7236 7237 if (andResume) { 7238 if (DEBUG_STATES) { 7239 Slog.d(TAG_STATES, "Resumed after relaunch " + this); 7240 } 7241 results = null; 7242 newIntents = null; 7243 mAtmService.getAppWarningsLocked().onResumeActivity(this); 7244 } else { 7245 removePauseTimeout(); 7246 setState(PAUSED, "relaunchActivityLocked"); 7247 } 7248 7249 configChangeFlags = 0; 7250 deferRelaunchUntilPaused = false; 7251 preserveWindowOnDeferredRelaunch = false; 7252 } 7253 7254 /** 7255 * Request the process of the activity to restart with its saved state (from 7256 * {@link android.app.Activity#onSaveInstanceState}) if possible. It also forces to recompute 7257 * the override configuration. Note if the activity is in background, the process will be killed 7258 * directly with keeping its record. 7259 */ restartProcessIfVisible()7260 void restartProcessIfVisible() { 7261 Slog.i(TAG, "Request to restart process of " + this); 7262 7263 // Reset the existing override configuration so it can be updated according to the latest 7264 // configuration. 7265 clearSizeCompatMode(); 7266 if (mVisibleRequested) { 7267 // Configuration will be ensured when becoming visible, so if it is already visible, 7268 // then the manual update is needed. 7269 updateSizeCompatMode(); 7270 } 7271 7272 if (!attachedToProcess()) { 7273 return; 7274 } 7275 7276 // The restarting state avoids removing this record when process is died. 7277 setState(RESTARTING_PROCESS, "restartActivityProcess"); 7278 7279 if (!mVisibleRequested || mHaveState) { 7280 // Kill its process immediately because the activity should be in background. 7281 // The activity state will be update to {@link #DESTROYED} in 7282 // {@link ActivityStack#cleanUp} when handling process died. 7283 mAtmService.mH.post(() -> { 7284 final WindowProcessController wpc; 7285 synchronized (mAtmService.mGlobalLock) { 7286 if (!hasProcess() 7287 || app.getReportedProcState() <= PROCESS_STATE_IMPORTANT_FOREGROUND) { 7288 return; 7289 } 7290 wpc = app; 7291 } 7292 mAtmService.mAmInternal.killProcess(wpc.mName, wpc.mUid, "resetConfig"); 7293 }); 7294 return; 7295 } 7296 7297 if (getParent() != null) { 7298 startFreezingScreen(); 7299 } 7300 // The process will be killed until the activity reports stopped with saved state (see 7301 // {@link ActivityTaskManagerService.activityStopped}). 7302 try { 7303 mAtmService.getLifecycleManager().scheduleTransaction(app.getThread(), appToken, 7304 StopActivityItem.obtain(0 /* configChanges */)); 7305 } catch (RemoteException e) { 7306 Slog.w(TAG, "Exception thrown during restart " + this, e); 7307 } 7308 mStackSupervisor.scheduleRestartTimeout(this); 7309 } 7310 isProcessRunning()7311 boolean isProcessRunning() { 7312 WindowProcessController proc = app; 7313 if (proc == null) { 7314 proc = mAtmService.mProcessNames.get(processName, info.applicationInfo.uid); 7315 } 7316 return proc != null && proc.hasThread(); 7317 } 7318 7319 /** 7320 * @return Whether a task snapshot starting window may be shown. 7321 */ allowTaskSnapshot()7322 private boolean allowTaskSnapshot() { 7323 if (newIntents == null) { 7324 return true; 7325 } 7326 7327 // Restrict task snapshot starting window to launcher start, or is same as the last 7328 // delivered intent, or there is no intent at all (eg. task being brought to front). If 7329 // the intent is something else, likely the app is going to show some specific page or 7330 // view, instead of what's left last time. 7331 for (int i = newIntents.size() - 1; i >= 0; i--) { 7332 final Intent intent = newIntents.get(i); 7333 if (intent == null || ActivityRecord.isMainIntent(intent)) { 7334 continue; 7335 } 7336 7337 final boolean sameIntent = mLastNewIntent != null ? mLastNewIntent.filterEquals(intent) 7338 : this.intent.filterEquals(intent); 7339 if (!sameIntent || intent.getExtras() != null) { 7340 return false; 7341 } 7342 } 7343 return true; 7344 } 7345 7346 /** 7347 * Returns {@code true} if the associated activity has the no history flag set on it. 7348 * {@code false} otherwise. 7349 */ isNoHistory()7350 boolean isNoHistory() { 7351 return (intent.getFlags() & FLAG_ACTIVITY_NO_HISTORY) != 0 7352 || (info.flags & FLAG_NO_HISTORY) != 0; 7353 } 7354 saveToXml(XmlSerializer out)7355 void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException { 7356 out.attribute(null, ATTR_ID, String.valueOf(createTime)); 7357 out.attribute(null, ATTR_LAUNCHEDFROMUID, String.valueOf(launchedFromUid)); 7358 if (launchedFromPackage != null) { 7359 out.attribute(null, ATTR_LAUNCHEDFROMPACKAGE, launchedFromPackage); 7360 } 7361 if (launchedFromFeatureId != null) { 7362 out.attribute(null, ATTR_LAUNCHEDFROMFEATURE, launchedFromFeatureId); 7363 } 7364 if (resolvedType != null) { 7365 out.attribute(null, ATTR_RESOLVEDTYPE, resolvedType); 7366 } 7367 out.attribute(null, ATTR_COMPONENTSPECIFIED, String.valueOf(componentSpecified)); 7368 out.attribute(null, ATTR_USERID, String.valueOf(mUserId)); 7369 7370 if (taskDescription != null) { 7371 taskDescription.saveToXml(out); 7372 } 7373 7374 out.startTag(null, TAG_INTENT); 7375 intent.saveToXml(out); 7376 out.endTag(null, TAG_INTENT); 7377 7378 if (isPersistable() && mPersistentState != null) { 7379 out.startTag(null, TAG_PERSISTABLEBUNDLE); 7380 mPersistentState.saveToXml(out); 7381 out.endTag(null, TAG_PERSISTABLEBUNDLE); 7382 } 7383 } 7384 restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)7385 static ActivityRecord restoreFromXml(XmlPullParser in, 7386 ActivityStackSupervisor stackSupervisor) throws IOException, XmlPullParserException { 7387 Intent intent = null; 7388 PersistableBundle persistentState = null; 7389 int launchedFromUid = 0; 7390 String launchedFromPackage = null; 7391 String launchedFromFeature = null; 7392 String resolvedType = null; 7393 boolean componentSpecified = false; 7394 int userId = 0; 7395 long createTime = -1; 7396 final int outerDepth = in.getDepth(); 7397 TaskDescription taskDescription = new TaskDescription(); 7398 7399 for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) { 7400 final String attrName = in.getAttributeName(attrNdx); 7401 final String attrValue = in.getAttributeValue(attrNdx); 7402 if (DEBUG) Slog.d(TaskPersister.TAG, 7403 "ActivityRecord: attribute name=" + attrName + " value=" + attrValue); 7404 if (ATTR_ID.equals(attrName)) { 7405 createTime = Long.parseLong(attrValue); 7406 } else if (ATTR_LAUNCHEDFROMUID.equals(attrName)) { 7407 launchedFromUid = Integer.parseInt(attrValue); 7408 } else if (ATTR_LAUNCHEDFROMPACKAGE.equals(attrName)) { 7409 launchedFromPackage = attrValue; 7410 } else if (ATTR_LAUNCHEDFROMFEATURE.equals(attrName)) { 7411 launchedFromFeature = attrValue; 7412 } else if (ATTR_RESOLVEDTYPE.equals(attrName)) { 7413 resolvedType = attrValue; 7414 } else if (ATTR_COMPONENTSPECIFIED.equals(attrName)) { 7415 componentSpecified = Boolean.parseBoolean(attrValue); 7416 } else if (ATTR_USERID.equals(attrName)) { 7417 userId = Integer.parseInt(attrValue); 7418 } else if (!attrName.startsWith(ATTR_TASKDESCRIPTION_PREFIX)) { 7419 Log.d(TAG, "Unknown ActivityRecord attribute=" + attrName); 7420 } 7421 } 7422 taskDescription.restoreFromXml(in); 7423 7424 int event; 7425 while (((event = in.next()) != END_DOCUMENT) && 7426 (event != END_TAG || in.getDepth() >= outerDepth)) { 7427 if (event == START_TAG) { 7428 final String name = in.getName(); 7429 if (DEBUG) 7430 Slog.d(TaskPersister.TAG, "ActivityRecord: START_TAG name=" + name); 7431 if (TAG_INTENT.equals(name)) { 7432 intent = Intent.restoreFromXml(in); 7433 if (DEBUG) 7434 Slog.d(TaskPersister.TAG, "ActivityRecord: intent=" + intent); 7435 } else if (TAG_PERSISTABLEBUNDLE.equals(name)) { 7436 persistentState = PersistableBundle.restoreFromXml(in); 7437 if (DEBUG) Slog.d(TaskPersister.TAG, 7438 "ActivityRecord: persistentState=" + persistentState); 7439 } else { 7440 Slog.w(TAG, "restoreActivity: unexpected name=" + name); 7441 XmlUtils.skipCurrentTag(in); 7442 } 7443 } 7444 } 7445 7446 if (intent == null) { 7447 throw new XmlPullParserException("restoreActivity error intent=" + intent); 7448 } 7449 7450 final ActivityTaskManagerService service = stackSupervisor.mService; 7451 final ActivityInfo aInfo = stackSupervisor.resolveActivity(intent, resolvedType, 0, null, 7452 userId, Binder.getCallingUid()); 7453 if (aInfo == null) { 7454 throw new XmlPullParserException("restoreActivity resolver error. Intent=" + intent + 7455 " resolvedType=" + resolvedType); 7456 } 7457 final ActivityRecord r = new ActivityRecord(service, null /* caller */, 7458 0 /* launchedFromPid */, launchedFromUid, launchedFromPackage, launchedFromFeature, 7459 intent, resolvedType, aInfo, service.getConfiguration(), null /* resultTo */, 7460 null /* resultWho */, 0 /* reqCode */, componentSpecified, 7461 false /* rootVoiceInteraction */, stackSupervisor, null /* options */, 7462 null /* sourceRecord */); 7463 7464 r.mPersistentState = persistentState; 7465 r.taskDescription = taskDescription; 7466 r.createTime = createTime; 7467 7468 return r; 7469 } 7470 isInVrUiMode(Configuration config)7471 private static boolean isInVrUiMode(Configuration config) { 7472 return (config.uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_VR_HEADSET; 7473 } 7474 getUid()7475 int getUid() { 7476 return info.applicationInfo.uid; 7477 } 7478 isUid(int uid)7479 boolean isUid(int uid) { 7480 return info.applicationInfo.uid == uid; 7481 } 7482 getPid()7483 int getPid() { 7484 return app != null ? app.getPid() : 0; 7485 } 7486 7487 /** 7488 * Determines whether this ActivityRecord can turn the screen on. It checks whether the flag 7489 * {@link ActivityRecord#getTurnScreenOnFlag} is set and checks whether the ActivityRecord 7490 * should be visible depending on Keyguard state 7491 * 7492 * @return true if the screen can be turned on, false otherwise. 7493 */ canTurnScreenOn()7494 boolean canTurnScreenOn() { 7495 if (!getTurnScreenOnFlag()) { 7496 return false; 7497 } 7498 final ActivityStack stack = getRootTask(); 7499 return stack != null && 7500 stack.checkKeyguardVisibility(this, true /* shouldBeVisible */, 7501 stack.topRunningActivity() == this /* isTop */); 7502 } 7503 setTurnScreenOn(boolean turnScreenOn)7504 void setTurnScreenOn(boolean turnScreenOn) { 7505 mTurnScreenOn = turnScreenOn; 7506 } 7507 getTurnScreenOnFlag()7508 boolean getTurnScreenOnFlag() { 7509 return mTurnScreenOn || containsTurnScreenOnWindow(); 7510 } 7511 containsTurnScreenOnWindow()7512 private boolean containsTurnScreenOnWindow() { 7513 // When we are relaunching, it is possible for us to be unfrozen before our previous 7514 // windows have been added back. Using the cached value ensures that our previous 7515 // showWhenLocked preference is honored until relaunching is complete. 7516 if (isRelaunching()) { 7517 return mLastContainsTurnScreenOnWindow; 7518 } 7519 for (int i = mChildren.size() - 1; i >= 0; i--) { 7520 if ((mChildren.get(i).mAttrs.flags & LayoutParams.FLAG_TURN_SCREEN_ON) != 0) { 7521 return true; 7522 } 7523 } 7524 return false; 7525 } 7526 7527 /** 7528 * Check if this activity is able to resume. For pre-Q apps, only the topmost activities of each 7529 * process are allowed to be resumed. 7530 * 7531 * @return true if this activity can be resumed. 7532 */ canResumeByCompat()7533 boolean canResumeByCompat() { 7534 return app == null || app.updateTopResumingActivityInProcessIfNeeded(this); 7535 } 7536 isTopRunningActivity()7537 boolean isTopRunningActivity() { 7538 return mRootWindowContainer.topRunningActivity() == this; 7539 } 7540 7541 /** 7542 * @return {@code true} if this is the resumed activity on its current display, {@code false} 7543 * otherwise. 7544 */ isResumedActivityOnDisplay()7545 boolean isResumedActivityOnDisplay() { 7546 final DisplayContent display = getDisplay(); 7547 if (display == null) { 7548 return false; 7549 } 7550 for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { 7551 final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx); 7552 final ActivityRecord resumedActivity = taskDisplayArea.getFocusedActivity(); 7553 if (resumedActivity != null) { 7554 return resumedActivity == this; 7555 } 7556 } 7557 return false; 7558 } 7559 7560 7561 /** 7562 * Check if this is the root of the task - first activity that is not finishing, starting from 7563 * the bottom of the task. If all activities are finishing - then this method will return 7564 * {@code true} if the activity is at the bottom. 7565 * 7566 * NOTE: This is different from 'effective root' - an activity that defines the task identity. 7567 */ isRootOfTask()7568 boolean isRootOfTask() { 7569 if (task == null) { 7570 return false; 7571 } 7572 final ActivityRecord rootActivity = task.getRootActivity(true); 7573 return this == rootActivity; 7574 } 7575 setTaskOverlay(boolean taskOverlay)7576 void setTaskOverlay(boolean taskOverlay) { 7577 mTaskOverlay = taskOverlay; 7578 setAlwaysOnTop(mTaskOverlay); 7579 } 7580 isTaskOverlay()7581 boolean isTaskOverlay() { 7582 return mTaskOverlay; 7583 } 7584 7585 @Override showToCurrentUser()7586 boolean showToCurrentUser() { 7587 return mShowForAllUsers || mWmService.isCurrentProfile(mUserId); 7588 } 7589 7590 @Override toString()7591 public String toString() { 7592 if (stringName != null) { 7593 return stringName + " t" + (task == null ? INVALID_TASK_ID : task.mTaskId) + 7594 (finishing ? " f}" : "") + (mIsExiting ? " isExiting" : "") + "}"; 7595 } 7596 StringBuilder sb = new StringBuilder(128); 7597 sb.append("ActivityRecord{"); 7598 sb.append(Integer.toHexString(System.identityHashCode(this))); 7599 sb.append(" u"); 7600 sb.append(mUserId); 7601 sb.append(' '); 7602 sb.append(intent.getComponent().flattenToShortString()); 7603 stringName = sb.toString(); 7604 return stringName; 7605 } 7606 7607 /** 7608 * Write all fields to an {@code ActivityRecordProto}. This assumes the 7609 * {@code ActivityRecordProto} is the outer-most proto data. 7610 */ dumpDebug(ProtoOutputStream proto, @WindowTraceLogLevel int logLevel)7611 void dumpDebug(ProtoOutputStream proto, @WindowTraceLogLevel int logLevel) { 7612 writeNameToProto(proto, NAME); 7613 super.dumpDebug(proto, WINDOW_TOKEN, logLevel); 7614 proto.write(LAST_SURFACE_SHOWING, mLastSurfaceShowing); 7615 proto.write(IS_WAITING_FOR_TRANSITION_START, isWaitingForTransitionStart()); 7616 proto.write(IS_ANIMATING, isAnimating(PARENTS)); 7617 if (mThumbnail != null){ 7618 mThumbnail.dumpDebug(proto, THUMBNAIL); 7619 } 7620 proto.write(FILLS_PARENT, fillsParent()); 7621 proto.write(APP_STOPPED, mAppStopped); 7622 proto.write(TRANSLUCENT, !occludesParent()); 7623 proto.write(VISIBLE, mVisible); 7624 proto.write(VISIBLE_REQUESTED, mVisibleRequested); 7625 proto.write(CLIENT_VISIBLE, mClientVisible); 7626 proto.write(DEFER_HIDING_CLIENT, mDeferHidingClient); 7627 proto.write(REPORTED_DRAWN, reportedDrawn); 7628 proto.write(REPORTED_VISIBLE, reportedVisible); 7629 proto.write(NUM_INTERESTING_WINDOWS, mNumInterestingWindows); 7630 proto.write(NUM_DRAWN_WINDOWS, mNumDrawnWindows); 7631 proto.write(ALL_DRAWN, allDrawn); 7632 proto.write(LAST_ALL_DRAWN, mLastAllDrawn); 7633 if (startingWindow != null) { 7634 startingWindow.writeIdentifierToProto(proto, STARTING_WINDOW); 7635 } 7636 proto.write(STARTING_DISPLAYED, startingDisplayed); 7637 proto.write(STARTING_MOVED, startingMoved); 7638 proto.write(VISIBLE_SET_FROM_TRANSFERRED_STARTING_WINDOW, 7639 mVisibleSetFromTransferredStartingWindow); 7640 for (Rect bounds : mFrozenBounds) { 7641 bounds.dumpDebug(proto, FROZEN_BOUNDS); 7642 } 7643 7644 writeIdentifierToProto(proto, IDENTIFIER); 7645 proto.write(STATE, mState.toString()); 7646 proto.write(FRONT_OF_TASK, isRootOfTask()); 7647 if (hasProcess()) { 7648 proto.write(PROC_ID, app.getPid()); 7649 } 7650 } 7651 7652 @Override getProtoFieldId()7653 long getProtoFieldId() { 7654 return ACTIVITY; 7655 } 7656 7657 @Override dumpDebug(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel)7658 public void dumpDebug(ProtoOutputStream proto, long fieldId, 7659 @WindowTraceLogLevel int logLevel) { 7660 // Critical log level logs only visible elements to mitigate performance overheard 7661 if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) { 7662 return; 7663 } 7664 7665 final long token = proto.start(fieldId); 7666 dumpDebug(proto, logLevel); 7667 proto.end(token); 7668 } 7669 writeNameToProto(ProtoOutputStream proto, long fieldId)7670 void writeNameToProto(ProtoOutputStream proto, long fieldId) { 7671 if (appToken != null) { 7672 proto.write(fieldId, appToken.getName()); 7673 } 7674 } 7675 7676 @Override writeIdentifierToProto(ProtoOutputStream proto, long fieldId)7677 void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) { 7678 final long token = proto.start(fieldId); 7679 proto.write(HASH_CODE, System.identityHashCode(this)); 7680 proto.write(USER_ID, mUserId); 7681 proto.write(TITLE, intent.getComponent().flattenToShortString()); 7682 proto.end(token); 7683 } 7684 7685 /** 7686 * The precomputed insets of the display in each rotation. This is used to make the size 7687 * compatibility mode activity compute the configuration without relying on its current display. 7688 * This currently only supports fullscreen and freeform windowing mode. 7689 */ 7690 static class CompatDisplayInsets { 7691 private final int mWidth; 7692 private final int mHeight; 7693 final boolean mIsFloating; 7694 7695 /** 7696 * The nonDecorInsets for each rotation. Includes the navigation bar and cutout insets. It 7697 * is used to compute the appBounds. 7698 */ 7699 final Rect[] mNonDecorInsets = new Rect[4]; 7700 /** 7701 * The stableInsets for each rotation. Includes the status bar inset and the 7702 * nonDecorInsets. It is used to compute {@link Configuration#screenWidthDp} and 7703 * {@link Configuration#screenHeightDp}. 7704 */ 7705 final Rect[] mStableInsets = new Rect[4]; 7706 7707 /** Constructs the environment to simulate the bounds behavior of the given container. */ CompatDisplayInsets(DisplayContent display, WindowContainer container)7708 CompatDisplayInsets(DisplayContent display, WindowContainer container) { 7709 mIsFloating = container.getWindowConfiguration().tasksAreFloating(); 7710 if (mIsFloating) { 7711 final Rect containerBounds = container.getWindowConfiguration().getBounds(); 7712 mWidth = containerBounds.width(); 7713 mHeight = containerBounds.height(); 7714 // For apps in freeform, the task bounds are the parent bounds from the app's 7715 // perspective. No insets because within a window. 7716 final Rect emptyRect = new Rect(); 7717 for (int rotation = 0; rotation < 4; rotation++) { 7718 mNonDecorInsets[rotation] = emptyRect; 7719 mStableInsets[rotation] = emptyRect; 7720 } 7721 return; 7722 } 7723 7724 // If the activity is not floating, assume it fills the display. 7725 mWidth = display.mBaseDisplayWidth; 7726 mHeight = display.mBaseDisplayHeight; 7727 final DisplayPolicy policy = display.getDisplayPolicy(); 7728 for (int rotation = 0; rotation < 4; rotation++) { 7729 mNonDecorInsets[rotation] = new Rect(); 7730 mStableInsets[rotation] = new Rect(); 7731 final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270); 7732 final int dw = rotated ? mHeight : mWidth; 7733 final int dh = rotated ? mWidth : mHeight; 7734 final DisplayCutout cutout = display.calculateDisplayCutoutForRotation(rotation) 7735 .getDisplayCutout(); 7736 policy.getNonDecorInsetsLw(rotation, dw, dh, cutout, mNonDecorInsets[rotation]); 7737 mStableInsets[rotation].set(mNonDecorInsets[rotation]); 7738 policy.convertNonDecorInsetsToStableInsets(mStableInsets[rotation], rotation); 7739 } 7740 } 7741 getBoundsByRotation(Rect outBounds, int rotation)7742 void getBoundsByRotation(Rect outBounds, int rotation) { 7743 final boolean rotated = (rotation == ROTATION_90 || rotation == ROTATION_270); 7744 final int dw = rotated ? mHeight : mWidth; 7745 final int dh = rotated ? mWidth : mHeight; 7746 outBounds.set(0, 0, dw, dh); 7747 } 7748 getFrameByOrientation(Rect outBounds, int orientation)7749 void getFrameByOrientation(Rect outBounds, int orientation) { 7750 final int longSide = Math.max(mWidth, mHeight); 7751 final int shortSide = Math.min(mWidth, mHeight); 7752 final boolean isLandscape = orientation == ORIENTATION_LANDSCAPE; 7753 outBounds.set(0, 0, isLandscape ? longSide : shortSide, 7754 isLandscape ? shortSide : longSide); 7755 } 7756 7757 /** Gets the horizontal centered container bounds for size compatibility mode. */ getContainerBounds(Rect outAppBounds, Rect outBounds, int rotation, int orientation, boolean orientationRequested, boolean canChangeOrientation)7758 void getContainerBounds(Rect outAppBounds, Rect outBounds, int rotation, int orientation, 7759 boolean orientationRequested, boolean canChangeOrientation) { 7760 if (mIsFloating) { 7761 getFrameByOrientation(outBounds, orientation); 7762 outAppBounds.set(outBounds); 7763 return; 7764 } 7765 7766 if (canChangeOrientation) { 7767 getBoundsByRotation(outBounds, rotation); 7768 if (orientationRequested) { 7769 getFrameByOrientation(outAppBounds, orientation); 7770 } else { 7771 outAppBounds.set(outBounds); 7772 } 7773 } else { 7774 if (orientationRequested) { 7775 getFrameByOrientation(outBounds, orientation); 7776 if ((outBounds.width() > outBounds.height()) != (mWidth > mHeight)) { 7777 // The orientation is mismatched but the display cannot rotate. The bounds 7778 // will fit to the short side of display. 7779 if (orientation == ORIENTATION_LANDSCAPE) { 7780 outBounds.bottom = (int) ((float) mWidth * mWidth / mHeight); 7781 outBounds.right = mWidth; 7782 } else { 7783 outBounds.bottom = mHeight; 7784 outBounds.right = (int) ((float) mHeight * mHeight / mWidth); 7785 } 7786 outBounds.offset( 7787 getHorizontalCenterOffset(mWidth, outBounds.width()), 0 /* dy */); 7788 } 7789 } else { 7790 outBounds.set(0, 0, mWidth, mHeight); 7791 } 7792 outAppBounds.set(outBounds); 7793 } 7794 7795 if (rotation != ROTATION_UNDEFINED) { 7796 // Ensure the app bounds won't overlap with insets. 7797 Task.intersectWithInsetsIfFits(outAppBounds, outBounds, mNonDecorInsets[rotation]); 7798 } 7799 } 7800 } 7801 7802 private static class AppSaturationInfo { 7803 float[] mMatrix = new float[9]; 7804 float[] mTranslation = new float[3]; 7805 setSaturation(@ize9) float[] matrix, @Size(3) float[] translation)7806 void setSaturation(@Size(9) float[] matrix, @Size(3) float[] translation) { 7807 System.arraycopy(matrix, 0, mMatrix, 0, mMatrix.length); 7808 System.arraycopy(translation, 0, mTranslation, 0, mTranslation.length); 7809 } 7810 } 7811 7812 @Override createRemoteAnimationTarget( RemoteAnimationController.RemoteAnimationRecord record)7813 RemoteAnimationTarget createRemoteAnimationTarget( 7814 RemoteAnimationController.RemoteAnimationRecord record) { 7815 final WindowState mainWindow = findMainWindow(); 7816 if (task == null || mainWindow == null) { 7817 return null; 7818 } 7819 final Rect insets = new Rect(); 7820 mainWindow.getContentInsets(insets); 7821 InsetUtils.addInsets(insets, getLetterboxInsets()); 7822 return new RemoteAnimationTarget(task.mTaskId, record.getMode(), 7823 record.mAdapter.mCapturedLeash, !fillsParent(), 7824 mainWindow.mWinAnimator.mLastClipRect, insets, 7825 getPrefixOrderIndex(), record.mAdapter.mPosition, record.mAdapter.mLocalBounds, 7826 record.mAdapter.mStackBounds, task.getWindowConfiguration(), 7827 false /*isNotInRecents*/, 7828 record.mThumbnailAdapter != null ? record.mThumbnailAdapter.mCapturedLeash : null, 7829 record.mStartBounds); 7830 } 7831 7832 @Override canCreateRemoteAnimationTarget()7833 boolean canCreateRemoteAnimationTarget() { 7834 return true; 7835 } 7836 7837 @Override getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets, Rect outSurfaceInsets)7838 void getAnimationFrames(Rect outFrame, Rect outInsets, Rect outStableInsets, 7839 Rect outSurfaceInsets) { 7840 final WindowState win = findMainWindow(); 7841 if (win == null) { 7842 return; 7843 } 7844 win.getAnimationFrames(outFrame, outInsets, outStableInsets, outSurfaceInsets); 7845 } 7846 setPictureInPictureParams(PictureInPictureParams p)7847 void setPictureInPictureParams(PictureInPictureParams p) { 7848 pictureInPictureArgs.copyOnlySet(p); 7849 getTask().getRootTask().onPictureInPictureParamsChanged(); 7850 } 7851 } 7852