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