TaskRecord.java revision 979f5ed923db91b08279bb25799c3d54d743d1a7
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     * Sets the last thumbnail.
482     * @return whether the thumbnail was set
483     */
484    boolean setLastThumbnail(Bitmap thumbnail) {
485        if (mLastThumbnail != thumbnail) {
486            mLastThumbnail = thumbnail;
487            if (thumbnail == null) {
488                if (mLastThumbnailFile != null) {
489                    mLastThumbnailFile.delete();
490                }
491            } else {
492                mService.mTaskPersister.saveImage(thumbnail, mFilename);
493            }
494            return true;
495        }
496        return false;
497    }
498
499    void getLastThumbnail(TaskThumbnail thumbs) {
500        thumbs.mainThumbnail = mLastThumbnail;
501        thumbs.thumbnailFileDescriptor = null;
502        if (mLastThumbnail == null) {
503            thumbs.mainThumbnail = mService.mTaskPersister.getImageFromWriteQueue(mFilename);
504        }
505        // Only load the thumbnail file if we don't have a thumbnail
506        if (thumbs.mainThumbnail == null && mLastThumbnailFile.exists()) {
507            try {
508                thumbs.thumbnailFileDescriptor = ParcelFileDescriptor.open(mLastThumbnailFile,
509                        ParcelFileDescriptor.MODE_READ_ONLY);
510            } catch (IOException e) {
511            }
512        }
513    }
514
515    void freeLastThumbnail() {
516        mLastThumbnail = null;
517    }
518
519    void disposeThumbnail() {
520        mLastThumbnail = null;
521        lastDescription = null;
522    }
523
524    /** Returns the intent for the root activity for this task */
525    Intent getBaseIntent() {
526        return intent != null ? intent : affinityIntent;
527    }
528
529    /** Returns the first non-finishing activity from the root. */
530    ActivityRecord getRootActivity() {
531        for (int i = 0; i < mActivities.size(); i++) {
532            final ActivityRecord r = mActivities.get(i);
533            if (r.finishing) {
534                continue;
535            }
536            return r;
537        }
538        return null;
539    }
540
541    ActivityRecord getTopActivity() {
542        for (int i = mActivities.size() - 1; i >= 0; --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 topRunningActivityLocked() {
553        if (stack != null) {
554            for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
555                ActivityRecord r = mActivities.get(activityNdx);
556                if (!r.finishing && stack.okToShowLocked(r)) {
557                    return r;
558                }
559            }
560        }
561        return null;
562    }
563
564    /** Call after activity movement or finish to make sure that frontOfTask is set correctly */
565    final void setFrontOfTask() {
566        boolean foundFront = false;
567        final int numActivities = mActivities.size();
568        for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
569            final ActivityRecord r = mActivities.get(activityNdx);
570            if (foundFront || r.finishing) {
571                r.frontOfTask = false;
572            } else {
573                r.frontOfTask = true;
574                // Set frontOfTask false for every following activity.
575                foundFront = true;
576            }
577        }
578        if (!foundFront && numActivities > 0) {
579            // All activities of this task are finishing. As we ought to have a frontOfTask
580            // activity, make the bottom activity front.
581            mActivities.get(0).frontOfTask = true;
582        }
583    }
584
585    /**
586     * Reorder the history stack so that the passed activity is brought to the front.
587     */
588    final void moveActivityToFrontLocked(ActivityRecord newTop) {
589        if (DEBUG_ADD_REMOVE) Slog.i(TAG_ADD_REMOVE,
590                "Removing and adding activity " + newTop
591                + " to stack at top callers=" + Debug.getCallers(4));
592
593        mActivities.remove(newTop);
594        mActivities.add(newTop);
595        updateEffectiveIntent();
596
597        setFrontOfTask();
598    }
599
600    void addActivityAtBottom(ActivityRecord r) {
601        addActivityAtIndex(0, r);
602    }
603
604    void addActivityToTop(ActivityRecord r) {
605        addActivityAtIndex(mActivities.size(), r);
606    }
607
608    void addActivityAtIndex(int index, ActivityRecord r) {
609        // Remove r first, and if it wasn't already in the list and it's fullscreen, count it.
610        if (!mActivities.remove(r) && r.fullscreen) {
611            // Was not previously in list.
612            numFullscreen++;
613        }
614        // Only set this based on the first activity
615        if (mActivities.isEmpty()) {
616            taskType = r.mActivityType;
617            isPersistable = r.isPersistable();
618            mCallingUid = r.launchedFromUid;
619            mCallingPackage = r.launchedFromPackage;
620            // Clamp to [1, max].
621            maxRecents = Math.min(Math.max(r.info.maxRecents, 1),
622                    ActivityManager.getMaxAppRecentsLimitStatic());
623        } else {
624            // Otherwise make all added activities match this one.
625            r.mActivityType = taskType;
626        }
627        mActivities.add(index, r);
628        updateEffectiveIntent();
629        if (r.isPersistable()) {
630            mService.notifyTaskPersisterLocked(this, false);
631        }
632    }
633
634    /** @return true if this was the last activity in the task */
635    boolean removeActivity(ActivityRecord r) {
636        if (mActivities.remove(r) && r.fullscreen) {
637            // Was previously in list.
638            numFullscreen--;
639        }
640        if (r.isPersistable()) {
641            mService.notifyTaskPersisterLocked(this, false);
642        }
643        if (mActivities.isEmpty()) {
644            return !mReuseTask;
645        }
646        updateEffectiveIntent();
647        return false;
648    }
649
650    boolean autoRemoveFromRecents() {
651        // We will automatically remove the task either if it has explicitly asked for
652        // this, or it is empty and has never contained an activity that got shown to
653        // the user.
654        return autoRemoveRecents || (mActivities.isEmpty() && !hasBeenVisible);
655    }
656
657    /**
658     * Completely remove all activities associated with an existing
659     * task starting at a specified index.
660     */
661    final void performClearTaskAtIndexLocked(int activityNdx) {
662        int numActivities = mActivities.size();
663        for ( ; activityNdx < numActivities; ++activityNdx) {
664            final ActivityRecord r = mActivities.get(activityNdx);
665            if (r.finishing) {
666                continue;
667            }
668            if (stack == null) {
669                // Task was restored from persistent storage.
670                r.takeFromHistory();
671                mActivities.remove(activityNdx);
672                --activityNdx;
673                --numActivities;
674            } else if (stack.finishActivityLocked(
675                    r, Activity.RESULT_CANCELED, null, "clear-task-index", false)) {
676                --activityNdx;
677                --numActivities;
678            }
679        }
680    }
681
682    /**
683     * Completely remove all activities associated with an existing task.
684     */
685    final void performClearTaskLocked() {
686        mReuseTask = true;
687        performClearTaskAtIndexLocked(0);
688        mReuseTask = false;
689    }
690
691    /**
692     * Perform clear operation as requested by
693     * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
694     * stack to the given task, then look for
695     * an instance of that activity in the stack and, if found, finish all
696     * activities on top of it and return the instance.
697     *
698     * @param newR Description of the new activity being started.
699     * @return Returns the old activity that should be continued to be used,
700     * or null if none was found.
701     */
702    final ActivityRecord performClearTaskLocked(ActivityRecord newR, int launchFlags) {
703        int numActivities = mActivities.size();
704        for (int activityNdx = numActivities - 1; activityNdx >= 0; --activityNdx) {
705            ActivityRecord r = mActivities.get(activityNdx);
706            if (r.finishing) {
707                continue;
708            }
709            if (r.realActivity.equals(newR.realActivity)) {
710                // Here it is!  Now finish everything in front...
711                final ActivityRecord ret = r;
712
713                for (++activityNdx; activityNdx < numActivities; ++activityNdx) {
714                    r = mActivities.get(activityNdx);
715                    if (r.finishing) {
716                        continue;
717                    }
718                    ActivityOptions opts = r.takeOptionsLocked();
719                    if (opts != null) {
720                        ret.updateOptionsLocked(opts);
721                    }
722                    if (stack != null && stack.finishActivityLocked(
723                            r, Activity.RESULT_CANCELED, null, "clear-task-stack", false)) {
724                        --activityNdx;
725                        --numActivities;
726                    }
727                }
728
729                // Finally, if this is a normal launch mode (that is, not
730                // expecting onNewIntent()), then we will finish the current
731                // instance of the activity so a new fresh one can be started.
732                if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
733                        && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
734                    if (!ret.finishing) {
735                        if (stack != null) {
736                            stack.finishActivityLocked(
737                                    ret, Activity.RESULT_CANCELED, null, "clear-task-top", false);
738                        }
739                        return null;
740                    }
741                }
742
743                return ret;
744            }
745        }
746
747        return null;
748    }
749
750    public TaskThumbnail getTaskThumbnailLocked() {
751        if (stack != null) {
752            final ActivityRecord resumedActivity = stack.mResumedActivity;
753            if (resumedActivity != null && resumedActivity.task == this) {
754                final Bitmap thumbnail = stack.screenshotActivities(resumedActivity);
755                setLastThumbnail(thumbnail);
756            }
757        }
758        final TaskThumbnail taskThumbnail = new TaskThumbnail();
759        getLastThumbnail(taskThumbnail);
760        return taskThumbnail;
761    }
762
763    public void removeTaskActivitiesLocked() {
764        // Just remove the entire task.
765        performClearTaskAtIndexLocked(0);
766    }
767
768    String lockTaskAuthToString() {
769        switch (mLockTaskAuth) {
770            case LOCK_TASK_AUTH_DONT_LOCK: return "LOCK_TASK_AUTH_DONT_LOCK";
771            case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE";
772            case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE";
773            case LOCK_TASK_AUTH_WHITELISTED: return "LOCK_TASK_AUTH_WHITELISTED";
774            case LOCK_TASK_AUTH_LAUNCHABLE_PRIV: return "LOCK_TASK_AUTH_LAUNCHABLE_PRIV";
775            default: return "unknown=" + mLockTaskAuth;
776        }
777    }
778
779    void setLockTaskAuth() {
780        if (!mPrivileged &&
781                (mLockTaskMode == LOCK_TASK_LAUNCH_MODE_ALWAYS ||
782                        mLockTaskMode == LOCK_TASK_LAUNCH_MODE_NEVER)) {
783            // Non-priv apps are not allowed to use always or never, fall back to default
784            mLockTaskMode = LOCK_TASK_LAUNCH_MODE_DEFAULT;
785        }
786        switch (mLockTaskMode) {
787            case LOCK_TASK_LAUNCH_MODE_DEFAULT:
788                mLockTaskAuth = isLockTaskWhitelistedLocked() ?
789                    LOCK_TASK_AUTH_WHITELISTED : LOCK_TASK_AUTH_PINNABLE;
790                break;
791
792            case LOCK_TASK_LAUNCH_MODE_NEVER:
793                mLockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK;
794                break;
795
796            case LOCK_TASK_LAUNCH_MODE_ALWAYS:
797                mLockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
798                break;
799
800            case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED:
801                mLockTaskAuth = isLockTaskWhitelistedLocked() ?
802                        LOCK_TASK_AUTH_LAUNCHABLE : LOCK_TASK_AUTH_PINNABLE;
803                break;
804        }
805        if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "setLockTaskAuth: task=" + this +
806                " mLockTaskAuth=" + lockTaskAuthToString());
807    }
808
809    boolean isLockTaskWhitelistedLocked() {
810        String pkg = (realActivity != null) ? realActivity.getPackageName() : null;
811        if (pkg == null) {
812            return false;
813        }
814        String[] packages = mService.mLockTaskPackages.get(userId);
815        if (packages == null) {
816            return false;
817        }
818        for (int i = packages.length - 1; i >= 0; --i) {
819            if (pkg.equals(packages[i])) {
820                return true;
821            }
822        }
823        return false;
824    }
825    boolean isHomeTask() {
826        return taskType == HOME_ACTIVITY_TYPE;
827    }
828
829    boolean isApplicationTask() {
830        return taskType == APPLICATION_ACTIVITY_TYPE;
831    }
832
833    boolean isOverHomeStack() {
834        return mTaskToReturnTo == HOME_ACTIVITY_TYPE || mTaskToReturnTo == RECENTS_ACTIVITY_TYPE;
835    }
836
837    /**
838     * Find the activity in the history stack within the given task.  Returns
839     * the index within the history at which it's found, or < 0 if not found.
840     */
841    final ActivityRecord findActivityInHistoryLocked(ActivityRecord r) {
842        final ComponentName realActivity = r.realActivity;
843        for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
844            ActivityRecord candidate = mActivities.get(activityNdx);
845            if (candidate.finishing) {
846                continue;
847            }
848            if (candidate.realActivity.equals(realActivity)) {
849                return candidate;
850            }
851        }
852        return null;
853    }
854
855    /** Updates the last task description values. */
856    void updateTaskDescription() {
857        // Traverse upwards looking for any break between main task activities and
858        // utility activities.
859        int activityNdx;
860        final int numActivities = mActivities.size();
861        final boolean relinquish = numActivities == 0 ? false :
862                (mActivities.get(0).info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) != 0;
863        for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities;
864                ++activityNdx) {
865            final ActivityRecord r = mActivities.get(activityNdx);
866            if (relinquish && (r.info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
867                // This will be the top activity for determining taskDescription. Pre-inc to
868                // overcome initial decrement below.
869                ++activityNdx;
870                break;
871            }
872            if (r.intent != null &&
873                    (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
874                break;
875            }
876        }
877        if (activityNdx > 0) {
878            // Traverse downwards starting below break looking for set label, icon.
879            // Note that if there are activities in the task but none of them set the
880            // recent activity values, then we do not fall back to the last set
881            // values in the TaskRecord.
882            String label = null;
883            String iconFilename = null;
884            int colorPrimary = 0;
885            for (--activityNdx; activityNdx >= 0; --activityNdx) {
886                final ActivityRecord r = mActivities.get(activityNdx);
887                if (r.taskDescription != null) {
888                    if (label == null) {
889                        label = r.taskDescription.getLabel();
890                    }
891                    if (iconFilename == null) {
892                        iconFilename = r.taskDescription.getIconFilename();
893                    }
894                    if (colorPrimary == 0) {
895                        colorPrimary = r.taskDescription.getPrimaryColor();
896                    }
897                }
898            }
899            lastTaskDescription = new TaskDescription(label, colorPrimary, iconFilename);
900            // Update the task affiliation color if we are the parent of the group
901            if (taskId == mAffiliatedTaskId) {
902                mAffiliatedTaskColor = lastTaskDescription.getPrimaryColor();
903            }
904        }
905    }
906
907    int findEffectiveRootIndex() {
908        int effectiveNdx = 0;
909        final int topActivityNdx = mActivities.size() - 1;
910        for (int activityNdx = 0; activityNdx <= topActivityNdx; ++activityNdx) {
911            final ActivityRecord r = mActivities.get(activityNdx);
912            if (r.finishing) {
913                continue;
914            }
915            effectiveNdx = activityNdx;
916            if ((r.info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
917                break;
918            }
919        }
920        return effectiveNdx;
921    }
922
923    void updateEffectiveIntent() {
924        final int effectiveRootIndex = findEffectiveRootIndex();
925        final ActivityRecord r = mActivities.get(effectiveRootIndex);
926        setIntent(r);
927    }
928
929    void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
930        if (DEBUG_RECENTS) Slog.i(TAG_RECENTS, "Saving task=" + this);
931
932        out.attribute(null, ATTR_TASKID, String.valueOf(taskId));
933        if (realActivity != null) {
934            out.attribute(null, ATTR_REALACTIVITY, realActivity.flattenToShortString());
935        }
936        if (origActivity != null) {
937            out.attribute(null, ATTR_ORIGACTIVITY, origActivity.flattenToShortString());
938        }
939        // Write affinity, and root affinity if it is different from affinity.
940        // We use the special string "@" for a null root affinity, so we can identify
941        // later whether we were given a root affinity or should just make it the
942        // same as the affinity.
943        if (affinity != null) {
944            out.attribute(null, ATTR_AFFINITY, affinity);
945            if (!affinity.equals(rootAffinity)) {
946                out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
947            }
948        } else if (rootAffinity != null) {
949            out.attribute(null, ATTR_ROOT_AFFINITY, rootAffinity != null ? rootAffinity : "@");
950        }
951        out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset));
952        out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents));
953        out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode));
954        out.attribute(null, ATTR_USERID, String.valueOf(userId));
955        out.attribute(null, ATTR_EFFECTIVE_UID, String.valueOf(effectiveUid));
956        out.attribute(null, ATTR_TASKTYPE, String.valueOf(taskType));
957        out.attribute(null, ATTR_FIRSTACTIVETIME, String.valueOf(firstActiveTime));
958        out.attribute(null, ATTR_LASTACTIVETIME, String.valueOf(lastActiveTime));
959        out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved));
960        out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity));
961        if (lastDescription != null) {
962            out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
963        }
964        if (lastTaskDescription != null) {
965            lastTaskDescription.saveToXml(out);
966        }
967        out.attribute(null, ATTR_TASK_AFFILIATION_COLOR, String.valueOf(mAffiliatedTaskColor));
968        out.attribute(null, ATTR_TASK_AFFILIATION, String.valueOf(mAffiliatedTaskId));
969        out.attribute(null, ATTR_PREV_AFFILIATION, String.valueOf(mPrevAffiliateTaskId));
970        out.attribute(null, ATTR_NEXT_AFFILIATION, String.valueOf(mNextAffiliateTaskId));
971        out.attribute(null, ATTR_CALLING_UID, String.valueOf(mCallingUid));
972        out.attribute(null, ATTR_CALLING_PACKAGE, mCallingPackage == null ? "" : mCallingPackage);
973        out.attribute(null, ATTR_RESIZEABLE, String.valueOf(mResizeable));
974        out.attribute(null, ATTR_PRIVILEGED, String.valueOf(mPrivileged));
975        if (mLastNonFullscreenBounds != null) {
976            out.attribute(
977                    null, ATTR_NON_FULLSCREEN_BOUNDS, mLastNonFullscreenBounds.flattenToString());
978        }
979
980        if (affinityIntent != null) {
981            out.startTag(null, TAG_AFFINITYINTENT);
982            affinityIntent.saveToXml(out);
983            out.endTag(null, TAG_AFFINITYINTENT);
984        }
985
986        out.startTag(null, TAG_INTENT);
987        intent.saveToXml(out);
988        out.endTag(null, TAG_INTENT);
989
990        final ArrayList<ActivityRecord> activities = mActivities;
991        final int numActivities = activities.size();
992        for (int activityNdx = 0; activityNdx < numActivities; ++activityNdx) {
993            final ActivityRecord r = activities.get(activityNdx);
994            if (r.info.persistableMode == ActivityInfo.PERSIST_ROOT_ONLY || !r.isPersistable() ||
995                    ((r.intent.getFlags() & FLAG_ACTIVITY_NEW_DOCUMENT
996                            | FLAG_ACTIVITY_RETAIN_IN_RECENTS) == FLAG_ACTIVITY_NEW_DOCUMENT) &&
997                            activityNdx > 0) {
998                // Stop at first non-persistable or first break in task (CLEAR_WHEN_TASK_RESET).
999                break;
1000            }
1001            out.startTag(null, TAG_ACTIVITY);
1002            r.saveToXml(out);
1003            out.endTag(null, TAG_ACTIVITY);
1004        }
1005    }
1006
1007    static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
1008            throws IOException, XmlPullParserException {
1009        Intent intent = null;
1010        Intent affinityIntent = null;
1011        ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>();
1012        ComponentName realActivity = null;
1013        ComponentName origActivity = null;
1014        String affinity = null;
1015        String rootAffinity = null;
1016        boolean hasRootAffinity = false;
1017        boolean rootHasReset = false;
1018        boolean autoRemoveRecents = false;
1019        boolean askedCompatMode = false;
1020        int taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE;
1021        int userId = 0;
1022        int effectiveUid = -1;
1023        String lastDescription = null;
1024        long firstActiveTime = -1;
1025        long lastActiveTime = -1;
1026        long lastTimeOnTop = 0;
1027        boolean neverRelinquishIdentity = true;
1028        int taskId = INVALID_TASK_ID;
1029        final int outerDepth = in.getDepth();
1030        TaskDescription taskDescription = new TaskDescription();
1031        int taskAffiliation = INVALID_TASK_ID;
1032        int taskAffiliationColor = 0;
1033        int prevTaskId = INVALID_TASK_ID;
1034        int nextTaskId = INVALID_TASK_ID;
1035        int callingUid = -1;
1036        String callingPackage = "";
1037        boolean resizeable = false;
1038        boolean privileged = false;
1039        Rect bounds = null;
1040
1041        for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
1042            final String attrName = in.getAttributeName(attrNdx);
1043            final String attrValue = in.getAttributeValue(attrNdx);
1044            if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: attribute name=" +
1045                    attrName + " value=" + attrValue);
1046            if (ATTR_TASKID.equals(attrName)) {
1047                if (taskId == INVALID_TASK_ID) taskId = Integer.valueOf(attrValue);
1048            } else if (ATTR_REALACTIVITY.equals(attrName)) {
1049                realActivity = ComponentName.unflattenFromString(attrValue);
1050            } else if (ATTR_ORIGACTIVITY.equals(attrName)) {
1051                origActivity = ComponentName.unflattenFromString(attrValue);
1052            } else if (ATTR_AFFINITY.equals(attrName)) {
1053                affinity = attrValue;
1054            } else if (ATTR_ROOT_AFFINITY.equals(attrName)) {
1055                rootAffinity = attrValue;
1056                hasRootAffinity = true;
1057            } else if (ATTR_ROOTHASRESET.equals(attrName)) {
1058                rootHasReset = Boolean.valueOf(attrValue);
1059            } else if (ATTR_AUTOREMOVERECENTS.equals(attrName)) {
1060                autoRemoveRecents = Boolean.valueOf(attrValue);
1061            } else if (ATTR_ASKEDCOMPATMODE.equals(attrName)) {
1062                askedCompatMode = Boolean.valueOf(attrValue);
1063            } else if (ATTR_USERID.equals(attrName)) {
1064                userId = Integer.valueOf(attrValue);
1065            } else if (ATTR_EFFECTIVE_UID.equals(attrName)) {
1066                effectiveUid = Integer.valueOf(attrValue);
1067            } else if (ATTR_TASKTYPE.equals(attrName)) {
1068                taskType = Integer.valueOf(attrValue);
1069            } else if (ATTR_FIRSTACTIVETIME.equals(attrName)) {
1070                firstActiveTime = Long.valueOf(attrValue);
1071            } else if (ATTR_LASTACTIVETIME.equals(attrName)) {
1072                lastActiveTime = Long.valueOf(attrValue);
1073            } else if (ATTR_LASTDESCRIPTION.equals(attrName)) {
1074                lastDescription = attrValue;
1075            } else if (ATTR_LASTTIMEMOVED.equals(attrName)) {
1076                lastTimeOnTop = Long.valueOf(attrValue);
1077            } else if (ATTR_NEVERRELINQUISH.equals(attrName)) {
1078                neverRelinquishIdentity = Boolean.valueOf(attrValue);
1079            } else if (attrName.startsWith(TaskDescription.ATTR_TASKDESCRIPTION_PREFIX)) {
1080                taskDescription.restoreFromXml(attrName, attrValue);
1081            } else if (ATTR_TASK_AFFILIATION.equals(attrName)) {
1082                taskAffiliation = Integer.valueOf(attrValue);
1083            } else if (ATTR_PREV_AFFILIATION.equals(attrName)) {
1084                prevTaskId = Integer.valueOf(attrValue);
1085            } else if (ATTR_NEXT_AFFILIATION.equals(attrName)) {
1086                nextTaskId = Integer.valueOf(attrValue);
1087            } else if (ATTR_TASK_AFFILIATION_COLOR.equals(attrName)) {
1088                taskAffiliationColor = Integer.valueOf(attrValue);
1089            } else if (ATTR_CALLING_UID.equals(attrName)) {
1090                callingUid = Integer.valueOf(attrValue);
1091            } else if (ATTR_CALLING_PACKAGE.equals(attrName)) {
1092                callingPackage = attrValue;
1093            } else if (ATTR_RESIZEABLE.equals(attrName)) {
1094                resizeable = Boolean.valueOf(attrValue);
1095            } else if (ATTR_PRIVILEGED.equals(attrName)) {
1096                privileged = Boolean.valueOf(attrValue);
1097            } else if (ATTR_NON_FULLSCREEN_BOUNDS.equals(attrName)) {
1098                bounds = Rect.unflattenFromString(attrValue);
1099            } else {
1100                Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName);
1101            }
1102        }
1103
1104        int event;
1105        while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
1106                (event != XmlPullParser.END_TAG || in.getDepth() >= outerDepth)) {
1107            if (event == XmlPullParser.START_TAG) {
1108                final String name = in.getName();
1109                if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: START_TAG name=" +
1110                        name);
1111                if (TAG_AFFINITYINTENT.equals(name)) {
1112                    affinityIntent = Intent.restoreFromXml(in);
1113                } else if (TAG_INTENT.equals(name)) {
1114                    intent = Intent.restoreFromXml(in);
1115                } else if (TAG_ACTIVITY.equals(name)) {
1116                    ActivityRecord activity = ActivityRecord.restoreFromXml(in, stackSupervisor);
1117                    if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: activity=" +
1118                            activity);
1119                    if (activity != null) {
1120                        activities.add(activity);
1121                    }
1122                } else {
1123                    Slog.e(TAG, "restoreTask: Unexpected name=" + name);
1124                    XmlUtils.skipCurrentTag(in);
1125                }
1126            }
1127        }
1128        if (!hasRootAffinity) {
1129            rootAffinity = affinity;
1130        } else if ("@".equals(rootAffinity)) {
1131            rootAffinity = null;
1132        }
1133        if (effectiveUid <= 0) {
1134            Intent checkIntent = intent != null ? intent : affinityIntent;
1135            effectiveUid = 0;
1136            if (checkIntent != null) {
1137                IPackageManager pm = AppGlobals.getPackageManager();
1138                try {
1139                    ApplicationInfo ai = pm.getApplicationInfo(
1140                            checkIntent.getComponent().getPackageName(),
1141                            PackageManager.GET_UNINSTALLED_PACKAGES
1142                                    | PackageManager.GET_DISABLED_COMPONENTS, userId);
1143                    if (ai != null) {
1144                        effectiveUid = ai.uid;
1145                    }
1146                } catch (RemoteException e) {
1147                }
1148            }
1149            Slog.w(TAG, "Updating task #" + taskId + " for " + checkIntent
1150                    + ": effectiveUid=" + effectiveUid);
1151        }
1152
1153        final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent,
1154                affinityIntent, affinity, rootAffinity, realActivity, origActivity, rootHasReset,
1155                autoRemoveRecents, askedCompatMode, taskType, userId, effectiveUid, lastDescription,
1156                activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity,
1157                taskDescription, taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor,
1158                callingUid, callingPackage, resizeable, privileged);
1159        task.updateOverrideConfiguration(bounds);
1160
1161        for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
1162            activities.get(activityNdx).task = task;
1163        }
1164
1165        if (DEBUG_RECENTS) Slog.d(TAG_RECENTS, "Restored task=" + task);
1166        return task;
1167    }
1168
1169    /**
1170     * Update task's override configuration based on the bounds.
1171     * @return Update configuration or null if there is no change.
1172     */
1173    Configuration updateOverrideConfiguration(Rect bounds) {
1174        if (Objects.equals(mBounds, bounds)) {
1175            return null;
1176        }
1177        Configuration oldConfig = mOverrideConfig;
1178
1179        mFullscreen = bounds == null;
1180        if (mFullscreen) {
1181            if (mBounds != null && stack.mStackId != DOCKED_STACK_ID) {
1182                mLastNonFullscreenBounds = mBounds;
1183            }
1184            mBounds = null;
1185            mOverrideConfig = Configuration.EMPTY;
1186        } else {
1187            mBounds = new Rect(bounds);
1188            if (stack == null || stack.mStackId != DOCKED_STACK_ID) {
1189                mLastNonFullscreenBounds = mBounds;
1190            }
1191
1192            final Configuration serviceConfig = mService.mConfiguration;
1193            mOverrideConfig = new Configuration(serviceConfig);
1194            // TODO(multidisplay): Update Dp to that of display stack is on.
1195            final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
1196            mOverrideConfig.screenWidthDp =
1197                    Math.min((int)(mBounds.width() / density), serviceConfig.screenWidthDp);
1198            mOverrideConfig.screenHeightDp =
1199                    Math.min((int)(mBounds.height() / density), serviceConfig.screenHeightDp);
1200            mOverrideConfig.smallestScreenWidthDp =
1201                    Math.min(mOverrideConfig.screenWidthDp, mOverrideConfig.screenHeightDp);
1202            mOverrideConfig.orientation =
1203                    (mOverrideConfig.screenWidthDp <= mOverrideConfig.screenHeightDp)
1204                            ? Configuration.ORIENTATION_PORTRAIT
1205                            : Configuration.ORIENTATION_LANDSCAPE;
1206        }
1207        return !mOverrideConfig.equals(oldConfig) ? mOverrideConfig : null;
1208    }
1209
1210    /**
1211     * Returns the correct stack to use based on task type and currently set bounds,
1212     * regardless of the focused stack and current stack association of the task.
1213     * The task will be moved (and stack focus changed) later if necessary.
1214     */
1215    int getLaunchStackId() {
1216        if (!isApplicationTask()) {
1217            return HOME_STACK_ID;
1218        }
1219        if (mBounds != null) {
1220            return FREEFORM_WORKSPACE_STACK_ID;
1221        }
1222        return FULLSCREEN_WORKSPACE_STACK_ID;
1223    }
1224
1225    /** Returns the bounds that should be used to launch this task. */
1226    Rect getLaunchBounds() {
1227        if (stack == null
1228                || stack.mStackId == HOME_STACK_ID
1229                || stack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID) {
1230            return (mResizeable && stack != null) ? stack.mBounds : null;
1231        } else if (stack.mStackId == DOCKED_STACK_ID) {
1232            return stack.mBounds;
1233        }
1234        return mLastNonFullscreenBounds;
1235    }
1236
1237    void dump(PrintWriter pw, String prefix) {
1238        pw.print(prefix); pw.print("userId="); pw.print(userId);
1239                pw.print(" effectiveUid="); UserHandle.formatUid(pw, effectiveUid);
1240                pw.print(" mCallingUid="); UserHandle.formatUid(pw, mCallingUid);
1241                pw.print(" mCallingPackage="); pw.println(mCallingPackage);
1242        if (affinity != null || rootAffinity != null) {
1243            pw.print(prefix); pw.print("affinity="); pw.print(affinity);
1244            if (affinity == null || !affinity.equals(rootAffinity)) {
1245                pw.print(" root="); pw.println(rootAffinity);
1246            } else {
1247                pw.println();
1248            }
1249        }
1250        if (voiceSession != null || voiceInteractor != null) {
1251            pw.print(prefix); pw.print("VOICE: session=0x");
1252            pw.print(Integer.toHexString(System.identityHashCode(voiceSession)));
1253            pw.print(" interactor=0x");
1254            pw.println(Integer.toHexString(System.identityHashCode(voiceInteractor)));
1255        }
1256        if (intent != null) {
1257            StringBuilder sb = new StringBuilder(128);
1258            sb.append(prefix); sb.append("intent={");
1259            intent.toShortString(sb, false, true, false, true);
1260            sb.append('}');
1261            pw.println(sb.toString());
1262        }
1263        if (affinityIntent != null) {
1264            StringBuilder sb = new StringBuilder(128);
1265            sb.append(prefix); sb.append("affinityIntent={");
1266            affinityIntent.toShortString(sb, false, true, false, true);
1267            sb.append('}');
1268            pw.println(sb.toString());
1269        }
1270        if (origActivity != null) {
1271            pw.print(prefix); pw.print("origActivity=");
1272            pw.println(origActivity.flattenToShortString());
1273        }
1274        if (realActivity != null) {
1275            pw.print(prefix); pw.print("realActivity=");
1276            pw.println(realActivity.flattenToShortString());
1277        }
1278        if (autoRemoveRecents || isPersistable || taskType != 0 || mTaskToReturnTo != 0
1279                || numFullscreen != 0) {
1280            pw.print(prefix); pw.print("autoRemoveRecents="); pw.print(autoRemoveRecents);
1281                    pw.print(" isPersistable="); pw.print(isPersistable);
1282                    pw.print(" numFullscreen="); pw.print(numFullscreen);
1283                    pw.print(" taskType="); pw.print(taskType);
1284                    pw.print(" mTaskToReturnTo="); pw.println(mTaskToReturnTo);
1285        }
1286        if (rootWasReset || mNeverRelinquishIdentity || mReuseTask
1287                || mLockTaskAuth != LOCK_TASK_AUTH_PINNABLE) {
1288            pw.print(prefix); pw.print("rootWasReset="); pw.print(rootWasReset);
1289                    pw.print(" mNeverRelinquishIdentity="); pw.print(mNeverRelinquishIdentity);
1290                    pw.print(" mReuseTask="); pw.print(mReuseTask);
1291                    pw.print(" mLockTaskAuth="); pw.println(lockTaskAuthToString());
1292        }
1293        if (mAffiliatedTaskId != taskId || mPrevAffiliateTaskId != INVALID_TASK_ID
1294                || mPrevAffiliate != null || mNextAffiliateTaskId != INVALID_TASK_ID
1295                || mNextAffiliate != null) {
1296            pw.print(prefix); pw.print("affiliation="); pw.print(mAffiliatedTaskId);
1297                    pw.print(" prevAffiliation="); pw.print(mPrevAffiliateTaskId);
1298                    pw.print(" (");
1299                    if (mPrevAffiliate == null) {
1300                        pw.print("null");
1301                    } else {
1302                        pw.print(Integer.toHexString(System.identityHashCode(mPrevAffiliate)));
1303                    }
1304                    pw.print(") nextAffiliation="); pw.print(mNextAffiliateTaskId);
1305                    pw.print(" (");
1306                    if (mNextAffiliate == null) {
1307                        pw.print("null");
1308                    } else {
1309                        pw.print(Integer.toHexString(System.identityHashCode(mNextAffiliate)));
1310                    }
1311                    pw.println(")");
1312        }
1313        pw.print(prefix); pw.print("Activities="); pw.println(mActivities);
1314        if (!askedCompatMode || !inRecents || !isAvailable) {
1315            pw.print(prefix); pw.print("askedCompatMode="); pw.print(askedCompatMode);
1316                    pw.print(" inRecents="); pw.print(inRecents);
1317                    pw.print(" isAvailable="); pw.println(isAvailable);
1318        }
1319        pw.print(prefix); pw.print("lastThumbnail="); pw.print(mLastThumbnail);
1320                pw.print(" lastThumbnailFile="); pw.println(mLastThumbnailFile);
1321        if (lastDescription != null) {
1322            pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription);
1323        }
1324        if (stack != null) {
1325            pw.print(prefix); pw.print("stackId="); pw.println(stack.mStackId);
1326        }
1327        pw.print(prefix); pw.print("hasBeenVisible="); pw.print(hasBeenVisible);
1328                pw.print(" mResizeable="); pw.print(mResizeable);
1329                pw.print(" firstActiveTime="); pw.print(lastActiveTime);
1330                pw.print(" lastActiveTime="); pw.print(lastActiveTime);
1331                pw.print(" (inactive for ");
1332                pw.print((getInactiveDuration()/1000)); pw.println("s)");
1333    }
1334
1335    @Override
1336    public String toString() {
1337        StringBuilder sb = new StringBuilder(128);
1338        if (stringName != null) {
1339            sb.append(stringName);
1340            sb.append(" U=");
1341            sb.append(userId);
1342            sb.append(" sz=");
1343            sb.append(mActivities.size());
1344            sb.append('}');
1345            return sb.toString();
1346        }
1347        sb.append("TaskRecord{");
1348        sb.append(Integer.toHexString(System.identityHashCode(this)));
1349        sb.append(" #");
1350        sb.append(taskId);
1351        if (affinity != null) {
1352            sb.append(" A=");
1353            sb.append(affinity);
1354        } else if (intent != null) {
1355            sb.append(" I=");
1356            sb.append(intent.getComponent().flattenToShortString());
1357        } else if (affinityIntent != null) {
1358            sb.append(" aI=");
1359            sb.append(affinityIntent.getComponent().flattenToShortString());
1360        } else {
1361            sb.append(" ??");
1362        }
1363        stringName = sb.toString();
1364        return toString();
1365    }
1366}
1367