TaskRecord.java revision 979f5ed923db91b08279bb25799c3d54d743d1a7
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 * Sets the last thumbnail. 482 * @return whether the thumbnail was set 483 */ 484 boolean setLastThumbnail(Bitmap thumbnail) { 485 if (mLastThumbnail != thumbnail) { 486 mLastThumbnail = thumbnail; 487 if (thumbnail == null) { 488 if (mLastThumbnailFile != null) { 489 mLastThumbnailFile.delete(); 490 } 491 } else { 492 mService.mTaskPersister.saveImage(thumbnail, mFilename); 493 } 494 return true; 495 } 496 return false; 497 } 498 499 void getLastThumbnail(TaskThumbnail thumbs) { 500 thumbs.mainThumbnail = mLastThumbnail; 501 thumbs.thumbnailFileDescriptor = null; 502 if (mLastThumbnail == null) { 503 thumbs.mainThumbnail = mService.mTaskPersister.getImageFromWriteQueue(mFilename); 504 } 505 // Only load the thumbnail file if we don't have a thumbnail 506 if (thumbs.mainThumbnail == null && mLastThumbnailFile.exists()) { 507 try { 508 thumbs.thumbnailFileDescriptor = ParcelFileDescriptor.open(mLastThumbnailFile, 509 ParcelFileDescriptor.MODE_READ_ONLY); 510 } catch (IOException e) { 511 } 512 } 513 } 514 515 void freeLastThumbnail() { 516 mLastThumbnail = null; 517 } 518 519 void disposeThumbnail() { 520 mLastThumbnail = null; 521 lastDescription = null; 522 } 523 524 /** Returns the intent for the root activity for this task */ 525 Intent getBaseIntent() { 526 return intent != null ? intent : affinityIntent; 527 } 528 529 /** Returns the first non-finishing activity from the root. */ 530 ActivityRecord getRootActivity() { 531 for (int i = 0; i < mActivities.size(); i++) { 532 final ActivityRecord r = mActivities.get(i); 533 if (r.finishing) { 534 continue; 535 } 536 return r; 537 } 538 return null; 539 } 540 541 ActivityRecord getTopActivity() { 542 for (int i = mActivities.size() - 1; i >= 0; --i) { 543 final ActivityRecord r = mActivities.get(i); 544 if (r.finishing) { 545 continue; 546 } 547 return r; 548 } 549 return null; 550 } 551 552 ActivityRecord topRunningActivityLocked() { 553 if (stack != null) { 554 for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) { 555 ActivityRecord r = mActivities.get(activityNdx); 556 if (!r.finishing && stack.okToShowLocked(r)) { 557 return r; 558 } 559 } 560 } 561 return null; 562 } 563 564 /** Call after activity movement or finish to make sure that frontOfTask is set correctly */ 565 final void setFrontOfTask() { 566 boolean foundFront = false; 567 final int numActivities = mActivities.size(); 568 for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) { 569 final ActivityRecord r = mActivities.get(activityNdx); 570 if (foundFront || r.finishing) { 571 r.frontOfTask = false; 572 } else { 573 r.frontOfTask = true; 574 // Set frontOfTask false for every following activity. 575 foundFront = true; 576 } 577 } 578 if (!foundFront && numActivities > 0) { 579 // All activities of this task are finishing. As we ought to have a frontOfTask 580 // activity, make the bottom activity front. 581 mActivities.get(0).frontOfTask = true; 582 } 583 } 584 585 /** 586 * Reorder the history stack so that the passed activity is brought to the front. 587 */ 588 final void moveActivityToFrontLocked(ActivityRecord newTop) { 589 if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE, 590 "Removing and adding activity " + newTop 591 + " to stack at top callers=" + Debug.getCallers(4)); 592 593 mActivities.remove(newTop); 594 mActivities.add(newTop); 595 updateEffectiveIntent(); 596 597 setFrontOfTask(); 598 } 599 600 void addActivityAtBottom(ActivityRecord r) { 601 addActivityAtIndex(0, r); 602 } 603 604 void addActivityToTop(ActivityRecord r) { 605 addActivityAtIndex(mActivities.size(), r); 606 } 607 608 void addActivityAtIndex(int index, ActivityRecord r) { 609 // Remove r first, and if it wasn't already in the list and it's fullscreen, count it. 610 if (!mActivities.remove(r) && r.fullscreen) { 611 // Was not previously in list. 612 numFullscreen++; 613 } 614 // Only set this based on the first activity 615 if (mActivities.isEmpty()) { 616 taskType = r.mActivityType; 617 isPersistable = r.isPersistable(); 618 mCallingUid = r.launchedFromUid; 619 mCallingPackage = r.launchedFromPackage; 620 // Clamp to [1, max]. 621 maxRecents = Math.min(Math.max(r.info.maxRecents, 1), 622 ActivityManager.getMaxAppRecentsLimitStatic()); 623 } else { 624 // Otherwise make all added activities match this one. 625 r.mActivityType = taskType; 626 } 627 mActivities.add(index, r); 628 updateEffectiveIntent(); 629 if (r.isPersistable()) { 630 mService.notifyTaskPersisterLocked(this, false); 631 } 632 } 633 634 /** @return true if this was the last activity in the task */ 635 boolean removeActivity(ActivityRecord r) { 636 if (mActivities.remove(r) && r.fullscreen) { 637 // Was previously in list. 638 numFullscreen--; 639 } 640 if (r.isPersistable()) { 641 mService.notifyTaskPersisterLocked(this, false); 642 } 643 if (mActivities.isEmpty()) { 644 return !mReuseTask; 645 } 646 updateEffectiveIntent(); 647 return false; 648 } 649 650 boolean autoRemoveFromRecents() { 651 // We will automatically remove the task either if it has explicitly asked for 652 // this, or it is empty and has never contained an activity that got shown to 653 // the user. 654 return autoRemoveRecents || (mActivities.isEmpty() && !hasBeenVisible); 655 } 656 657 /** 658 * Completely remove all activities associated with an existing 659 * task starting at a specified index. 660 */ 661 final void performClearTaskAtIndexLocked(int activityNdx) { 662 int numActivities = mActivities.size(); 663 for ( ; activityNdx < numActivities; ++activityNdx) { 664 final ActivityRecord r = mActivities.get(activityNdx); 665 if (r.finishing) { 666 continue; 667 } 668 if (stack == null) { 669 // Task was restored from persistent storage. 670 r.takeFromHistory(); 671 mActivities.remove(activityNdx); 672 --activityNdx; 673 --numActivities; 674 } else if (stack.finishActivityLocked( 675 r, Activity.RESULT_CANCELED, null, "clear-task-index", false)) { 676 --activityNdx; 677 --numActivities; 678 } 679 } 680 } 681 682 /** 683 * Completely remove all activities associated with an existing task. 684 */ 685 final void performClearTaskLocked() { 686 mReuseTask = true; 687 performClearTaskAtIndexLocked(0); 688 mReuseTask = false; 689 } 690 691 /** 692 * Perform clear operation as requested by 693 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the 694 * stack to the given task, then look for 695 * an instance of that activity in the stack and, if found, finish all 696 * activities on top of it and return the instance. 697 * 698 * @param newR Description of the new activity being started. 699 * @return Returns the old activity that should be continued to be used, 700 * or null if none was found. 701 */ 702 final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) { 703 int numActivities = mActivities.size(); 704 for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) { 705 ActivityRecord r = mActivities.get(activityNdx); 706 if (r.finishing) { 707 continue; 708 } 709 if (r.realActivity.equals(newR.realActivity)) { 710 // Here it is! Now finish everything in front... 711 final ActivityRecord ret = r; 712 713 for (++activityNdx; activityNdx < numActivities; ++activityNdx) { 714 r = mActivities.get(activityNdx); 715 if (r.finishing) { 716 continue; 717 } 718 ActivityOptions opts = r.takeOptionsLocked(); 719 if (opts != null) { 720 ret.updateOptionsLocked(opts); 721 } 722 if (stack != null && stack.finishActivityLocked( 723 r, Activity.RESULT_CANCELED, null, "clear-task-stack", false)) { 724 --activityNdx; 725 --numActivities; 726 } 727 } 728 729 // Finally, if this is a normal launch mode (that is, not 730 // expecting onNewIntent()), then we will finish the current 731 // instance of the activity so a new fresh one can be started. 732 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE 733 && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) { 734 if (!ret.finishing) { 735 if (stack != null) { 736 stack.finishActivityLocked( 737 ret, Activity.RESULT_CANCELED, null, "clear-task-top", false); 738 } 739 return null; 740 } 741 } 742 743 return ret; 744 } 745 } 746 747 return null; 748 } 749 750 public TaskThumbnail getTaskThumbnailLocked() { 751 if (stack != null) { 752 final ActivityRecord resumedActivity = stack.mResumedActivity; 753 if (resumedActivity != null && resumedActivity.task == this) { 754 final Bitmap thumbnail = stack.screenshotActivities(resumedActivity); 755 setLastThumbnail(thumbnail); 756 } 757 } 758 final TaskThumbnail taskThumbnail = new TaskThumbnail(); 759 getLastThumbnail(taskThumbnail); 760 return taskThumbnail; 761 } 762 763 public void removeTaskActivitiesLocked() { 764 // Just remove the entire task. 765 performClearTaskAtIndexLocked(0); 766 } 767 768 String lockTaskAuthToString() { 769 switch (mLockTaskAuth) { 770 case LOCK_TASK_AUTH_DONT_LOCK: return "LOCK_TASK_AUTH_DONT_LOCK"; 771 case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE"; 772 case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE"; 773 case LOCK_TASK_AUTH_WHITELISTED: return "LOCK_TASK_AUTH_WHITELISTED"; 774 case LOCK_TASK_AUTH_LAUNCHABLE_PRIV: return "LOCK_TASK_AUTH_LAUNCHABLE_PRIV"; 775 default: return "unknown=" + mLockTaskAuth; 776 } 777 } 778 779 void setLockTaskAuth() { 780 if (!mPrivileged && 781 (mLockTaskMode == LOCK_TASK_LAUNCH_MODE_ALWAYS || 782 mLockTaskMode == LOCK_TASK_LAUNCH_MODE_NEVER)) { 783 // Non-priv apps are not allowed to use always or never, fall back to default 784 mLockTaskMode = LOCK_TASK_LAUNCH_MODE_DEFAULT; 785 } 786 switch (mLockTaskMode) { 787 case LOCK_TASK_LAUNCH_MODE_DEFAULT: 788 mLockTaskAuth = isLockTaskWhitelistedLocked() ? 789 LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE; 790 break; 791 792 case LOCK_TASK_LAUNCH_MODE_NEVER: 793 mLockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK; 794 break; 795 796 case LOCK_TASK_LAUNCH_MODE_ALWAYS: 797 mLockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV; 798 break; 799 800 case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED: 801 mLockTaskAuth = isLockTaskWhitelistedLocked() ? 802 LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE; 803 break; 804 } 805 if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this + 806 " mLockTaskAuth=" + lockTaskAuthToString()); 807 } 808 809 boolean isLockTaskWhitelistedLocked() { 810 String pkg = (realActivity != null) ? realActivity.getPackageName() : null; 811 if (pkg == null) { 812 return false; 813 } 814 String[] packages = mService.mLockTaskPackages.get(userId); 815 if (packages == null) { 816 return false; 817 } 818 for (int i = packages.length - 1; i >= 0; --i) { 819 if (pkg.equals(packages[i])) { 820 return true; 821 } 822 } 823 return false; 824 } 825 boolean isHomeTask() { 826 return taskType == HOME_ACTIVITY_TYPE; 827 } 828 829 boolean isApplicationTask() { 830 return taskType == APPLICATION_ACTIVITY_TYPE; 831 } 832 833 boolean isOverHomeStack() { 834 return mTaskToReturnTo == HOME_ACTIVITY_TYPE || mTaskToReturnTo == RECENTS_ACTIVITY_TYPE; 835 } 836 837 /** 838 * Find the activity in the history stack within the given task. Returns 839 * the index within the history at which it's found, or < 0 if not found. 840 */ 841 final ActivityRecord findActivityInHistoryLocked(ActivityRecord r) { 842 final ComponentName realActivity = r.realActivity; 843 for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) { 844 ActivityRecord candidate = mActivities.get(activityNdx); 845 if (candidate.finishing) { 846 continue; 847 } 848 if (candidate.realActivity.equals(realActivity)) { 849 return candidate; 850 } 851 } 852 return null; 853 } 854 855 /** Updates the last task description values. */ 856 void updateTaskDescription() { 857 // Traverse upwards looking for any break between main task activities and 858 // utility activities. 859 int activityNdx; 860 final int numActivities = mActivities.size(); 861 final boolean relinquish = numActivities == 0 ? false : 862 (mActivities.get(0).info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) != 0; 863 for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities; 864 ++activityNdx) { 865 final ActivityRecord r = mActivities.get(activityNdx); 866 if (relinquish && (r.info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0) { 867 // This will be the top activity for determining taskDescription. Pre-inc to 868 // overcome initial decrement below. 869 ++activityNdx; 870 break; 871 } 872 if (r.intent != null && 873 (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) { 874 break; 875 } 876 } 877 if (activityNdx > 0) { 878 // Traverse downwards starting below break looking for set label, icon. 879 // Note that if there are activities in the task but none of them set the 880 // recent activity values, then we do not fall back to the last set 881 // values in the TaskRecord. 882 String label = null; 883 String iconFilename = null; 884 int colorPrimary = 0; 885 for (--activityNdx; activityNdx >= 0; --activityNdx) { 886 final ActivityRecord r = mActivities.get(activityNdx); 887 if (r.taskDescription != null) { 888 if (label == null) { 889 label = r.taskDescription.getLabel(); 890 } 891 if (iconFilename == null) { 892 iconFilename = r.taskDescription.getIconFilename(); 893 } 894 if (colorPrimary == 0) { 895 colorPrimary = r.taskDescription.getPrimaryColor(); 896 } 897 } 898 } 899 lastTaskDescription = new TaskDescription(label, colorPrimary, iconFilename); 900 // Update the task affiliation color if we are the parent of the group 901 if (taskId == mAffiliatedTaskId) { 902 mAffiliatedTaskColor = lastTaskDescription.getPrimaryColor(); 903 } 904 } 905 } 906 907 int findEffectiveRootIndex() { 908 int effectiveNdx = 0; 909 final int topActivityNdx = mActivities.size() - 1; 910 for (int activityNdx = 0; activityNdx <= topActivityNdx; ++activityNdx) { 911 final ActivityRecord r = mActivities.get(activityNdx); 912 if (r.finishing) { 913 continue; 914 } 915 effectiveNdx = activityNdx; 916 if ((r.info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0) { 917 break; 918 } 919 } 920 return effectiveNdx; 921 } 922 923 void updateEffectiveIntent() { 924 final int effectiveRootIndex = findEffectiveRootIndex(); 925 final ActivityRecord r = mActivities.get(effectiveRootIndex); 926 setIntent(r); 927 } 928 929 void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException { 930 if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this); 931 932 out.attribute(null, ATTR_TASKID, String.valueOf(taskId)); 933 if (realActivity != null) { 934 out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString()); 935 } 936 if (origActivity != null) { 937 out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString()); 938 } 939 // Write affinity, and root affinity if it is different from affinity. 940 // We use the special string "@" for a null root affinity, so we can identify 941 // later whether we were given a root affinity or should just make it the 942 // same as the affinity. 943 if (affinity != null) { 944 out.attribute(null, ATTR_AFFINITY, affinity); 945 if (!affinity.equals(rootAffinity)) { 946 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@"); 947 } 948 } else if (rootAffinity != null) { 949 out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@"); 950 } 951 out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset)); 952 out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents)); 953 out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode)); 954 out.attribute(null, ATTR_USERID, String.valueOf(userId)); 955 out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid)); 956 out.attribute(null, ATTR_TASKTYPE, String.valueOf(taskType)); 957 out.attribute(null, ATTR_FIRSTACTIVETIME, String.valueOf(firstActiveTime)); 958 out.attribute(null, ATTR_LASTACTIVETIME, String.valueOf(lastActiveTime)); 959 out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved)); 960 out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity)); 961 if (lastDescription != null) { 962 out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString()); 963 } 964 if (lastTaskDescription != null) { 965 lastTaskDescription.saveToXml(out); 966 } 967 out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor)); 968 out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId)); 969 out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId)); 970 out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId)); 971 out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid)); 972 out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage); 973 out.attribute(null, ATTR_RESIZEABLE, String.valueOf(mResizeable)); 974 out.attribute(null, ATTR_PRIVILEGED, String.valueOf(mPrivileged)); 975 if (mLastNonFullscreenBounds != null) { 976 out.attribute( 977 null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString()); 978 } 979 980 if (affinityIntent != null) { 981 out.startTag(null, TAG_AFFINITYINTENT); 982 affinityIntent.saveToXml(out); 983 out.endTag(null, TAG_AFFINITYINTENT); 984 } 985 986 out.startTag(null, TAG_INTENT); 987 intent.saveToXml(out); 988 out.endTag(null, TAG_INTENT); 989 990 final ArrayList<ActivityRecord> activities = mActivities; 991 final int numActivities = activities.size(); 992 for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) { 993 final ActivityRecord r = activities.get(activityNdx); 994 if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable() || 995 ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT 996 | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT) && 997 activityNdx > 0) { 998 // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET). 999 break; 1000 } 1001 out.startTag(null, TAG_ACTIVITY); 1002 r.saveToXml(out); 1003 out.endTag(null, TAG_ACTIVITY); 1004 } 1005 } 1006 1007 static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor) 1008 throws IOException, XmlPullParserException { 1009 Intent intent = null; 1010 Intent affinityIntent = null; 1011 ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>(); 1012 ComponentName realActivity = null; 1013 ComponentName origActivity = null; 1014 String affinity = null; 1015 String rootAffinity = null; 1016 boolean hasRootAffinity = false; 1017 boolean rootHasReset = false; 1018 boolean autoRemoveRecents = false; 1019 boolean askedCompatMode = false; 1020 int taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE; 1021 int userId = 0; 1022 int effectiveUid = -1; 1023 String lastDescription = null; 1024 long firstActiveTime = -1; 1025 long lastActiveTime = -1; 1026 long lastTimeOnTop = 0; 1027 boolean neverRelinquishIdentity = true; 1028 int taskId = INVALID_TASK_ID; 1029 final int outerDepth = in.getDepth(); 1030 TaskDescription taskDescription = new TaskDescription(); 1031 int taskAffiliation = INVALID_TASK_ID; 1032 int taskAffiliationColor = 0; 1033 int prevTaskId = INVALID_TASK_ID; 1034 int nextTaskId = INVALID_TASK_ID; 1035 int callingUid = -1; 1036 String callingPackage = ""; 1037 boolean resizeable = false; 1038 boolean privileged = false; 1039 Rect bounds = null; 1040 1041 for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) { 1042 final String attrName = in.getAttributeName(attrNdx); 1043 final String attrValue = in.getAttributeValue(attrNdx); 1044 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: attribute name=" + 1045 attrName + " value=" + attrValue); 1046 if (ATTR_TASKID.equals(attrName)) { 1047 if (taskId == INVALID_TASK_ID) taskId = Integer.valueOf(attrValue); 1048 } else if (ATTR_REALACTIVITY.equals(attrName)) { 1049 realActivity = ComponentName.unflattenFromString(attrValue); 1050 } else if (ATTR_ORIGACTIVITY.equals(attrName)) { 1051 origActivity = ComponentName.unflattenFromString(attrValue); 1052 } else if (ATTR_AFFINITY.equals(attrName)) { 1053 affinity = attrValue; 1054 } else if (ATTR_ROOT_AFFINITY.equals(attrName)) { 1055 rootAffinity = attrValue; 1056 hasRootAffinity = true; 1057 } else if (ATTR_ROOTHASRESET.equals(attrName)) { 1058 rootHasReset = Boolean.valueOf(attrValue); 1059 } else if (ATTR_AUTOREMOVERECENTS.equals(attrName)) { 1060 autoRemoveRecents = Boolean.valueOf(attrValue); 1061 } else if (ATTR_ASKEDCOMPATMODE.equals(attrName)) { 1062 askedCompatMode = Boolean.valueOf(attrValue); 1063 } else if (ATTR_USERID.equals(attrName)) { 1064 userId = Integer.valueOf(attrValue); 1065 } else if (ATTR_EFFECTIVE_UID.equals(attrName)) { 1066 effectiveUid = Integer.valueOf(attrValue); 1067 } else if (ATTR_TASKTYPE.equals(attrName)) { 1068 taskType = Integer.valueOf(attrValue); 1069 } else if (ATTR_FIRSTACTIVETIME.equals(attrName)) { 1070 firstActiveTime = Long.valueOf(attrValue); 1071 } else if (ATTR_LASTACTIVETIME.equals(attrName)) { 1072 lastActiveTime = Long.valueOf(attrValue); 1073 } else if (ATTR_LASTDESCRIPTION.equals(attrName)) { 1074 lastDescription = attrValue; 1075 } else if (ATTR_LASTTIMEMOVED.equals(attrName)) { 1076 lastTimeOnTop = Long.valueOf(attrValue); 1077 } else if (ATTR_NEVERRELINQUISH.equals(attrName)) { 1078 neverRelinquishIdentity = Boolean.valueOf(attrValue); 1079 } else if (attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) { 1080 taskDescription.restoreFromXml(attrName, attrValue); 1081 } else if (ATTR_TASK_AFFILIATION.equals(attrName)) { 1082 taskAffiliation = Integer.valueOf(attrValue); 1083 } else if (ATTR_PREV_AFFILIATION.equals(attrName)) { 1084 prevTaskId = Integer.valueOf(attrValue); 1085 } else if (ATTR_NEXT_AFFILIATION.equals(attrName)) { 1086 nextTaskId = Integer.valueOf(attrValue); 1087 } else if (ATTR_TASK_AFFILIATION_COLOR.equals(attrName)) { 1088 taskAffiliationColor = Integer.valueOf(attrValue); 1089 } else if (ATTR_CALLING_UID.equals(attrName)) { 1090 callingUid = Integer.valueOf(attrValue); 1091 } else if (ATTR_CALLING_PACKAGE.equals(attrName)) { 1092 callingPackage = attrValue; 1093 } else if (ATTR_RESIZEABLE.equals(attrName)) { 1094 resizeable = Boolean.valueOf(attrValue); 1095 } else if (ATTR_PRIVILEGED.equals(attrName)) { 1096 privileged = Boolean.valueOf(attrValue); 1097 } else if (ATTR_NON_FULLSCREEN_BOUNDS.equals(attrName)) { 1098 bounds = Rect.unflattenFromString(attrValue); 1099 } else { 1100 Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName); 1101 } 1102 } 1103 1104 int event; 1105 while (((event = in.next()) != XmlPullParser.END_DOCUMENT) && 1106 (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) { 1107 if (event == XmlPullParser.START_TAG) { 1108 final String name = in.getName(); 1109 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: START_TAG name=" + 1110 name); 1111 if (TAG_AFFINITYINTENT.equals(name)) { 1112 affinityIntent = Intent.restoreFromXml(in); 1113 } else if (TAG_INTENT.equals(name)) { 1114 intent = Intent.restoreFromXml(in); 1115 } else if (TAG_ACTIVITY.equals(name)) { 1116 ActivityRecord activity = ActivityRecord.restoreFromXml(in, stackSupervisor); 1117 if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: activity=" + 1118 activity); 1119 if (activity != null) { 1120 activities.add(activity); 1121 } 1122 } else { 1123 Slog.e(TAG, "restoreTask: Unexpected name=" + name); 1124 XmlUtils.skipCurrentTag(in); 1125 } 1126 } 1127 } 1128 if (!hasRootAffinity) { 1129 rootAffinity = affinity; 1130 } else if ("@".equals(rootAffinity)) { 1131 rootAffinity = null; 1132 } 1133 if (effectiveUid <= 0) { 1134 Intent checkIntent = intent != null ? intent : affinityIntent; 1135 effectiveUid = 0; 1136 if (checkIntent != null) { 1137 IPackageManager pm = AppGlobals.getPackageManager(); 1138 try { 1139 ApplicationInfo ai = pm.getApplicationInfo( 1140 checkIntent.getComponent().getPackageName(), 1141 PackageManager.GET_UNINSTALLED_PACKAGES 1142 | PackageManager.GET_DISABLED_COMPONENTS, userId); 1143 if (ai != null) { 1144 effectiveUid = ai.uid; 1145 } 1146 } catch (RemoteException e) { 1147 } 1148 } 1149 Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent 1150 + ": effectiveUid=" + effectiveUid); 1151 } 1152 1153 final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent, 1154 affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootHasReset, 1155 autoRemoveRecents, askedCompatMode, taskType, userId, effectiveUid, lastDescription, 1156 activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity, 1157 taskDescription, taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor, 1158 callingUid, callingPackage, resizeable, privileged); 1159 task.updateOverrideConfiguration(bounds); 1160 1161 for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) { 1162 activities.get(activityNdx).task = task; 1163 } 1164 1165 if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task); 1166 return task; 1167 } 1168 1169 /** 1170 * Update task's override configuration based on the bounds. 1171 * @return Update configuration or null if there is no change. 1172 */ 1173 Configuration updateOverrideConfiguration(Rect bounds) { 1174 if (Objects.equals(mBounds, bounds)) { 1175 return null; 1176 } 1177 Configuration oldConfig = mOverrideConfig; 1178 1179 mFullscreen = bounds == null; 1180 if (mFullscreen) { 1181 if (mBounds != null && stack.mStackId != DOCKED_STACK_ID) { 1182 mLastNonFullscreenBounds = mBounds; 1183 } 1184 mBounds = null; 1185 mOverrideConfig = Configuration.EMPTY; 1186 } else { 1187 mBounds = new Rect(bounds); 1188 if (stack == null || stack.mStackId != DOCKED_STACK_ID) { 1189 mLastNonFullscreenBounds = mBounds; 1190 } 1191 1192 final Configuration serviceConfig = mService.mConfiguration; 1193 mOverrideConfig = new Configuration(serviceConfig); 1194 // TODO(multidisplay): Update Dp to that of display stack is on. 1195 final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE; 1196 mOverrideConfig.screenWidthDp = 1197 Math.min((int)(mBounds.width() / density), serviceConfig.screenWidthDp); 1198 mOverrideConfig.screenHeightDp = 1199 Math.min((int)(mBounds.height() / density), serviceConfig.screenHeightDp); 1200 mOverrideConfig.smallestScreenWidthDp = 1201 Math.min(mOverrideConfig.screenWidthDp, mOverrideConfig.screenHeightDp); 1202 mOverrideConfig.orientation = 1203 (mOverrideConfig.screenWidthDp <= mOverrideConfig.screenHeightDp) 1204 ? Configuration.ORIENTATION_PORTRAIT 1205 : Configuration.ORIENTATION_LANDSCAPE; 1206 } 1207 return !mOverrideConfig.equals(oldConfig) ? mOverrideConfig : null; 1208 } 1209 1210 /** 1211 * Returns the correct stack to use based on task type and currently set bounds, 1212 * regardless of the focused stack and current stack association of the task. 1213 * The task will be moved (and stack focus changed) later if necessary. 1214 */ 1215 int getLaunchStackId() { 1216 if (!isApplicationTask()) { 1217 return HOME_STACK_ID; 1218 } 1219 if (mBounds != null) { 1220 return FREEFORM_WORKSPACE_STACK_ID; 1221 } 1222 return FULLSCREEN_WORKSPACE_STACK_ID; 1223 } 1224 1225 /** Returns the bounds that should be used to launch this task. */ 1226 Rect getLaunchBounds() { 1227 if (stack == null 1228 || stack.mStackId == HOME_STACK_ID 1229 || stack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID) { 1230 return (mResizeable && stack != null) ? stack.mBounds : null; 1231 } else if (stack.mStackId == DOCKED_STACK_ID) { 1232 return stack.mBounds; 1233 } 1234 return mLastNonFullscreenBounds; 1235 } 1236 1237 void dump(PrintWriter pw, String prefix) { 1238 pw.print(prefix); pw.print("userId="); pw.print(userId); 1239 pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid); 1240 pw.print(" mCallingUid="); UserHandle.formatUid(pw, mCallingUid); 1241 pw.print(" mCallingPackage="); pw.println(mCallingPackage); 1242 if (affinity != null || rootAffinity != null) { 1243 pw.print(prefix); pw.print("affinity="); pw.print(affinity); 1244 if (affinity == null || !affinity.equals(rootAffinity)) { 1245 pw.print(" root="); pw.println(rootAffinity); 1246 } else { 1247 pw.println(); 1248 } 1249 } 1250 if (voiceSession != null || voiceInteractor != null) { 1251 pw.print(prefix); pw.print("VOICE: session=0x"); 1252 pw.print(Integer.toHexString(System.identityHashCode(voiceSession))); 1253 pw.print(" interactor=0x"); 1254 pw.println(Integer.toHexString(System.identityHashCode(voiceInteractor))); 1255 } 1256 if (intent != null) { 1257 StringBuilder sb = new StringBuilder(128); 1258 sb.append(prefix); sb.append("intent={"); 1259 intent.toShortString(sb, false, true, false, true); 1260 sb.append('}'); 1261 pw.println(sb.toString()); 1262 } 1263 if (affinityIntent != null) { 1264 StringBuilder sb = new StringBuilder(128); 1265 sb.append(prefix); sb.append("affinityIntent={"); 1266 affinityIntent.toShortString(sb, false, true, false, true); 1267 sb.append('}'); 1268 pw.println(sb.toString()); 1269 } 1270 if (origActivity != null) { 1271 pw.print(prefix); pw.print("origActivity="); 1272 pw.println(origActivity.flattenToShortString()); 1273 } 1274 if (realActivity != null) { 1275 pw.print(prefix); pw.print("realActivity="); 1276 pw.println(realActivity.flattenToShortString()); 1277 } 1278 if (autoRemoveRecents || isPersistable || taskType != 0 || mTaskToReturnTo != 0 1279 || numFullscreen != 0) { 1280 pw.print(prefix); pw.print("autoRemoveRecents="); pw.print(autoRemoveRecents); 1281 pw.print(" isPersistable="); pw.print(isPersistable); 1282 pw.print(" numFullscreen="); pw.print(numFullscreen); 1283 pw.print(" taskType="); pw.print(taskType); 1284 pw.print(" mTaskToReturnTo="); pw.println(mTaskToReturnTo); 1285 } 1286 if (rootWasReset || mNeverRelinquishIdentity || mReuseTask 1287 || mLockTaskAuth != LOCK_TASK_AUTH_PINNABLE) { 1288 pw.print(prefix); pw.print("rootWasReset="); pw.print(rootWasReset); 1289 pw.print(" mNeverRelinquishIdentity="); pw.print(mNeverRelinquishIdentity); 1290 pw.print(" mReuseTask="); pw.print(mReuseTask); 1291 pw.print(" mLockTaskAuth="); pw.println(lockTaskAuthToString()); 1292 } 1293 if (mAffiliatedTaskId != taskId || mPrevAffiliateTaskId != INVALID_TASK_ID 1294 || mPrevAffiliate != null || mNextAffiliateTaskId != INVALID_TASK_ID 1295 || mNextAffiliate != null) { 1296 pw.print(prefix); pw.print("affiliation="); pw.print(mAffiliatedTaskId); 1297 pw.print(" prevAffiliation="); pw.print(mPrevAffiliateTaskId); 1298 pw.print(" ("); 1299 if (mPrevAffiliate == null) { 1300 pw.print("null"); 1301 } else { 1302 pw.print(Integer.toHexString(System.identityHashCode(mPrevAffiliate))); 1303 } 1304 pw.print(") nextAffiliation="); pw.print(mNextAffiliateTaskId); 1305 pw.print(" ("); 1306 if (mNextAffiliate == null) { 1307 pw.print("null"); 1308 } else { 1309 pw.print(Integer.toHexString(System.identityHashCode(mNextAffiliate))); 1310 } 1311 pw.println(")"); 1312 } 1313 pw.print(prefix); pw.print("Activities="); pw.println(mActivities); 1314 if (!askedCompatMode || !inRecents || !isAvailable) { 1315 pw.print(prefix); pw.print("askedCompatMode="); pw.print(askedCompatMode); 1316 pw.print(" inRecents="); pw.print(inRecents); 1317 pw.print(" isAvailable="); pw.println(isAvailable); 1318 } 1319 pw.print(prefix); pw.print("lastThumbnail="); pw.print(mLastThumbnail); 1320 pw.print(" lastThumbnailFile="); pw.println(mLastThumbnailFile); 1321 if (lastDescription != null) { 1322 pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription); 1323 } 1324 if (stack != null) { 1325 pw.print(prefix); pw.print("stackId="); pw.println(stack.mStackId); 1326 } 1327 pw.print(prefix); pw.print("hasBeenVisible="); pw.print(hasBeenVisible); 1328 pw.print(" mResizeable="); pw.print(mResizeable); 1329 pw.print(" firstActiveTime="); pw.print(lastActiveTime); 1330 pw.print(" lastActiveTime="); pw.print(lastActiveTime); 1331 pw.print(" (inactive for "); 1332 pw.print((getInactiveDuration()/1000)); pw.println("s)"); 1333 } 1334 1335 @Override 1336 public String toString() { 1337 StringBuilder sb = new StringBuilder(128); 1338 if (stringName != null) { 1339 sb.append(stringName); 1340 sb.append(" U="); 1341 sb.append(userId); 1342 sb.append(" sz="); 1343 sb.append(mActivities.size()); 1344 sb.append('}'); 1345 return sb.toString(); 1346 } 1347 sb.append("TaskRecord{"); 1348 sb.append(Integer.toHexString(System.identityHashCode(this))); 1349 sb.append(" #"); 1350 sb.append(taskId); 1351 if (affinity != null) { 1352 sb.append(" A="); 1353 sb.append(affinity); 1354 } else if (intent != null) { 1355 sb.append(" I="); 1356 sb.append(intent.getComponent().flattenToShortString()); 1357 } else if (affinityIntent != null) { 1358 sb.append(" aI="); 1359 sb.append(affinityIntent.getComponent().flattenToShortString()); 1360 } else { 1361 sb.append(" ??"); 1362 } 1363 stringName = sb.toString(); 1364 return toString(); 1365 } 1366} 1367