TaskRecord.java revision 3ee3b9d17b2aec84e791f3efa6b9453cab0d9c9b
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 17package com.android.server.am; 18 19import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; 20import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; 21import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; 22import static android.app.ActivityManager.StackId.HOME_STACK_ID; 23import static android.app.ActivityManager.StackId.INVALID_STACK_ID; 24import static android.app.ActivityManager.StackId.PINNED_STACK_ID; 25import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; 26import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS; 27import static android.content.pm.ActivityInfo.FLAG_RESIZEABLE; 28import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS; 29import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT; 30import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED; 31import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER; 32import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRIVILEGED; 33import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ADD_REMOVE; 34import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK; 35import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS; 36import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS; 37import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_ADD_REMOVE; 38import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK; 39import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS; 40import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS; 41import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; 42import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; 43import static com.android.server.am.ActivityManagerService.LOCK_SCREEN_SHOWN; 44import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE; 45import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE; 46import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE; 47 48import android.app.Activity; 49import android.app.ActivityManager; 50import android.app.ActivityManager.StackId; 51import android.app.ActivityManager.TaskDescription; 52import android.app.ActivityManager.TaskThumbnail; 53import android.app.ActivityManager.TaskThumbnailInfo; 54import android.app.ActivityOptions; 55import android.app.AppGlobals; 56import android.content.ComponentName; 57import android.content.Intent; 58import android.content.pm.ActivityInfo; 59import android.content.pm.ApplicationInfo; 60import android.content.pm.IPackageManager; 61import android.content.pm.PackageManager; 62import android.content.res.Configuration; 63import android.graphics.Bitmap; 64import android.graphics.Point; 65import android.graphics.Rect; 66import android.os.Debug; 67import android.os.ParcelFileDescriptor; 68import android.os.RemoteException; 69import android.os.UserHandle; 70import android.service.voice.IVoiceInteractionSession; 71import android.util.DisplayMetrics; 72import android.util.Slog; 73 74import com.android.internal.app.IVoiceInteractor; 75import com.android.internal.util.XmlUtils; 76 77import org.xmlpull.v1.XmlPullParser; 78import org.xmlpull.v1.XmlPullParserException; 79import org.xmlpull.v1.XmlSerializer; 80 81import java.io.File; 82import java.io.IOException; 83import java.io.PrintWriter; 84import java.util.ArrayList; 85import java.util.Objects; 86 87final class TaskRecord { 88 private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM; 89 private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE; 90 private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS; 91 private static final String TAG_LOCKTASK = TAG + POSTFIX_LOCKTASK; 92 private static final String TAG_TASKS = TAG + POSTFIX_TASKS; 93 94 static final String ATTR_TASKID = "task_id"; 95 private static final String TAG_INTENT = "intent"; 96 private static final String TAG_AFFINITYINTENT = "affinity_intent"; 97 static final String ATTR_REALACTIVITY = "real_activity"; 98 private static final String ATTR_ORIGACTIVITY = "orig_activity"; 99 private static final String TAG_ACTIVITY = "activity"; 100 private static final String ATTR_AFFINITY = "affinity"; 101 private static final String ATTR_ROOT_AFFINITY = "root_affinity"; 102 private static final String ATTR_ROOTHASRESET = "root_has_reset"; 103 private static final String ATTR_AUTOREMOVERECENTS = "auto_remove_recents"; 104 private static final String ATTR_ASKEDCOMPATMODE = "asked_compat_mode"; 105 private static final String ATTR_USERID = "user_id"; 106 private static final String ATTR_EFFECTIVE_UID = "effective_uid"; 107 private static final String ATTR_TASKTYPE = "task_type"; 108 private static final String ATTR_FIRSTACTIVETIME = "first_active_time"; 109 private static final String ATTR_LASTACTIVETIME = "last_active_time"; 110 private static final String ATTR_LASTDESCRIPTION = "last_description"; 111 private static final String ATTR_LASTTIMEMOVED = "last_time_moved"; 112 private static final String ATTR_NEVERRELINQUISH = "never_relinquish_identity"; 113 static final String ATTR_TASK_AFFILIATION = "task_affiliation"; 114 private static final String ATTR_PREV_AFFILIATION = "prev_affiliation"; 115 private static final String ATTR_NEXT_AFFILIATION = "next_affiliation"; 116 private static final String ATTR_TASK_AFFILIATION_COLOR = "task_affiliation_color"; 117 private static final String ATTR_CALLING_UID = "calling_uid"; 118 private static final String ATTR_CALLING_PACKAGE = "calling_package"; 119 private static final String ATTR_RESIZEABLE = "resizeable"; 120 private static final String ATTR_PRIVILEGED = "privileged"; 121 private static final String ATTR_NON_FULLSCREEN_BOUNDS = "non_fullscreen_bounds"; 122 123 private static final String TASK_THUMBNAIL_SUFFIX = "_task_thumbnail"; 124 125 static final boolean IGNORE_RETURN_TO_RECENTS = true; 126 127 static final int INVALID_TASK_ID = -1; 128 129 final int taskId; // Unique identifier for this task. 130 String affinity; // The affinity name for this task, or null; may change identity. 131 String rootAffinity; // Initial base affinity, or null; does not change from initial root. 132 final IVoiceInteractionSession voiceSession; // Voice interaction session driving task 133 final IVoiceInteractor voiceInteractor; // Associated interactor to provide to app 134 Intent intent; // The original intent that started the task. 135 Intent affinityIntent; // Intent of affinity-moved activity that started this task. 136 int effectiveUid; // The current effective uid of the identity of this task. 137 ComponentName origActivity; // The non-alias activity component of the intent. 138 ComponentName realActivity; // The actual activity component that started the task. 139 long firstActiveTime; // First time this task was active. 140 long lastActiveTime; // Last time this task was active, including sleep. 141 boolean inRecents; // Actually in the recents list? 142 boolean isAvailable; // Is the activity available to be launched? 143 boolean rootWasReset; // True if the intent at the root of the task had 144 // the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag. 145 boolean autoRemoveRecents; // If true, we should automatically remove the task from 146 // recents when activity finishes 147 boolean askedCompatMode;// Have asked the user about compat mode for this task. 148 boolean hasBeenVisible; // Set if any activities in the task have been visible to the user. 149 150 String stringName; // caching of toString() result. 151 int userId; // user for which this task was created 152 153 int numFullscreen; // Number of fullscreen activities. 154 155 boolean mResizeable; // Activities in the task resizeable. Based on the resizable setting of 156 // the root activity. 157 int mLockTaskMode; // Which tasklock mode to launch this task in. One of 158 // ActivityManager.LOCK_TASK_LAUNCH_MODE_* 159 private boolean mPrivileged; // The root activity application of this task holds 160 // privileged permissions. 161 162 /** Can't be put in lockTask mode. */ 163 final static int LOCK_TASK_AUTH_DONT_LOCK = 0; 164 /** Can enter app pinning with user approval. Can never start over existing lockTask task. */ 165 final static int LOCK_TASK_AUTH_PINNABLE = 1; 166 /** Starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing lockTask task. */ 167 final static int LOCK_TASK_AUTH_LAUNCHABLE = 2; 168 /** Can enter lockTask without user approval. Can start over existing lockTask task. */ 169 final static int LOCK_TASK_AUTH_WHITELISTED = 3; 170 /** Priv-app that starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing 171 * lockTask task. */ 172 final static int LOCK_TASK_AUTH_LAUNCHABLE_PRIV = 4; 173 int mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE; 174 175 int mLockTaskUid = -1; // The uid of the application that called startLockTask(). 176 177 // This represents the last resolved activity values for this task 178 // NOTE: This value needs to be persisted with each task 179 TaskDescription lastTaskDescription = new TaskDescription(); 180 181 /** List of all activities in the task arranged in history order */ 182 final ArrayList<ActivityRecord> mActivities; 183 184 /** Current stack */ 185 ActivityStack stack; 186 187 /** Takes on same set of values as ActivityRecord.mActivityType */ 188 int taskType; 189 190 /** Takes on same value as first root activity */ 191 boolean isPersistable = false; 192 int maxRecents; 193 194 /** Only used for persistable tasks, otherwise 0. The last time this task was moved. Used for 195 * determining the order when restoring. Sign indicates whether last task movement was to front 196 * (positive) or back (negative). Absolute value indicates time. */ 197 long mLastTimeMoved = System.currentTimeMillis(); 198 199 /** Indication of what to run next when task exits. Use ActivityRecord types. 200 * ActivityRecord.APPLICATION_ACTIVITY_TYPE indicates to resume the task below this one in the 201 * task stack. */ 202 private int mTaskToReturnTo = APPLICATION_ACTIVITY_TYPE; 203 204 /** If original intent did not allow relinquishing task identity, save that information */ 205 boolean mNeverRelinquishIdentity = true; 206 207 // Used in the unique case where we are clearing the task in order to reuse it. In that case we 208 // do not want to delete the stack when the task goes empty. 209 boolean mReuseTask = false; 210 211 private Bitmap mLastThumbnail; // Last thumbnail captured for this item. 212 private final File mLastThumbnailFile; // File containing last thumbnail. 213 private final String mFilename; 214 private TaskThumbnailInfo mLastThumbnailInfo; 215 CharSequence lastDescription; // Last description captured for this item. 216 217 int mAffiliatedTaskId; // taskId of parent affiliation or self if no parent. 218 int mAffiliatedTaskColor; // color of the parent task affiliation. 219 TaskRecord mPrevAffiliate; // previous task in affiliated chain. 220 int mPrevAffiliateTaskId = INVALID_TASK_ID; // previous id for persistence. 221 TaskRecord mNextAffiliate; // next task in affiliated chain. 222 int mNextAffiliateTaskId = INVALID_TASK_ID; // next id for persistence. 223 224 // For relaunching the task from recents as though it was launched by the original launcher. 225 int mCallingUid; 226 String mCallingPackage; 227 228 final ActivityManagerService mService; 229 230 // Whether or not this task covers the entire screen; by default tasks are fullscreen. 231 boolean mFullscreen = true; 232 233 // Bounds of the Task. null for fullscreen tasks. 234 Rect mBounds = null; 235 // Last non-fullscreen bounds the task was launched in or resized to. 236 // The information is persisted and used to determine the appropriate stack to launch the 237 // task into on restore. 238 Rect mLastNonFullscreenBounds = null; 239 // Minimal size for width/height of this task when it's resizeable. -1 means it should use the 240 // default minimal size. 241 final int mMinimalSize; 242 243 // Ranking (from top) of this task among all visible tasks. (-1 means it's not visible) 244 // This number will be assigned when we evaluate OOM scores for all visible tasks. 245 int mLayerRank = -1; 246 247 Configuration mOverrideConfig = Configuration.EMPTY; 248 249 TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent, 250 IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) { 251 mService = service; 252 mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX + 253 TaskPersister.IMAGE_EXTENSION; 254 userId = UserHandle.getUserId(info.applicationInfo.uid); 255 mLastThumbnailFile = new File(TaskPersister.getUserImagesDir(userId), mFilename); 256 mLastThumbnailInfo = new TaskThumbnailInfo(); 257 taskId = _taskId; 258 mAffiliatedTaskId = _taskId; 259 voiceSession = _voiceSession; 260 voiceInteractor = _voiceInteractor; 261 isAvailable = true; 262 mActivities = new ArrayList<>(); 263 mCallingUid = info.applicationInfo.uid; 264 mCallingPackage = info.packageName; 265 setIntent(_intent, info); 266 mMinimalSize = info != null && info.layout != null ? info.layout.minimalSize : -1; 267 } 268 269 TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent, 270 TaskDescription _taskDescription, TaskThumbnailInfo thumbnailInfo) { 271 mService = service; 272 mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX + 273 TaskPersister.IMAGE_EXTENSION; 274 userId = UserHandle.getUserId(info.applicationInfo.uid); 275 mLastThumbnailFile = new File(TaskPersister.getUserImagesDir(userId), mFilename); 276 mLastThumbnailInfo = thumbnailInfo; 277 taskId = _taskId; 278 mAffiliatedTaskId = _taskId; 279 voiceSession = null; 280 voiceInteractor = null; 281 isAvailable = true; 282 mActivities = new ArrayList<>(); 283 mCallingUid = info.applicationInfo.uid; 284 mCallingPackage = info.packageName; 285 setIntent(_intent, info); 286 287 taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE; 288 isPersistable = true; 289 // Clamp to [1, max]. 290 maxRecents = Math.min(Math.max(info.maxRecents, 1), 291 ActivityManager.getMaxAppRecentsLimitStatic()); 292 293 taskType = APPLICATION_ACTIVITY_TYPE; 294 mTaskToReturnTo = HOME_ACTIVITY_TYPE; 295 lastTaskDescription = _taskDescription; 296 mMinimalSize = info != null && info.layout != null ? info.layout.minimalSize : -1; 297 } 298 299 private TaskRecord(ActivityManagerService service, int _taskId, Intent _intent, 300 Intent _affinityIntent, String _affinity, String _rootAffinity, 301 ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset, 302 boolean _autoRemoveRecents, boolean _askedCompatMode, int _taskType, int _userId, 303 int _effectiveUid, String _lastDescription, ArrayList<ActivityRecord> activities, 304 long _firstActiveTime, long _lastActiveTime, long lastTimeMoved, 305 boolean neverRelinquishIdentity, TaskDescription _lastTaskDescription, 306 TaskThumbnailInfo lastThumbnailInfo, int taskAffiliation, int prevTaskId, 307 int nextTaskId, int taskAffiliationColor, int callingUid, String callingPackage, 308 boolean resizeable, boolean privileged) { 309 mService = service; 310 mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX + 311 TaskPersister.IMAGE_EXTENSION; 312 mLastThumbnailFile = new File(TaskPersister.getUserImagesDir(_userId), mFilename); 313 mLastThumbnailInfo = lastThumbnailInfo; 314 taskId = _taskId; 315 intent = _intent; 316 affinityIntent = _affinityIntent; 317 affinity = _affinity; 318 rootAffinity = _rootAffinity; 319 voiceSession = null; 320 voiceInteractor = null; 321 realActivity = _realActivity; 322 origActivity = _origActivity; 323 rootWasReset = _rootWasReset; 324 isAvailable = true; 325 autoRemoveRecents = _autoRemoveRecents; 326 askedCompatMode = _askedCompatMode; 327 taskType = _taskType; 328 mTaskToReturnTo = HOME_ACTIVITY_TYPE; 329 userId = _userId; 330 effectiveUid = _effectiveUid; 331 firstActiveTime = _firstActiveTime; 332 lastActiveTime = _lastActiveTime; 333 lastDescription = _lastDescription; 334 mActivities = activities; 335 mLastTimeMoved = lastTimeMoved; 336 mNeverRelinquishIdentity = neverRelinquishIdentity; 337 lastTaskDescription = _lastTaskDescription; 338 mAffiliatedTaskId = taskAffiliation; 339 mAffiliatedTaskColor = taskAffiliationColor; 340 mPrevAffiliateTaskId = prevTaskId; 341 mNextAffiliateTaskId = nextTaskId; 342 mCallingUid = callingUid; 343 mCallingPackage = callingPackage; 344 mResizeable = resizeable || mService.mForceResizableActivities; 345 mPrivileged = privileged; 346 ActivityInfo info = (mActivities.size() > 0) ? mActivities.get(0).info : null; 347 mMinimalSize = info != null && info.layout != null ? info.layout.minimalSize : -1; 348 } 349 350 void touchActiveTime() { 351 lastActiveTime = System.currentTimeMillis(); 352 if (firstActiveTime == 0) { 353 firstActiveTime = lastActiveTime; 354 } 355 } 356 357 long getInactiveDuration() { 358 return System.currentTimeMillis() - lastActiveTime; 359 } 360 361 /** Sets the original intent, and the calling uid and package. */ 362 void setIntent(ActivityRecord r) { 363 mCallingUid = r.launchedFromUid; 364 mCallingPackage = r.launchedFromPackage; 365 setIntent(r.intent, r.info); 366 } 367 368 /** Sets the original intent, _without_ updating the calling uid or package. */ 369 private void setIntent(Intent _intent, ActivityInfo info) { 370 if (intent == null) { 371 mNeverRelinquishIdentity = 372 (info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0; 373 } else if (mNeverRelinquishIdentity) { 374 return; 375 } 376 377 affinity = info.taskAffinity; 378 if (intent == null) { 379 // If this task already has an intent associated with it, don't set the root 380 // affinity -- we don't want it changing after initially set, but the initially 381 // set value may be null. 382 rootAffinity = affinity; 383 } 384 effectiveUid = info.applicationInfo.uid; 385 stringName = null; 386 387 if (info.targetActivity == null) { 388 if (_intent != null) { 389 // If this Intent has a selector, we want to clear it for the 390 // recent task since it is not relevant if the user later wants 391 // to re-launch the app. 392 if (_intent.getSelector() != null || _intent.getSourceBounds() != null) { 393 _intent = new Intent(_intent); 394 _intent.setSelector(null); 395 _intent.setSourceBounds(null); 396 } 397 } 398 if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Setting Intent of " + this + " to " + _intent); 399 intent = _intent; 400 realActivity = _intent != null ? _intent.getComponent() : null; 401 origActivity = null; 402 } else { 403 ComponentName targetComponent = new ComponentName( 404 info.packageName, info.targetActivity); 405 if (_intent != null) { 406 Intent targetIntent = new Intent(_intent); 407 targetIntent.setComponent(targetComponent); 408 targetIntent.setSelector(null); 409 targetIntent.setSourceBounds(null); 410 if (DEBUG_TASKS) Slog.v(TAG_TASKS, 411 "Setting Intent of " + this + " to target " + targetIntent); 412 intent = targetIntent; 413 realActivity = targetComponent; 414 origActivity = _intent.getComponent(); 415 } else { 416 intent = null; 417 realActivity = targetComponent; 418 origActivity = new ComponentName(info.packageName, info.name); 419 } 420 } 421 422 final int intentFlags = intent == null ? 0 : intent.getFlags(); 423 if ((intentFlags & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) { 424 // Once we are set to an Intent with this flag, we count this 425 // task as having a true root activity. 426 rootWasReset = true; 427 } 428 429 userId = UserHandle.getUserId(info.applicationInfo.uid); 430 if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) { 431 // If the activity itself has requested auto-remove, then just always do it. 432 autoRemoveRecents = true; 433 } else if ((intentFlags & (FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS)) 434 == FLAG_ACTIVITY_NEW_DOCUMENT) { 435 // If the caller has not asked for the document to be retained, then we may 436 // want to turn on auto-remove, depending on whether the target has set its 437 // own document launch mode. 438 if (info.documentLaunchMode != ActivityInfo.DOCUMENT_LAUNCH_NONE) { 439 autoRemoveRecents = false; 440 } else { 441 autoRemoveRecents = true; 442 } 443 } else { 444 autoRemoveRecents = false; 445 } 446 mResizeable = (info.flags & FLAG_RESIZEABLE) != 0 || mService.mForceResizableActivities; 447 mLockTaskMode = info.lockTaskLaunchMode; 448 mPrivileged = (info.applicationInfo.privateFlags & PRIVATE_FLAG_PRIVILEGED) != 0; 449 setLockTaskAuth(); 450 } 451 452 void setTaskToReturnTo(int taskToReturnTo) { 453 mTaskToReturnTo = (IGNORE_RETURN_TO_RECENTS && taskToReturnTo == RECENTS_ACTIVITY_TYPE) 454 ? HOME_ACTIVITY_TYPE : taskToReturnTo; 455 } 456 457 int getTaskToReturnTo() { 458 return mTaskToReturnTo; 459 } 460 461 void setPrevAffiliate(TaskRecord prevAffiliate) { 462 mPrevAffiliate = prevAffiliate; 463 mPrevAffiliateTaskId = prevAffiliate == null ? INVALID_TASK_ID : prevAffiliate.taskId; 464 } 465 466 void setNextAffiliate(TaskRecord nextAffiliate) { 467 mNextAffiliate = nextAffiliate; 468 mNextAffiliateTaskId = nextAffiliate == null ? INVALID_TASK_ID : nextAffiliate.taskId; 469 } 470 471 // Close up recents linked list. 472 void closeRecentsChain() { 473 if (mPrevAffiliate != null) { 474 mPrevAffiliate.setNextAffiliate(mNextAffiliate); 475 } 476 if (mNextAffiliate != null) { 477 mNextAffiliate.setPrevAffiliate(mPrevAffiliate); 478 } 479 setPrevAffiliate(null); 480 setNextAffiliate(null); 481 } 482 483 void removedFromRecents() { 484 disposeThumbnail(); 485 closeRecentsChain(); 486 if (inRecents) { 487 inRecents = false; 488 mService.notifyTaskPersisterLocked(this, false); 489 } 490 } 491 492 void setTaskToAffiliateWith(TaskRecord taskToAffiliateWith) { 493 closeRecentsChain(); 494 mAffiliatedTaskId = taskToAffiliateWith.mAffiliatedTaskId; 495 mAffiliatedTaskColor = taskToAffiliateWith.mAffiliatedTaskColor; 496 // Find the end 497 while (taskToAffiliateWith.mNextAffiliate != null) { 498 final TaskRecord nextRecents = taskToAffiliateWith.mNextAffiliate; 499 if (nextRecents.mAffiliatedTaskId != mAffiliatedTaskId) { 500 Slog.e(TAG, "setTaskToAffiliateWith: nextRecents=" + nextRecents + " affilTaskId=" 501 + nextRecents.mAffiliatedTaskId + " should be " + mAffiliatedTaskId); 502 if (nextRecents.mPrevAffiliate == taskToAffiliateWith) { 503 nextRecents.setPrevAffiliate(null); 504 } 505 taskToAffiliateWith.setNextAffiliate(null); 506 break; 507 } 508 taskToAffiliateWith = nextRecents; 509 } 510 taskToAffiliateWith.setNextAffiliate(this); 511 setPrevAffiliate(taskToAffiliateWith); 512 setNextAffiliate(null); 513 } 514 515 /** 516 * Sets the last thumbnail with the current task bounds and the system orientation. 517 * @return whether the thumbnail was set 518 */ 519 boolean setLastThumbnailLocked(Bitmap thumbnail) { 520 final Configuration serviceConfig = mService.mConfiguration; 521 int taskWidth = 0; 522 int taskHeight = 0; 523 if (mBounds != null) { 524 // Non-fullscreen tasks 525 taskWidth = mBounds.width(); 526 taskHeight = mBounds.height(); 527 } else if (stack != null) { 528 // Fullscreen tasks 529 final Point displaySize = new Point(); 530 stack.getDisplaySize(displaySize); 531 taskWidth = displaySize.x; 532 taskHeight = displaySize.y; 533 } else { 534 Slog.e(TAG, "setLastThumbnailLocked() called on Task without stack"); 535 } 536 return setLastThumbnailLocked(thumbnail, taskWidth, taskHeight, serviceConfig.orientation); 537 } 538 539 /** 540 * Sets the last thumbnail with the current task bounds. 541 * @return whether the thumbnail was set 542 */ 543 private boolean setLastThumbnailLocked(Bitmap thumbnail, int taskWidth, int taskHeight, 544 int screenOrientation) { 545 if (mLastThumbnail != thumbnail) { 546 mLastThumbnail = thumbnail; 547 mLastThumbnailInfo.taskWidth = taskWidth; 548 mLastThumbnailInfo.taskHeight = taskHeight; 549 mLastThumbnailInfo.screenOrientation = screenOrientation; 550 if (thumbnail == null) { 551 if (mLastThumbnailFile != null) { 552 mLastThumbnailFile.delete(); 553 } 554 } else { 555 mService.mRecentTasks.saveImage(thumbnail, mLastThumbnailFile.getAbsolutePath()); 556 } 557 return true; 558 } 559 return false; 560 } 561 562 void getLastThumbnail(TaskThumbnail thumbs) { 563 thumbs.mainThumbnail = mLastThumbnail; 564 thumbs.thumbnailInfo = mLastThumbnailInfo; 565 thumbs.thumbnailFileDescriptor = null; 566 if (mLastThumbnail == null) { 567 thumbs.mainThumbnail = mService.mRecentTasks.getImageFromWriteQueue( 568 mLastThumbnailFile.getAbsolutePath()); 569 } 570 // Only load the thumbnail file if we don't have a thumbnail 571 if (thumbs.mainThumbnail == null && mLastThumbnailFile.exists()) { 572 try { 573 thumbs.thumbnailFileDescriptor = ParcelFileDescriptor.open(mLastThumbnailFile, 574 ParcelFileDescriptor.MODE_READ_ONLY); 575 } catch (IOException e) { 576 } 577 } 578 } 579 580 /** 581 * Removes in-memory thumbnail data when the max number of in-memory task thumbnails is reached. 582 */ 583 void freeLastThumbnail() { 584 mLastThumbnail = null; 585 } 586 587 /** 588 * Removes all associated thumbnail data when a task is removed or pruned from recents. 589 */ 590 void disposeThumbnail() { 591 mLastThumbnailInfo.reset(); 592 mLastThumbnail = null; 593 lastDescription = null; 594 } 595 596 /** Returns the intent for the root activity for this task */ 597 Intent getBaseIntent() { 598 return intent != null ? intent : affinityIntent; 599 } 600 601 /** Returns the first non-finishing activity from the root. */ 602 ActivityRecord getRootActivity() { 603 for (int i = 0; i < mActivities.size(); i++) { 604 final ActivityRecord r = mActivities.get(i); 605 if (r.finishing) { 606 continue; 607 } 608 return r; 609 } 610 return null; 611 } 612 613 ActivityRecord getTopActivity() { 614 for (int i = mActivities.size() - 1; i >= 0; --i) { 615 final ActivityRecord r = mActivities.get(i); 616 if (r.finishing) { 617 continue; 618 } 619 return r; 620 } 621 return null; 622 } 623 624 ActivityRecord topRunningActivityLocked() { 625 if (stack != null) { 626 for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) { 627 ActivityRecord r = mActivities.get(activityNdx); 628 if (!r.finishing && stack.okToShowLocked(r)) { 629 return r; 630 } 631 } 632 } 633 return null; 634 } 635 636 void setFrontOfTask() { 637 setFrontOfTask(null); 638 } 639 640 /** Call after activity movement or finish to make sure that frontOfTask is set correctly */ 641 void setFrontOfTask(ActivityRecord newTop) { 642 // If a top candidate is suggested by the caller, go ahead and use it and mark all others 643 // as not front. This is needed in situations where the current front activity in the 644 // task isn't finished yet and we want to set the front to the activity moved to the front 645 // of the task. 646 boolean foundFront = newTop != null ? true : false; 647 648 final int numActivities = mActivities.size(); 649 for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) { 650 final ActivityRecord r = mActivities.get(activityNdx); 651 if (foundFront || r.finishing) { 652 r.frontOfTask = false; 653 } else { 654 r.frontOfTask = true; 655 // Set frontOfTask false for every following activity. 656 foundFront = true; 657 } 658 } 659 if (!foundFront && numActivities > 0) { 660 // All activities of this task are finishing. As we ought to have a frontOfTask 661 // activity, make the bottom activity front. 662 mActivities.get(0).frontOfTask = true; 663 } 664 if (newTop != null) { 665 newTop.frontOfTask = true; 666 } 667 } 668 669 /** 670 * Reorder the history stack so that the passed activity is brought to the front. 671 */ 672 final void moveActivityToFrontLocked(ActivityRecord newTop) { 673 if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE, 674 "Removing and adding activity " + newTop 675 + " to stack at top callers=" + Debug.getCallers(4)); 676 677 mActivities.remove(newTop); 678 mActivities.add(newTop); 679 updateEffectiveIntent(); 680 681 setFrontOfTask(newTop); 682 } 683 684 void addActivityAtBottom(ActivityRecord r) { 685 addActivityAtIndex(0, r); 686 } 687 688 void addActivityToTop(ActivityRecord r) { 689 addActivityAtIndex(mActivities.size(), r); 690 } 691 692 void addActivityAtIndex(int index, ActivityRecord r) { 693 // Remove r first, and if it wasn't already in the list and it's fullscreen, count it. 694 if (!mActivities.remove(r) && r.fullscreen) { 695 // Was not previously in list. 696 numFullscreen++; 697 } 698 // Only set this based on the first activity 699 if (mActivities.isEmpty()) { 700 taskType = r.mActivityType; 701 if (taskType == HOME_ACTIVITY_TYPE && mService.mForceResizableActivities) { 702 mResizeable = r.isResizeable(); 703 } 704 isPersistable = r.isPersistable(); 705 mCallingUid = r.launchedFromUid; 706 mCallingPackage = r.launchedFromPackage; 707 // Clamp to [1, max]. 708 maxRecents = Math.min(Math.max(r.info.maxRecents, 1), 709 ActivityManager.getMaxAppRecentsLimitStatic()); 710 } else { 711 // Otherwise make all added activities match this one. 712 r.mActivityType = taskType; 713 } 714 mActivities.add(index, r); 715 updateEffectiveIntent(); 716 if (r.isPersistable()) { 717 mService.notifyTaskPersisterLocked(this, false); 718 } 719 } 720 721 /** @return true if this was the last activity in the task */ 722 boolean removeActivity(ActivityRecord r) { 723 if (mActivities.remove(r) && r.fullscreen) { 724 // Was previously in list. 725 numFullscreen--; 726 } 727 if (r.isPersistable()) { 728 mService.notifyTaskPersisterLocked(this, false); 729 } 730 if (mActivities.isEmpty()) { 731 return !mReuseTask; 732 } 733 updateEffectiveIntent(); 734 return false; 735 } 736 737 boolean autoRemoveFromRecents() { 738 // We will automatically remove the task either if it has explicitly asked for 739 // this, or it is empty and has never contained an activity that got shown to 740 // the user. 741 return autoRemoveRecents || (mActivities.isEmpty() && !hasBeenVisible); 742 } 743 744 /** 745 * Completely remove all activities associated with an existing 746 * task starting at a specified index. 747 */ 748 final void performClearTaskAtIndexLocked(int activityNdx) { 749 int numActivities = mActivities.size(); 750 for ( ; activityNdx < numActivities; ++activityNdx) { 751 final ActivityRecord r = mActivities.get(activityNdx); 752 if (r.finishing) { 753 continue; 754 } 755 if (stack == null) { 756 // Task was restored from persistent storage. 757 r.takeFromHistory(); 758 mActivities.remove(activityNdx); 759 --activityNdx; 760 --numActivities; 761 } else if (stack.finishActivityLocked( 762 r, Activity.RESULT_CANCELED, null, "clear-task-index", false)) { 763 --activityNdx; 764 --numActivities; 765 } 766 } 767 } 768 769 /** 770 * Completely remove all activities associated with an existing task. 771 */ 772 final void performClearTaskLocked() { 773 mReuseTask = true; 774 performClearTaskAtIndexLocked(0); 775 mReuseTask = false; 776 } 777 778 /** 779 * Perform clear operation as requested by 780 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the 781 * stack to the given task, then look for 782 * an instance of that activity in the stack and, if found, finish all 783 * activities on top of it and return the instance. 784 * 785 * @param newR Description of the new activity being started. 786 * @return Returns the old activity that should be continued to be used, 787 * or null if none was found. 788 */ 789 final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) { 790 int numActivities = mActivities.size(); 791 for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) { 792 ActivityRecord r = mActivities.get(activityNdx); 793 if (r.finishing) { 794 continue; 795 } 796 if (r.realActivity.equals(newR.realActivity)) { 797 // Here it is! Now finish everything in front... 798 final ActivityRecord ret = r; 799 800 for (++activityNdx; activityNdx < numActivities; ++activityNdx) { 801 r = mActivities.get(activityNdx); 802 if (r.finishing) { 803 continue; 804 } 805 ActivityOptions opts = r.takeOptionsLocked(); 806 if (opts != null) { 807 ret.updateOptionsLocked(opts); 808 } 809 if (stack != null && stack.finishActivityLocked( 810 r, Activity.RESULT_CANCELED, null, "clear-task-stack", false)) { 811 --activityNdx; 812 --numActivities; 813 } 814 } 815 816 // Finally, if this is a normal launch mode (that is, not 817 // expecting onNewIntent()), then we will finish the current 818 // instance of the activity so a new fresh one can be started. 819 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE 820 && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) { 821 if (!ret.finishing) { 822 if (stack != null) { 823 stack.finishActivityLocked( 824 ret, Activity.RESULT_CANCELED, null, "clear-task-top", false); 825 } 826 return null; 827 } 828 } 829 830 return ret; 831 } 832 } 833 834 return null; 835 } 836 837 public TaskThumbnail getTaskThumbnailLocked() { 838 if (stack != null) { 839 final ActivityRecord resumedActivity = stack.mResumedActivity; 840 if (resumedActivity != null && resumedActivity.task == this) { 841 final Bitmap thumbnail = stack.screenshotActivitiesLocked(resumedActivity); 842 setLastThumbnailLocked(thumbnail); 843 } 844 } 845 final TaskThumbnail taskThumbnail = new TaskThumbnail(); 846 getLastThumbnail(taskThumbnail); 847 return taskThumbnail; 848 } 849 850 public void removeTaskActivitiesLocked() { 851 // Just remove the entire task. 852 performClearTaskAtIndexLocked(0); 853 } 854 855 String lockTaskAuthToString() { 856 switch (mLockTaskAuth) { 857 case LOCK_TASK_AUTH_DONT_LOCK: return "LOCK_TASK_AUTH_DONT_LOCK"; 858 case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE"; 859 case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE"; 860 case LOCK_TASK_AUTH_WHITELISTED: return "LOCK_TASK_AUTH_WHITELISTED"; 861 case LOCK_TASK_AUTH_LAUNCHABLE_PRIV: return "LOCK_TASK_AUTH_LAUNCHABLE_PRIV"; 862 default: return "unknown=" + mLockTaskAuth; 863 } 864 } 865 866 void setLockTaskAuth() { 867 if (!mPrivileged && 868 (mLockTaskMode == LOCK_TASK_LAUNCH_MODE_ALWAYS || 869 mLockTaskMode == LOCK_TASK_LAUNCH_MODE_NEVER)) { 870 // Non-priv apps are not allowed to use always or never, fall back to default 871 mLockTaskMode = LOCK_TASK_LAUNCH_MODE_DEFAULT; 872 } 873 switch (mLockTaskMode) { 874 case LOCK_TASK_LAUNCH_MODE_DEFAULT: 875 mLockTaskAuth = isLockTaskWhitelistedLocked() ? 876 LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE; 877 break; 878 879 case LOCK_TASK_LAUNCH_MODE_NEVER: 880 mLockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK; 881 break; 882 883 case LOCK_TASK_LAUNCH_MODE_ALWAYS: 884 mLockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV; 885 break; 886 887 case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED: 888 mLockTaskAuth = isLockTaskWhitelistedLocked() ? 889 LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE; 890 break; 891 } 892 if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this + 893 " mLockTaskAuth=" + lockTaskAuthToString()); 894 } 895 896 boolean isLockTaskWhitelistedLocked() { 897 String pkg = (realActivity != null) ? realActivity.getPackageName() : null; 898 if (pkg == null) { 899 return false; 900 } 901 String[] packages = mService.mLockTaskPackages.get(userId); 902 if (packages == null) { 903 return false; 904 } 905 for (int i = packages.length - 1; i >= 0; --i) { 906 if (pkg.equals(packages[i])) { 907 return true; 908 } 909 } 910 return false; 911 } 912 boolean isHomeTask() { 913 return taskType == HOME_ACTIVITY_TYPE; 914 } 915 916 boolean isApplicationTask() { 917 return taskType == APPLICATION_ACTIVITY_TYPE; 918 } 919 920 boolean isOverHomeStack() { 921 return mTaskToReturnTo == HOME_ACTIVITY_TYPE || mTaskToReturnTo == RECENTS_ACTIVITY_TYPE; 922 } 923 924 /** 925 * Find the activity in the history stack within the given task. Returns 926 * the index within the history at which it's found, or < 0 if not found. 927 */ 928 final ActivityRecord findActivityInHistoryLocked(ActivityRecord r) { 929 final ComponentName realActivity = r.realActivity; 930 for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) { 931 ActivityRecord candidate = mActivities.get(activityNdx); 932 if (candidate.finishing) { 933 continue; 934 } 935 if (candidate.realActivity.equals(realActivity)) { 936 return candidate; 937 } 938 } 939 return null; 940 } 941 942 /** Updates the last task description values. */ 943 void updateTaskDescription() { 944 // Traverse upwards looking for any break between main task activities and 945 // utility activities. 946 int activityNdx; 947 final int numActivities = mActivities.size(); 948 final boolean relinquish = numActivities == 0 ? false : 949 (mActivities.get(0).info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) != 0; 950 for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities; 951 ++activityNdx) { 952 final ActivityRecord r = mActivities.get(activityNdx); 953 if (relinquish && (r.info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0) { 954 // This will be the top activity for determining taskDescription. Pre-inc to 955 // overcome initial decrement below. 956 ++activityNdx; 957 break; 958 } 959 if (r.intent != null && 960 (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) { 961 break; 962 } 963 } 964 if (activityNdx > 0) { 965 // Traverse downwards starting below break looking for set label, icon. 966 // Note that if there are activities in the task but none of them set the 967 // recent activity values, then we do not fall back to the last set 968 // values in the TaskRecord. 969 String label = null; 970 String iconFilename = null; 971 int colorPrimary = 0; 972 for (--activityNdx; activityNdx >= 0; --activityNdx) { 973 final ActivityRecord r = mActivities.get(activityNdx); 974 if (r.taskDescription != null) { 975 if (label == null) { 976 label = r.taskDescription.getLabel(); 977 } 978 if (iconFilename == null) { 979 iconFilename = r.taskDescription.getIconFilename(); 980 } 981 if (colorPrimary == 0) { 982 colorPrimary = r.taskDescription.getPrimaryColor(); 983 } 984 } 985 } 986 lastTaskDescription = new TaskDescription(label, colorPrimary, iconFilename); 987 // Update the task affiliation color if we are the parent of the group 988 if (taskId == mAffiliatedTaskId) { 989 mAffiliatedTaskColor = lastTaskDescription.getPrimaryColor(); 990 } 991 } 992 } 993 994 int findEffectiveRootIndex() { 995 int effectiveNdx = 0; 996 final int topActivityNdx = mActivities.size() - 1; 997 for (int activityNdx = 0; activityNdx <= topActivityNdx; ++activityNdx) { 998 final ActivityRecord r = mActivities.get(activityNdx); 999 if (r.finishing) { 1000 continue; 1001 } 1002 effectiveNdx = activityNdx; 1003 if ((r.info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0) { 1004 break; 1005 } 1006 } 1007 return effectiveNdx; 1008 } 1009 1010 void updateEffectiveIntent() { 1011 final int effectiveRootIndex = findEffectiveRootIndex(); 1012 final ActivityRecord r = mActivities.get(effectiveRootIndex); 1013 setIntent(r); 1014 } 1015 1016 void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException { 1017 if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this); 1018 1019 out.attribute(null, ATTR_TASKID, String.valueOf(taskId)); 1020 if (realActivity != null) { 1021 out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString()); 1022 } 1023 if (origActivity != null) { 1024 out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString()); 1025 } 1026 // Write affinity, and root affinity if it is different from affinity. 1027 // We use the special string "@" for a null root affinity, so we can identify 1028 // later whether we were given a root affinity or should just make it the 1029 // same as the affinity. 1030 if (affinity != null) { 1031 out.attribute(null, ATTR_AFFINITY, affinity); 1032 if (!affinity.equals(rootAffinity)) { 1033 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@"); 1034 } 1035 } else if (rootAffinity != null) { 1036 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@"); 1037 } 1038 out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset)); 1039 out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents)); 1040 out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode)); 1041 out.attribute(null, ATTR_USERID, String.valueOf(userId)); 1042 out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid)); 1043 out.attribute(null, ATTR_TASKTYPE, String.valueOf(taskType)); 1044 out.attribute(null, ATTR_FIRSTACTIVETIME, String.valueOf(firstActiveTime)); 1045 out.attribute(null, ATTR_LASTACTIVETIME, String.valueOf(lastActiveTime)); 1046 out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved)); 1047 out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity)); 1048 if (lastDescription != null) { 1049 out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString()); 1050 } 1051 if (lastTaskDescription != null) { 1052 lastTaskDescription.saveToXml(out); 1053 } 1054 mLastThumbnailInfo.saveToXml(out); 1055 out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor)); 1056 out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId)); 1057 out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId)); 1058 out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId)); 1059 out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid)); 1060 out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage); 1061 out.attribute(null, ATTR_RESIZEABLE, String.valueOf(mResizeable)); 1062 out.attribute(null, ATTR_PRIVILEGED, String.valueOf(mPrivileged)); 1063 if (mLastNonFullscreenBounds != null) { 1064 out.attribute( 1065 null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString()); 1066 } 1067 1068 if (affinityIntent != null) { 1069 out.startTag(null, TAG_AFFINITYINTENT); 1070 affinityIntent.saveToXml(out); 1071 out.endTag(null, TAG_AFFINITYINTENT); 1072 } 1073 1074 out.startTag(null, TAG_INTENT); 1075 intent.saveToXml(out); 1076 out.endTag(null, TAG_INTENT); 1077 1078 final ArrayList<ActivityRecord> activities = mActivities; 1079 final int numActivities = activities.size(); 1080 for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) { 1081 final ActivityRecord r = activities.get(activityNdx); 1082 if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable() || 1083 ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT 1084 | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT) && 1085 activityNdx > 0) { 1086 // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET). 1087 break; 1088 } 1089 out.startTag(null, TAG_ACTIVITY); 1090 r.saveToXml(out); 1091 out.endTag(null, TAG_ACTIVITY); 1092 } 1093 } 1094 1095 static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor) 1096 throws IOException, XmlPullParserException { 1097 Intent intent = null; 1098 Intent affinityIntent = null; 1099 ArrayList<ActivityRecord> activities = new ArrayList<>(); 1100 ComponentName realActivity = null; 1101 ComponentName origActivity = null; 1102 String affinity = null; 1103 String rootAffinity = null; 1104 boolean hasRootAffinity = false; 1105 boolean rootHasReset = false; 1106 boolean autoRemoveRecents = false; 1107 boolean askedCompatMode = false; 1108 int taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE; 1109 int userId = 0; 1110 int effectiveUid = -1; 1111 String lastDescription = null; 1112 long firstActiveTime = -1; 1113 long lastActiveTime = -1; 1114 long lastTimeOnTop = 0; 1115 boolean neverRelinquishIdentity = true; 1116 int taskId = INVALID_TASK_ID; 1117 final int outerDepth = in.getDepth(); 1118 TaskDescription taskDescription = new TaskDescription(); 1119 TaskThumbnailInfo thumbnailInfo = new TaskThumbnailInfo(); 1120 int taskAffiliation = INVALID_TASK_ID; 1121 int taskAffiliationColor = 0; 1122 int prevTaskId = INVALID_TASK_ID; 1123 int nextTaskId = INVALID_TASK_ID; 1124 int callingUid = -1; 1125 String callingPackage = ""; 1126 boolean resizeable = false; 1127 boolean privileged = false; 1128 Rect bounds = null; 1129 1130 for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) { 1131 final String attrName = in.getAttributeName(attrNdx); 1132 final String attrValue = in.getAttributeValue(attrNdx); 1133 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: attribute name=" + 1134 attrName + " value=" + attrValue); 1135 if (ATTR_TASKID.equals(attrName)) { 1136 if (taskId == INVALID_TASK_ID) taskId = Integer.valueOf(attrValue); 1137 } else if (ATTR_REALACTIVITY.equals(attrName)) { 1138 realActivity = ComponentName.unflattenFromString(attrValue); 1139 } else if (ATTR_ORIGACTIVITY.equals(attrName)) { 1140 origActivity = ComponentName.unflattenFromString(attrValue); 1141 } else if (ATTR_AFFINITY.equals(attrName)) { 1142 affinity = attrValue; 1143 } else if (ATTR_ROOT_AFFINITY.equals(attrName)) { 1144 rootAffinity = attrValue; 1145 hasRootAffinity = true; 1146 } else if (ATTR_ROOTHASRESET.equals(attrName)) { 1147 rootHasReset = Boolean.valueOf(attrValue); 1148 } else if (ATTR_AUTOREMOVERECENTS.equals(attrName)) { 1149 autoRemoveRecents = Boolean.valueOf(attrValue); 1150 } else if (ATTR_ASKEDCOMPATMODE.equals(attrName)) { 1151 askedCompatMode = Boolean.valueOf(attrValue); 1152 } else if (ATTR_USERID.equals(attrName)) { 1153 userId = Integer.valueOf(attrValue); 1154 } else if (ATTR_EFFECTIVE_UID.equals(attrName)) { 1155 effectiveUid = Integer.valueOf(attrValue); 1156 } else if (ATTR_TASKTYPE.equals(attrName)) { 1157 taskType = Integer.valueOf(attrValue); 1158 } else if (ATTR_FIRSTACTIVETIME.equals(attrName)) { 1159 firstActiveTime = Long.valueOf(attrValue); 1160 } else if (ATTR_LASTACTIVETIME.equals(attrName)) { 1161 lastActiveTime = Long.valueOf(attrValue); 1162 } else if (ATTR_LASTDESCRIPTION.equals(attrName)) { 1163 lastDescription = attrValue; 1164 } else if (ATTR_LASTTIMEMOVED.equals(attrName)) { 1165 lastTimeOnTop = Long.valueOf(attrValue); 1166 } else if (ATTR_NEVERRELINQUISH.equals(attrName)) { 1167 neverRelinquishIdentity = Boolean.valueOf(attrValue); 1168 } else if (attrName.startsWith(TaskThumbnailInfo.ATTR_TASK_THUMBNAILINFO_PREFIX)) { 1169 thumbnailInfo.restoreFromXml(attrName, attrValue); 1170 } else if (attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) { 1171 taskDescription.restoreFromXml(attrName, attrValue); 1172 } else if (ATTR_TASK_AFFILIATION.equals(attrName)) { 1173 taskAffiliation = Integer.valueOf(attrValue); 1174 } else if (ATTR_PREV_AFFILIATION.equals(attrName)) { 1175 prevTaskId = Integer.valueOf(attrValue); 1176 } else if (ATTR_NEXT_AFFILIATION.equals(attrName)) { 1177 nextTaskId = Integer.valueOf(attrValue); 1178 } else if (ATTR_TASK_AFFILIATION_COLOR.equals(attrName)) { 1179 taskAffiliationColor = Integer.valueOf(attrValue); 1180 } else if (ATTR_CALLING_UID.equals(attrName)) { 1181 callingUid = Integer.valueOf(attrValue); 1182 } else if (ATTR_CALLING_PACKAGE.equals(attrName)) { 1183 callingPackage = attrValue; 1184 } else if (ATTR_RESIZEABLE.equals(attrName)) { 1185 resizeable = Boolean.valueOf(attrValue); 1186 } else if (ATTR_PRIVILEGED.equals(attrName)) { 1187 privileged = Boolean.valueOf(attrValue); 1188 } else if (ATTR_NON_FULLSCREEN_BOUNDS.equals(attrName)) { 1189 bounds = Rect.unflattenFromString(attrValue); 1190 } else { 1191 Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName); 1192 } 1193 } 1194 1195 int event; 1196 while (((event = in.next()) != XmlPullParser.END_DOCUMENT) && 1197 (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) { 1198 if (event == XmlPullParser.START_TAG) { 1199 final String name = in.getName(); 1200 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: START_TAG name=" + 1201 name); 1202 if (TAG_AFFINITYINTENT.equals(name)) { 1203 affinityIntent = Intent.restoreFromXml(in); 1204 } else if (TAG_INTENT.equals(name)) { 1205 intent = Intent.restoreFromXml(in); 1206 } else if (TAG_ACTIVITY.equals(name)) { 1207 ActivityRecord activity = ActivityRecord.restoreFromXml(in, stackSupervisor); 1208 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: activity=" + 1209 activity); 1210 if (activity != null) { 1211 activities.add(activity); 1212 } 1213 } else { 1214 Slog.e(TAG, "restoreTask: Unexpected name=" + name); 1215 XmlUtils.skipCurrentTag(in); 1216 } 1217 } 1218 } 1219 if (!hasRootAffinity) { 1220 rootAffinity = affinity; 1221 } else if ("@".equals(rootAffinity)) { 1222 rootAffinity = null; 1223 } 1224 if (effectiveUid <= 0) { 1225 Intent checkIntent = intent != null ? intent : affinityIntent; 1226 effectiveUid = 0; 1227 if (checkIntent != null) { 1228 IPackageManager pm = AppGlobals.getPackageManager(); 1229 try { 1230 ApplicationInfo ai = pm.getApplicationInfo( 1231 checkIntent.getComponent().getPackageName(), 1232 PackageManager.GET_UNINSTALLED_PACKAGES 1233 | PackageManager.GET_DISABLED_COMPONENTS, userId); 1234 if (ai != null) { 1235 effectiveUid = ai.uid; 1236 } 1237 } catch (RemoteException e) { 1238 } 1239 } 1240 Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent 1241 + ": effectiveUid=" + effectiveUid); 1242 } 1243 1244 final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent, 1245 affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootHasReset, 1246 autoRemoveRecents, askedCompatMode, taskType, userId, effectiveUid, lastDescription, 1247 activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity, 1248 taskDescription, thumbnailInfo, taskAffiliation, prevTaskId, nextTaskId, 1249 taskAffiliationColor, callingUid, callingPackage, resizeable, privileged); 1250 task.updateOverrideConfiguration(bounds); 1251 1252 for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) { 1253 activities.get(activityNdx).task = task; 1254 } 1255 1256 if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task); 1257 return task; 1258 } 1259 1260 /** 1261 * Update task's override configuration based on the bounds. 1262 * @return Update configuration or null if there is no change. 1263 */ 1264 Configuration updateOverrideConfiguration(Rect bounds) { 1265 if (Objects.equals(mBounds, bounds)) { 1266 return null; 1267 } 1268 final Configuration oldConfig = mOverrideConfig; 1269 final boolean oldFullscreen = mFullscreen; 1270 1271 mFullscreen = bounds == null; 1272 if (mFullscreen) { 1273 if (mBounds != null && StackId.persistTaskBounds(stack.mStackId)) { 1274 mLastNonFullscreenBounds = mBounds; 1275 } 1276 mBounds = null; 1277 mOverrideConfig = Configuration.EMPTY; 1278 } else { 1279 if (mBounds == null) { 1280 mBounds = new Rect(bounds); 1281 } else { 1282 mBounds.set(bounds); 1283 } 1284 if (stack == null || StackId.persistTaskBounds(stack.mStackId)) { 1285 mLastNonFullscreenBounds = mBounds; 1286 } 1287 1288 final Configuration serviceConfig = mService.mConfiguration; 1289 mOverrideConfig = new Configuration(Configuration.EMPTY); 1290 // TODO(multidisplay): Update Dp to that of display stack is on. 1291 final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE; 1292 mOverrideConfig.screenWidthDp = 1293 Math.min((int)(mBounds.width() / density), serviceConfig.screenWidthDp); 1294 mOverrideConfig.screenHeightDp = 1295 Math.min((int)(mBounds.height() / density), serviceConfig.screenHeightDp); 1296 mOverrideConfig.smallestScreenWidthDp = 1297 Math.min(mOverrideConfig.screenWidthDp, mOverrideConfig.screenHeightDp); 1298 mOverrideConfig.orientation = 1299 (mOverrideConfig.screenWidthDp <= mOverrideConfig.screenHeightDp) 1300 ? Configuration.ORIENTATION_PORTRAIT 1301 : Configuration.ORIENTATION_LANDSCAPE; 1302 final int sl = Configuration.resetScreenLayout(serviceConfig.screenLayout); 1303 mOverrideConfig.screenLayout = Configuration.reduceScreenLayout( 1304 sl, mOverrideConfig.screenWidthDp, mOverrideConfig.screenHeightDp); 1305 } 1306 1307 if (mFullscreen != oldFullscreen) { 1308 reportMultiWindowModeChange(); 1309 } 1310 1311 return !mOverrideConfig.equals(oldConfig) ? mOverrideConfig : null; 1312 } 1313 1314 Rect updateOverrideConfigurationFromLaunchBounds() { 1315 final Rect bounds = validateBounds(getLaunchBounds()); 1316 updateOverrideConfiguration(bounds); 1317 return bounds; 1318 } 1319 1320 static Rect validateBounds(Rect bounds) { 1321 if (bounds != null && bounds.isEmpty()) { 1322 Slog.wtf(TAG, "Received strange task bounds: " + bounds, new Throwable()); 1323 return null; 1324 } 1325 return bounds; 1326 } 1327 1328 private void reportMultiWindowModeChange() { 1329 for (int i = mActivities.size() - 1; i >= 0; i--) { 1330 final ActivityRecord r = mActivities.get(i); 1331 if (r.app != null && r.app.thread != null) { 1332 try { 1333 // An activity is consider to be in multi-window mode if its task isn't 1334 // fullscreen. 1335 r.app.thread.scheduleMultiWindowModeChanged(r.appToken, !mFullscreen); 1336 } catch (Exception e) { 1337 Slog.e(TAG, "TaskRecord.reportMultiWindowModeChange: ", e); 1338 } 1339 } 1340 } 1341 } 1342 1343 void reportPictureInPictureModeChangeIfNeeded(ActivityStack prevStack) { 1344 if (prevStack == null || prevStack == stack 1345 || (prevStack.mStackId != PINNED_STACK_ID && stack.mStackId != PINNED_STACK_ID)) { 1346 return; 1347 } 1348 1349 for (int i = mActivities.size() - 1; i >= 0; i--) { 1350 final ActivityRecord r = mActivities.get(i); 1351 if (r.app != null && r.app.thread != null) { 1352 try { 1353 r.app.thread.schedulePictureInPictureModeChanged( 1354 r.appToken, stack.mStackId == PINNED_STACK_ID); 1355 } catch (Exception e) { 1356 Slog.e(TAG, "TaskRecord.reportMultiWindowModeChange: ", e); 1357 } 1358 } 1359 } 1360 } 1361 1362 /** Updates the task's bounds and override configuration to match what is expected for the 1363 * input stack. */ 1364 void updateOverrideConfigurationForStack(ActivityStack inStack) { 1365 if (stack != null && stack == inStack) { 1366 return; 1367 } 1368 1369 if (inStack.mStackId == FREEFORM_WORKSPACE_STACK_ID) { 1370 if (!mResizeable) { 1371 throw new IllegalArgumentException("Can not position non-resizeable task=" 1372 + this + " in stack=" + inStack); 1373 } 1374 if (mBounds != null) { 1375 return; 1376 } 1377 if (mLastNonFullscreenBounds != null) { 1378 updateOverrideConfiguration(mLastNonFullscreenBounds); 1379 } else { 1380 inStack.layoutTaskInStack(this, null); 1381 } 1382 } else { 1383 updateOverrideConfiguration(inStack.mBounds); 1384 } 1385 } 1386 1387 /** 1388 * Returns the correct stack to use based on task type and currently set bounds, 1389 * regardless of the focused stack and current stack association of the task. 1390 * The task will be moved (and stack focus changed) later if necessary. 1391 */ 1392 int getLaunchStackId() { 1393 if (!isApplicationTask()) { 1394 return HOME_STACK_ID; 1395 } 1396 if (mBounds != null) { 1397 return FREEFORM_WORKSPACE_STACK_ID; 1398 } 1399 return FULLSCREEN_WORKSPACE_STACK_ID; 1400 } 1401 1402 /** Returns the bounds that should be used to launch this task. */ 1403 Rect getLaunchBounds() { 1404 // If we're over lockscreen, forget about stack bounds and use fullscreen. 1405 if (mService.mLockScreenShown == LOCK_SCREEN_SHOWN) { 1406 return null; 1407 } 1408 1409 if (stack == null) { 1410 return null; 1411 } 1412 1413 final int stackId = stack.mStackId; 1414 if (stackId == HOME_STACK_ID 1415 || stackId == FULLSCREEN_WORKSPACE_STACK_ID 1416 || (stackId == DOCKED_STACK_ID && !mResizeable)) { 1417 return mResizeable ? stack.mBounds : null; 1418 } else if (!StackId.persistTaskBounds(stackId)) { 1419 return stack.mBounds; 1420 } 1421 return mLastNonFullscreenBounds; 1422 } 1423 1424 boolean canMatchRootAffinity() { 1425 // We don't allow root affinity matching on the pinned stack as no other task should 1426 // be launching in it based on affinity. 1427 return rootAffinity != null && (stack == null || stack.mStackId != PINNED_STACK_ID); 1428 } 1429 1430 void dump(PrintWriter pw, String prefix) { 1431 pw.print(prefix); pw.print("userId="); pw.print(userId); 1432 pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid); 1433 pw.print(" mCallingUid="); UserHandle.formatUid(pw, mCallingUid); 1434 pw.print(" mCallingPackage="); pw.println(mCallingPackage); 1435 if (affinity != null || rootAffinity != null) { 1436 pw.print(prefix); pw.print("affinity="); pw.print(affinity); 1437 if (affinity == null || !affinity.equals(rootAffinity)) { 1438 pw.print(" root="); pw.println(rootAffinity); 1439 } else { 1440 pw.println(); 1441 } 1442 } 1443 if (voiceSession != null || voiceInteractor != null) { 1444 pw.print(prefix); pw.print("VOICE: session=0x"); 1445 pw.print(Integer.toHexString(System.identityHashCode(voiceSession))); 1446 pw.print(" interactor=0x"); 1447 pw.println(Integer.toHexString(System.identityHashCode(voiceInteractor))); 1448 } 1449 if (intent != null) { 1450 StringBuilder sb = new StringBuilder(128); 1451 sb.append(prefix); sb.append("intent={"); 1452 intent.toShortString(sb, false, true, false, true); 1453 sb.append('}'); 1454 pw.println(sb.toString()); 1455 } 1456 if (affinityIntent != null) { 1457 StringBuilder sb = new StringBuilder(128); 1458 sb.append(prefix); sb.append("affinityIntent={"); 1459 affinityIntent.toShortString(sb, false, true, false, true); 1460 sb.append('}'); 1461 pw.println(sb.toString()); 1462 } 1463 if (origActivity != null) { 1464 pw.print(prefix); pw.print("origActivity="); 1465 pw.println(origActivity.flattenToShortString()); 1466 } 1467 if (realActivity != null) { 1468 pw.print(prefix); pw.print("realActivity="); 1469 pw.println(realActivity.flattenToShortString()); 1470 } 1471 if (autoRemoveRecents || isPersistable || taskType != 0 || mTaskToReturnTo != 0 1472 || numFullscreen != 0) { 1473 pw.print(prefix); pw.print("autoRemoveRecents="); pw.print(autoRemoveRecents); 1474 pw.print(" isPersistable="); pw.print(isPersistable); 1475 pw.print(" numFullscreen="); pw.print(numFullscreen); 1476 pw.print(" taskType="); pw.print(taskType); 1477 pw.print(" mTaskToReturnTo="); pw.println(mTaskToReturnTo); 1478 } 1479 if (rootWasReset || mNeverRelinquishIdentity || mReuseTask 1480 || mLockTaskAuth != LOCK_TASK_AUTH_PINNABLE) { 1481 pw.print(prefix); pw.print("rootWasReset="); pw.print(rootWasReset); 1482 pw.print(" mNeverRelinquishIdentity="); pw.print(mNeverRelinquishIdentity); 1483 pw.print(" mReuseTask="); pw.print(mReuseTask); 1484 pw.print(" mLockTaskAuth="); pw.println(lockTaskAuthToString()); 1485 } 1486 if (mAffiliatedTaskId != taskId || mPrevAffiliateTaskId != INVALID_TASK_ID 1487 || mPrevAffiliate != null || mNextAffiliateTaskId != INVALID_TASK_ID 1488 || mNextAffiliate != null) { 1489 pw.print(prefix); pw.print("affiliation="); pw.print(mAffiliatedTaskId); 1490 pw.print(" prevAffiliation="); pw.print(mPrevAffiliateTaskId); 1491 pw.print(" ("); 1492 if (mPrevAffiliate == null) { 1493 pw.print("null"); 1494 } else { 1495 pw.print(Integer.toHexString(System.identityHashCode(mPrevAffiliate))); 1496 } 1497 pw.print(") nextAffiliation="); pw.print(mNextAffiliateTaskId); 1498 pw.print(" ("); 1499 if (mNextAffiliate == null) { 1500 pw.print("null"); 1501 } else { 1502 pw.print(Integer.toHexString(System.identityHashCode(mNextAffiliate))); 1503 } 1504 pw.println(")"); 1505 } 1506 pw.print(prefix); pw.print("Activities="); pw.println(mActivities); 1507 if (!askedCompatMode || !inRecents || !isAvailable) { 1508 pw.print(prefix); pw.print("askedCompatMode="); pw.print(askedCompatMode); 1509 pw.print(" inRecents="); pw.print(inRecents); 1510 pw.print(" isAvailable="); pw.println(isAvailable); 1511 } 1512 pw.print(prefix); pw.print("lastThumbnail="); pw.print(mLastThumbnail); 1513 pw.print(" lastThumbnailFile="); pw.println(mLastThumbnailFile); 1514 if (lastDescription != null) { 1515 pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription); 1516 } 1517 if (stack != null) { 1518 pw.print(prefix); pw.print("stackId="); pw.println(stack.mStackId); 1519 } 1520 pw.print(prefix); pw.print("hasBeenVisible="); pw.print(hasBeenVisible); 1521 pw.print(" mResizeable="); pw.print(mResizeable); 1522 pw.print(" firstActiveTime="); pw.print(lastActiveTime); 1523 pw.print(" lastActiveTime="); pw.print(lastActiveTime); 1524 pw.print(" (inactive for "); 1525 pw.print((getInactiveDuration()/1000)); pw.println("s)"); 1526 } 1527 1528 @Override 1529 public String toString() { 1530 StringBuilder sb = new StringBuilder(128); 1531 if (stringName != null) { 1532 sb.append(stringName); 1533 sb.append(" U="); 1534 sb.append(userId); 1535 sb.append(" StackId="); 1536 sb.append(stack != null ? stack.mStackId : INVALID_STACK_ID); 1537 sb.append(" sz="); 1538 sb.append(mActivities.size()); 1539 sb.append('}'); 1540 return sb.toString(); 1541 } 1542 sb.append("TaskRecord{"); 1543 sb.append(Integer.toHexString(System.identityHashCode(this))); 1544 sb.append(" #"); 1545 sb.append(taskId); 1546 if (affinity != null) { 1547 sb.append(" A="); 1548 sb.append(affinity); 1549 } else if (intent != null) { 1550 sb.append(" I="); 1551 sb.append(intent.getComponent().flattenToShortString()); 1552 } else if (affinityIntent != null) { 1553 sb.append(" aI="); 1554 sb.append(affinityIntent.getComponent().flattenToShortString()); 1555 } else { 1556 sb.append(" ??"); 1557 } 1558 stringName = sb.toString(); 1559 return toString(); 1560 } 1561} 1562