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