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