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