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