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