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