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