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