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