121d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner/*
221d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner * Copyright (C) 2014 The Android Open Source Project
321d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner *
421d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner * Licensed under the Apache License, Version 2.0 (the "License");
521d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner * you may not use this file except in compliance with the License.
621d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner * You may obtain a copy of the License at
721d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner *
821d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner *      http://www.apache.org/licenses/LICENSE-2.0
921d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner *
1021d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner * Unless required by applicable law or agreed to in writing, software
1121d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner * distributed under the License is distributed on an "AS IS" BASIS,
1221d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1321d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner * See the License for the specific language governing permissions and
1421d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner * limitations under the License.
1521d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner */
1621d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
1721d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautnerpackage com.android.server.am;
1821d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
1918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwaleimport android.app.ActivityManager;
2018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwaleimport android.app.AppGlobals;
2118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwaleimport android.content.ComponentName;
2218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwaleimport android.content.pm.IPackageManager;
2321d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautnerimport android.graphics.Bitmap;
2421d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautnerimport android.graphics.BitmapFactory;
2521d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautnerimport android.os.Debug;
2618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwaleimport android.os.RemoteException;
2721d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautnerimport android.os.SystemClock;
2818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwaleimport android.os.UserHandle;
2918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwaleimport android.text.format.DateUtils;
3018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwaleimport android.util.ArrayMap;
3121d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautnerimport android.util.ArraySet;
3221d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautnerimport android.util.AtomicFile;
3321d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautnerimport android.util.Slog;
3418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwaleimport android.util.SparseArray;
3521d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautnerimport android.util.Xml;
3618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
3721d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautnerimport com.android.internal.util.FastXmlSerializer;
3821d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautnerimport com.android.internal.util.XmlUtils;
3918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
4021d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautnerimport org.xmlpull.v1.XmlPullParser;
4121d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautnerimport org.xmlpull.v1.XmlPullParserException;
4221d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautnerimport org.xmlpull.v1.XmlSerializer;
4321d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
4421d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautnerimport java.io.BufferedReader;
4521d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautnerimport java.io.File;
4621d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautnerimport java.io.FileOutputStream;
4721d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautnerimport java.io.FileReader;
4821d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautnerimport java.io.IOException;
4921d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautnerimport java.io.StringWriter;
5021d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautnerimport java.util.ArrayList;
5121d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautnerimport java.util.Arrays;
5218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwaleimport java.util.Collections;
5321d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautnerimport java.util.Comparator;
5418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwaleimport java.util.List;
5518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
5618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwaleimport libcore.io.IoUtils;
5718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
5818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwaleimport static com.android.server.am.TaskRecord.INVALID_TASK_ID;
5921d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
6021d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautnerpublic class TaskPersister {
6121d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner    static final String TAG = "TaskPersister";
6218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    static final boolean DEBUG_PERSISTER = false;
6318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    static final boolean DEBUG_RESTORER = false;
6421d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
65f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner    /** When not flushing don't write out files faster than this */
66f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner    private static final long INTER_WRITE_DELAY_MS = 500;
67f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner
68f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner    /** When not flushing delay this long before writing the first file out. This gives the next
69f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner     * task being launched a chance to load its resources without this occupying IO bandwidth. */
70f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner    private static final long PRE_TASK_DELAY_MS = 3000;
7121d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
7263f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner    /** The maximum number of entries to keep in the queue before draining it automatically. */
7363f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner    private static final int MAX_WRITE_QUEUE_LENGTH = 6;
7463f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner
7563f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner    /** Special value for mWriteTime to mean don't wait, just write */
7663f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner    private static final long FLUSH_QUEUE = -1;
7763f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner
7821d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner    private static final String RECENTS_FILENAME = "_task";
7921d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner    private static final String TASKS_DIRNAME = "recent_tasks";
8021d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner    private static final String TASK_EXTENSION = ".xml";
8121d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner    private static final String IMAGES_DIRNAME = "recent_images";
82c0ffce5ddd6446f1d46a49cdfaeda4a2ce408e1dCraig Mautner    static final String IMAGE_EXTENSION = ".png";
8321d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
84ac6a3a5e9d90edb533e5b377a4a14ef514be955aChristopher Tate    // Directory where restored historical task XML/PNG files are placed.  This directory
85ac6a3a5e9d90edb533e5b377a4a14ef514be955aChristopher Tate    // contains subdirs named after TASKS_DIRNAME and IMAGES_DIRNAME mirroring the
86ac6a3a5e9d90edb533e5b377a4a14ef514be955aChristopher Tate    // ancestral device's dataset.  This needs to match the RECENTS_TASK_RESTORE_DIR
87ac6a3a5e9d90edb533e5b377a4a14ef514be955aChristopher Tate    // value in RecentsBackupHelper.
8818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    private static final String RESTORED_TASKS_DIRNAME = "restored_" + TASKS_DIRNAME;
8918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
9018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    // Max time to wait for the application/package of a restored task to be installed
9118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    // before giving up.
9218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    private static final long MAX_INSTALL_WAIT_TIME = DateUtils.DAY_IN_MILLIS;
93ac6a3a5e9d90edb533e5b377a4a14ef514be955aChristopher Tate
9421d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner    private static final String TAG_TASK = "task";
9521d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
96c0ffce5ddd6446f1d46a49cdfaeda4a2ce408e1dCraig Mautner    static File sImagesDir;
97c0ffce5ddd6446f1d46a49cdfaeda4a2ce408e1dCraig Mautner    static File sTasksDir;
9818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    static File sRestoredTasksDir;
9921d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
10021d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner    private final ActivityManagerService mService;
10121d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner    private final ActivityStackSupervisor mStackSupervisor;
10221d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
103f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner    /** Value determines write delay mode as follows:
104f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner     *    < 0 We are Flushing. No delays between writes until the image queue is drained and all
105f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner     * tasks needing persisting are written to disk. There is no delay between writes.
106f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner     *    == 0 We are Idle. Next writes will be delayed by #PRE_TASK_DELAY_MS.
107f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner     *    > 0 We are Actively writing. Next write will be at this time. Subsequent writes will be
108f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner     * delayed by #INTER_WRITE_DELAY_MS. */
109f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner    private long mNextWriteTime = 0;
11021d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
11121d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner    private final LazyTaskWriterThread mLazyTaskWriterThread;
11221d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
113f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner    private static class WriteQueueItem {}
114f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner    private static class TaskWriteQueueItem extends WriteQueueItem {
115f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner        final TaskRecord mTask;
116f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner        TaskWriteQueueItem(TaskRecord task) {
117f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner            mTask = task;
118f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner        }
119f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner    }
120f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner    private static class ImageWriteQueueItem extends WriteQueueItem {
121f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner        final String mFilename;
122f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner        Bitmap mImage;
123f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner        ImageWriteQueueItem(String filename, Bitmap image) {
124f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner            mFilename = filename;
125f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner            mImage = image;
126f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner        }
127f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner    }
128f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner
129f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner    ArrayList<WriteQueueItem> mWriteQueue = new ArrayList<WriteQueueItem>();
130f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner
13118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    // Map of tasks that were backed-up on a different device that can be restored on this device.
13218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    // Data organization: <packageNameOfAffiliateTask, listOfAffiliatedTasksChains>
13318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    private ArrayMap<String, List<List<OtherDeviceTask>>> mOtherDeviceTasksMap =
13418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                new ArrayMap<>(10);
13592dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale    // Local cache of package names to uid used when restoring a task from another device.
13692dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale    private ArrayMap<String, Integer> mPackageUidMap;
13718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
13818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    // The next time in milliseconds we will remove expired task from
13918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    // {@link #mOtherDeviceTasksMap} and disk. Set to {@link Long.MAX_VALUE} to never clean-up
14018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    // tasks.
14118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    private long mExpiredTasksCleanupTime = Long.MAX_VALUE;
14218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
14321d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner    TaskPersister(File systemDir, ActivityStackSupervisor stackSupervisor) {
14421d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        sTasksDir = new File(systemDir, TASKS_DIRNAME);
14521d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        if (!sTasksDir.exists()) {
14618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            if (DEBUG_PERSISTER) Slog.d(TAG, "Creating tasks directory " + sTasksDir);
14721d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner            if (!sTasksDir.mkdir()) {
14821d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                Slog.e(TAG, "Failure creating tasks directory " + sTasksDir);
14921d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner            }
15021d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        }
15121d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
15221d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        sImagesDir = new File(systemDir, IMAGES_DIRNAME);
15321d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        if (!sImagesDir.exists()) {
15418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            if (DEBUG_PERSISTER) Slog.d(TAG, "Creating images directory " + sTasksDir);
15521d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner            if (!sImagesDir.mkdir()) {
15621d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                Slog.e(TAG, "Failure creating images directory " + sImagesDir);
15721d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner            }
15821d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        }
15921d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
16018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        sRestoredTasksDir = new File(systemDir, RESTORED_TASKS_DIRNAME);
16118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
16221d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        mStackSupervisor = stackSupervisor;
16321d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        mService = stackSupervisor.mService;
16421d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
16521d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        mLazyTaskWriterThread = new LazyTaskWriterThread("LazyTaskWriterThread");
16621d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner    }
16721d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
16821d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner    void startPersisting() {
16921d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        mLazyTaskWriterThread.start();
17021d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner    }
17121d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
17263f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner    private void removeThumbnails(TaskRecord task) {
17363f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner        final String taskString = Integer.toString(task.taskId);
17463f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner        for (int queueNdx = mWriteQueue.size() - 1; queueNdx >= 0; --queueNdx) {
17563f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner            final WriteQueueItem item = mWriteQueue.get(queueNdx);
17663f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner            if (item instanceof ImageWriteQueueItem &&
17763f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner                    ((ImageWriteQueueItem) item).mFilename.startsWith(taskString)) {
17818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                if (DEBUG_PERSISTER) Slog.d(TAG, "Removing "
17918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        + ((ImageWriteQueueItem) item).mFilename + " from write queue");
18063f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner                mWriteQueue.remove(queueNdx);
18163f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner            }
18263f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner        }
18363f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner    }
18463f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner
18563f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner    private void yieldIfQueueTooDeep() {
18663f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner        boolean stall = false;
18763f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner        synchronized (this) {
18863f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner            if (mNextWriteTime == FLUSH_QUEUE) {
18963f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner                stall = true;
19063f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner            }
19163f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner        }
19263f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner        if (stall) {
19363f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner            Thread.yield();
19463f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner        }
19563f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner    }
19663f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner
197f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner    void wakeup(TaskRecord task, boolean flush) {
198f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner        synchronized (this) {
199f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner            if (task != null) {
200f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                int queueNdx;
201f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                for (queueNdx = mWriteQueue.size() - 1; queueNdx >= 0; --queueNdx) {
202f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                    final WriteQueueItem item = mWriteQueue.get(queueNdx);
203f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                    if (item instanceof TaskWriteQueueItem &&
204f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                            ((TaskWriteQueueItem) item).mTask == task) {
20563f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner                        if (!task.inRecents) {
20663f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner                            // This task is being removed.
20763f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner                            removeThumbnails(task);
20863f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner                        }
209f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                        break;
210f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                    }
211f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                }
212be23ff4949612ecea89d112eff7f5e2c3dbf7685Wale Ogunwale                if (queueNdx < 0 && task.isPersistable) {
213f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                    mWriteQueue.add(new TaskWriteQueueItem(task));
214f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                }
215f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner            } else {
216f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                // Dummy.
217f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                mWriteQueue.add(new WriteQueueItem());
218f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner            }
21963f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner            if (flush || mWriteQueue.size() > MAX_WRITE_QUEUE_LENGTH) {
22063f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner                mNextWriteTime = FLUSH_QUEUE;
221f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner            } else if (mNextWriteTime == 0) {
222f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                mNextWriteTime = SystemClock.uptimeMillis() + PRE_TASK_DELAY_MS;
223f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner            }
22418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            if (DEBUG_PERSISTER) Slog.d(TAG, "wakeup: task=" + task + " flush=" + flush
22518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    + " mNextWriteTime=" + mNextWriteTime + " mWriteQueue.size="
22618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    + mWriteQueue.size() + " Callers=" + Debug.getCallers(4));
227f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner            notifyAll();
22821d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        }
22963f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner
23063f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner        yieldIfQueueTooDeep();
231f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner    }
232f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner
233ce0fd7665f297c5693ee23b3d6daf26baeed4e9dDianne Hackborn    void flush() {
234ce0fd7665f297c5693ee23b3d6daf26baeed4e9dDianne Hackborn        synchronized (this) {
235ce0fd7665f297c5693ee23b3d6daf26baeed4e9dDianne Hackborn            mNextWriteTime = FLUSH_QUEUE;
236ce0fd7665f297c5693ee23b3d6daf26baeed4e9dDianne Hackborn            notifyAll();
237ce0fd7665f297c5693ee23b3d6daf26baeed4e9dDianne Hackborn            do {
238ce0fd7665f297c5693ee23b3d6daf26baeed4e9dDianne Hackborn                try {
239ce0fd7665f297c5693ee23b3d6daf26baeed4e9dDianne Hackborn                    wait();
240ce0fd7665f297c5693ee23b3d6daf26baeed4e9dDianne Hackborn                } catch (InterruptedException e) {
241ce0fd7665f297c5693ee23b3d6daf26baeed4e9dDianne Hackborn                }
242ce0fd7665f297c5693ee23b3d6daf26baeed4e9dDianne Hackborn            } while (mNextWriteTime == FLUSH_QUEUE);
243ce0fd7665f297c5693ee23b3d6daf26baeed4e9dDianne Hackborn        }
244ce0fd7665f297c5693ee23b3d6daf26baeed4e9dDianne Hackborn    }
245ce0fd7665f297c5693ee23b3d6daf26baeed4e9dDianne Hackborn
246f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner    void saveImage(Bitmap image, String filename) {
24721d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        synchronized (this) {
248f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner            int queueNdx;
249f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner            for (queueNdx = mWriteQueue.size() - 1; queueNdx >= 0; --queueNdx) {
250f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                final WriteQueueItem item = mWriteQueue.get(queueNdx);
251f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                if (item instanceof ImageWriteQueueItem) {
252f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                    ImageWriteQueueItem imageWriteQueueItem = (ImageWriteQueueItem) item;
253f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                    if (imageWriteQueueItem.mFilename.equals(filename)) {
254f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                        // replace the Bitmap with the new one.
255f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                        imageWriteQueueItem.mImage = image;
256f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                        break;
257f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                    }
258f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                }
259f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner            }
260f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner            if (queueNdx < 0) {
261f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                mWriteQueue.add(new ImageWriteQueueItem(filename, image));
262f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner            }
26363f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner            if (mWriteQueue.size() > MAX_WRITE_QUEUE_LENGTH) {
26463f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner                mNextWriteTime = FLUSH_QUEUE;
26563f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner            } else if (mNextWriteTime == 0) {
266f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                mNextWriteTime = SystemClock.uptimeMillis() + PRE_TASK_DELAY_MS;
267f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner            }
26818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            if (DEBUG_PERSISTER) Slog.d(TAG, "saveImage: filename=" + filename + " now=" +
269f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                    SystemClock.uptimeMillis() + " mNextWriteTime=" +
270f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                    mNextWriteTime + " Callers=" + Debug.getCallers(4));
27121d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner            notifyAll();
27221d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        }
27363f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner
27463f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner        yieldIfQueueTooDeep();
27521d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner    }
27621d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
277648f69b95ce7fc95f551f6e08a2408d6e57dbab9Craig Mautner    Bitmap getTaskDescriptionIcon(String filename) {
278648f69b95ce7fc95f551f6e08a2408d6e57dbab9Craig Mautner        // See if it is in the write queue
279648f69b95ce7fc95f551f6e08a2408d6e57dbab9Craig Mautner        final Bitmap icon = getImageFromWriteQueue(filename);
280648f69b95ce7fc95f551f6e08a2408d6e57dbab9Craig Mautner        if (icon != null) {
281648f69b95ce7fc95f551f6e08a2408d6e57dbab9Craig Mautner            return icon;
282648f69b95ce7fc95f551f6e08a2408d6e57dbab9Craig Mautner        }
283648f69b95ce7fc95f551f6e08a2408d6e57dbab9Craig Mautner        return restoreImage(filename);
284648f69b95ce7fc95f551f6e08a2408d6e57dbab9Craig Mautner    }
285648f69b95ce7fc95f551f6e08a2408d6e57dbab9Craig Mautner
286648f69b95ce7fc95f551f6e08a2408d6e57dbab9Craig Mautner    Bitmap getImageFromWriteQueue(String filename) {
287f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner        synchronized (this) {
288f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner            for (int queueNdx = mWriteQueue.size() - 1; queueNdx >= 0; --queueNdx) {
289f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                final WriteQueueItem item = mWriteQueue.get(queueNdx);
290f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                if (item instanceof ImageWriteQueueItem) {
291f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                    ImageWriteQueueItem imageWriteQueueItem = (ImageWriteQueueItem) item;
292f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                    if (imageWriteQueueItem.mFilename.equals(filename)) {
293f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                        return imageWriteQueueItem.mImage;
294f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                    }
295f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                }
296f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner            }
297f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner            return null;
298f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner        }
299f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner    }
300f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner
30121d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner    private StringWriter saveToXml(TaskRecord task) throws IOException, XmlPullParserException {
30218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        if (DEBUG_PERSISTER) Slog.d(TAG, "saveToXml: task=" + task);
30321d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        final XmlSerializer xmlSerializer = new FastXmlSerializer();
30421d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        StringWriter stringWriter = new StringWriter();
30521d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        xmlSerializer.setOutput(stringWriter);
30621d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
30718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        if (DEBUG_PERSISTER) xmlSerializer.setFeature(
30821d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                    "http://xmlpull.org/v1/doc/features.html#indent-output", true);
30921d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
31021d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        // save task
31121d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        xmlSerializer.startDocument(null, true);
31221d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
31321d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        xmlSerializer.startTag(null, TAG_TASK);
31421d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        task.saveToXml(xmlSerializer);
31521d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        xmlSerializer.endTag(null, TAG_TASK);
31621d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
31721d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        xmlSerializer.endDocument();
31821d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        xmlSerializer.flush();
31921d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
32021d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        return stringWriter;
32121d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner    }
32221d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
32377b04267c68b86c512937793f7ce563da55a99f3Craig Mautner    private String fileToString(File file) {
32477b04267c68b86c512937793f7ce563da55a99f3Craig Mautner        final String newline = System.lineSeparator();
32577b04267c68b86c512937793f7ce563da55a99f3Craig Mautner        try {
32677b04267c68b86c512937793f7ce563da55a99f3Craig Mautner            BufferedReader reader = new BufferedReader(new FileReader(file));
32777b04267c68b86c512937793f7ce563da55a99f3Craig Mautner            StringBuffer sb = new StringBuffer((int) file.length() * 2);
32877b04267c68b86c512937793f7ce563da55a99f3Craig Mautner            String line;
32977b04267c68b86c512937793f7ce563da55a99f3Craig Mautner            while ((line = reader.readLine()) != null) {
33077b04267c68b86c512937793f7ce563da55a99f3Craig Mautner                sb.append(line + newline);
33177b04267c68b86c512937793f7ce563da55a99f3Craig Mautner            }
33277b04267c68b86c512937793f7ce563da55a99f3Craig Mautner            reader.close();
33377b04267c68b86c512937793f7ce563da55a99f3Craig Mautner            return sb.toString();
33477b04267c68b86c512937793f7ce563da55a99f3Craig Mautner        } catch (IOException ioe) {
33577b04267c68b86c512937793f7ce563da55a99f3Craig Mautner            Slog.e(TAG, "Couldn't read file " + file.getName());
33677b04267c68b86c512937793f7ce563da55a99f3Craig Mautner            return null;
33777b04267c68b86c512937793f7ce563da55a99f3Craig Mautner        }
33877b04267c68b86c512937793f7ce563da55a99f3Craig Mautner    }
33977b04267c68b86c512937793f7ce563da55a99f3Craig Mautner
340a228ae95ea2f842c0e84f237c64bf032689410ddCraig Mautner    private TaskRecord taskIdToTask(int taskId, ArrayList<TaskRecord> tasks) {
341a228ae95ea2f842c0e84f237c64bf032689410ddCraig Mautner        if (taskId < 0) {
342a228ae95ea2f842c0e84f237c64bf032689410ddCraig Mautner            return null;
343a228ae95ea2f842c0e84f237c64bf032689410ddCraig Mautner        }
344a228ae95ea2f842c0e84f237c64bf032689410ddCraig Mautner        for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
345a228ae95ea2f842c0e84f237c64bf032689410ddCraig Mautner            final TaskRecord task = tasks.get(taskNdx);
346a228ae95ea2f842c0e84f237c64bf032689410ddCraig Mautner            if (task.taskId == taskId) {
347a228ae95ea2f842c0e84f237c64bf032689410ddCraig Mautner                return task;
348a228ae95ea2f842c0e84f237c64bf032689410ddCraig Mautner            }
349a228ae95ea2f842c0e84f237c64bf032689410ddCraig Mautner        }
350a228ae95ea2f842c0e84f237c64bf032689410ddCraig Mautner        Slog.e(TAG, "Restore affiliation error looking for taskId=" + taskId);
351a228ae95ea2f842c0e84f237c64bf032689410ddCraig Mautner        return null;
352a228ae95ea2f842c0e84f237c64bf032689410ddCraig Mautner    }
353a228ae95ea2f842c0e84f237c64bf032689410ddCraig Mautner
35421d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner    ArrayList<TaskRecord> restoreTasksLocked() {
35521d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        final ArrayList<TaskRecord> tasks = new ArrayList<TaskRecord>();
35621d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        ArraySet<Integer> recoveredTaskIds = new ArraySet<Integer>();
35721d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
35821d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        File[] recentFiles = sTasksDir.listFiles();
35921d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        if (recentFiles == null) {
36021d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner            Slog.e(TAG, "Unable to list files from " + sTasksDir);
36121d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner            return tasks;
36221d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        }
36321d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
36421d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        for (int taskNdx = 0; taskNdx < recentFiles.length; ++taskNdx) {
36521d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner            File taskFile = recentFiles[taskNdx];
36618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            if (DEBUG_PERSISTER) Slog.d(TAG, "restoreTasksLocked: taskFile=" + taskFile.getName());
36721d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner            BufferedReader reader = null;
368e0129b3c672f5555deb75366b1a7159f41737874Craig Mautner            boolean deleteFile = false;
36921d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner            try {
37021d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                reader = new BufferedReader(new FileReader(taskFile));
37121d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                final XmlPullParser in = Xml.newPullParser();
37221d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                in.setInput(reader);
37321d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
37421d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                int event;
37521d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
37621d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                        event != XmlPullParser.END_TAG) {
37721d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                    final String name = in.getName();
37821d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                    if (event == XmlPullParser.START_TAG) {
37918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        if (DEBUG_PERSISTER)
38018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                                Slog.d(TAG, "restoreTasksLocked: START_TAG name=" + name);
38121d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                        if (TAG_TASK.equals(name)) {
38221d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                            final TaskRecord task =
38321d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                                    TaskRecord.restoreFromXml(in, mStackSupervisor);
38418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            if (DEBUG_PERSISTER) Slog.d(TAG, "restoreTasksLocked: restored task=" +
38577b04267c68b86c512937793f7ce563da55a99f3Craig Mautner                                    task);
38621d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                            if (task != null) {
38743e52ed32e2d55ef4aee18c4b4bc13b7fdef9cc4Craig Mautner                                task.isPersistable = true;
388852975d5377bfe5f4abc9d2a28e301aa2fa99994Dianne Hackborn                                // XXX Don't add to write queue... there is no reason to write
389852975d5377bfe5f4abc9d2a28e301aa2fa99994Dianne Hackborn                                // out the stuff we just read, if we don't write it we will
390852975d5377bfe5f4abc9d2a28e301aa2fa99994Dianne Hackborn                                // read the same thing again.
391852975d5377bfe5f4abc9d2a28e301aa2fa99994Dianne Hackborn                                //mWriteQueue.add(new TaskWriteQueueItem(task));
39221d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                                tasks.add(task);
39321d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                                final int taskId = task.taskId;
39421d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                                recoveredTaskIds.add(taskId);
39521d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                                mStackSupervisor.setNextTaskId(taskId);
39677b04267c68b86c512937793f7ce563da55a99f3Craig Mautner                            } else {
39777b04267c68b86c512937793f7ce563da55a99f3Craig Mautner                                Slog.e(TAG, "Unable to restore taskFile=" + taskFile + ": " +
39877b04267c68b86c512937793f7ce563da55a99f3Craig Mautner                                        fileToString(taskFile));
39921d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                            }
40021d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                        } else {
40143e52ed32e2d55ef4aee18c4b4bc13b7fdef9cc4Craig Mautner                            Slog.wtf(TAG, "restoreTasksLocked Unknown xml event=" + event +
40243e52ed32e2d55ef4aee18c4b4bc13b7fdef9cc4Craig Mautner                                    " name=" + name);
40321d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                        }
40421d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                    }
40521d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                    XmlUtils.skipCurrentTag(in);
40621d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                }
407e0129b3c672f5555deb75366b1a7159f41737874Craig Mautner            } catch (Exception e) {
408a228ae95ea2f842c0e84f237c64bf032689410ddCraig Mautner                Slog.wtf(TAG, "Unable to parse " + taskFile + ". Error ", e);
40977b04267c68b86c512937793f7ce563da55a99f3Craig Mautner                Slog.e(TAG, "Failing file: " + fileToString(taskFile));
410e0129b3c672f5555deb75366b1a7159f41737874Craig Mautner                deleteFile = true;
41121d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner            } finally {
41218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                IoUtils.closeQuietly(reader);
41318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                if (!DEBUG_PERSISTER && deleteFile) {
41418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    if (true || DEBUG_PERSISTER)
41518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            Slog.d(TAG, "Deleting file=" + taskFile.getName());
416e0129b3c672f5555deb75366b1a7159f41737874Craig Mautner                    taskFile.delete();
417e0129b3c672f5555deb75366b1a7159f41737874Craig Mautner                }
41821d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner            }
41921d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        }
42021d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
42118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        if (!DEBUG_PERSISTER) {
42221d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner            removeObsoleteFiles(recoveredTaskIds);
42321d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        }
42421d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
425a228ae95ea2f842c0e84f237c64bf032689410ddCraig Mautner        // Fixup task affiliation from taskIds
426a228ae95ea2f842c0e84f237c64bf032689410ddCraig Mautner        for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
427a228ae95ea2f842c0e84f237c64bf032689410ddCraig Mautner            final TaskRecord task = tasks.get(taskNdx);
428a228ae95ea2f842c0e84f237c64bf032689410ddCraig Mautner            task.setPrevAffiliate(taskIdToTask(task.mPrevAffiliateTaskId, tasks));
429a228ae95ea2f842c0e84f237c64bf032689410ddCraig Mautner            task.setNextAffiliate(taskIdToTask(task.mNextAffiliateTaskId, tasks));
430a228ae95ea2f842c0e84f237c64bf032689410ddCraig Mautner        }
431a228ae95ea2f842c0e84f237c64bf032689410ddCraig Mautner
43221d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        TaskRecord[] tasksArray = new TaskRecord[tasks.size()];
43321d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        tasks.toArray(tasksArray);
43421d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        Arrays.sort(tasksArray, new Comparator<TaskRecord>() {
43521d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner            @Override
43621d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner            public int compare(TaskRecord lhs, TaskRecord rhs) {
43743e52ed32e2d55ef4aee18c4b4bc13b7fdef9cc4Craig Mautner                final long diff = rhs.mLastTimeMoved - lhs.mLastTimeMoved;
43821d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                if (diff < 0) {
43921d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                    return -1;
44021d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                } else if (diff > 0) {
44121d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                    return +1;
44221d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                } else {
44321d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                    return 0;
44421d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                }
44521d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner            }
44621d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        });
44721d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
44821d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        return new ArrayList<TaskRecord>(Arrays.asList(tasksArray));
44921d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner    }
45021d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
451e0129b3c672f5555deb75366b1a7159f41737874Craig Mautner    private static void removeObsoleteFiles(ArraySet<Integer> persistentTaskIds, File[] files) {
45218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        if (DEBUG_PERSISTER) Slog.d(TAG, "removeObsoleteFile: persistentTaskIds="
45318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    + persistentTaskIds + " files=" + files);
454a5badf06dd818d67a8cdd2d42803e124be929ab8Craig Mautner        if (files == null) {
455a5badf06dd818d67a8cdd2d42803e124be929ab8Craig Mautner            Slog.e(TAG, "File error accessing recents directory (too many files open?).");
456a5badf06dd818d67a8cdd2d42803e124be929ab8Craig Mautner            return;
457a5badf06dd818d67a8cdd2d42803e124be929ab8Craig Mautner        }
45821d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        for (int fileNdx = 0; fileNdx < files.length; ++fileNdx) {
45921d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner            File file = files[fileNdx];
46021d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner            String filename = file.getName();
461ffcfcaadfefec2fb56f67a0a614a54bf4599d62bCraig Mautner            final int taskIdEnd = filename.indexOf('_');
46221d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner            if (taskIdEnd > 0) {
46321d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                final int taskId;
46421d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                try {
46521d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                    taskId = Integer.valueOf(filename.substring(0, taskIdEnd));
46618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    if (DEBUG_PERSISTER) Slog.d(TAG, "removeObsoleteFile: Found taskId=" + taskId);
46721d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                } catch (Exception e) {
46843e52ed32e2d55ef4aee18c4b4bc13b7fdef9cc4Craig Mautner                    Slog.wtf(TAG, "removeObsoleteFile: Can't parse file=" + file.getName());
46921d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                    file.delete();
47021d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                    continue;
47121d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                }
47221d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                if (!persistentTaskIds.contains(taskId)) {
47318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    if (true || DEBUG_PERSISTER) Slog.d(TAG, "removeObsoleteFile: deleting file=" +
47477b04267c68b86c512937793f7ce563da55a99f3Craig Mautner                            file.getName());
47521d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                    file.delete();
47621d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                }
47721d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner            }
47821d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        }
47921d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner    }
48021d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
48121d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner    private void removeObsoleteFiles(ArraySet<Integer> persistentTaskIds) {
48221d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        removeObsoleteFiles(persistentTaskIds, sTasksDir.listFiles());
48321d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        removeObsoleteFiles(persistentTaskIds, sImagesDir.listFiles());
48421d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner    }
48521d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
48621d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner    static Bitmap restoreImage(String filename) {
48718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        if (DEBUG_PERSISTER) Slog.d(TAG, "restoreImage: restoring " + filename);
488c0ffce5ddd6446f1d46a49cdfaeda4a2ce408e1dCraig Mautner        return BitmapFactory.decodeFile(sImagesDir + File.separator + filename);
48921d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner    }
49021d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
49118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    /**
49218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale     * Tries to restore task that were backed-up on a different device onto this device.
49318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale     */
49418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    void restoreTasksFromOtherDeviceLocked() {
49518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        readOtherDeviceTasksFromDisk();
49618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        addOtherDeviceTasksToRecentsLocked();
49718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    }
49818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
49918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    /**
50018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale     * Read the tasks that were backed-up on a different device and can be restored to this device
50118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale     * from disk and populated {@link #mOtherDeviceTasksMap} with the information. Also sets up
50218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale     * time to clear out other device tasks that have not been restored on this device
50318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale     * within the allotted time.
50418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale     */
50518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    private void readOtherDeviceTasksFromDisk() {
50618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        synchronized (mOtherDeviceTasksMap) {
50718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            // Clear out current map and expiration time.
50818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            mOtherDeviceTasksMap.clear();
50918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            mExpiredTasksCleanupTime = Long.MAX_VALUE;
51018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
51118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            final File[] taskFiles;
51218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            if (!sRestoredTasksDir.exists()
51318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    || (taskFiles = sRestoredTasksDir.listFiles()) == null) {
51418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                // Nothing to do if there are no tasks to restore.
51518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                return;
51618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            }
51718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
51818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            long earliestMtime = System.currentTimeMillis();
51918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            SparseArray<List<OtherDeviceTask>> tasksByAffiliateIds =
52018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        new SparseArray<>(taskFiles.length);
52118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
52218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            // Read new tasks from disk
52318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            for (int i = 0; i < taskFiles.length; ++i) {
52418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                final File taskFile = taskFiles[i];
52518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                if (DEBUG_RESTORER) Slog.d(TAG, "readOtherDeviceTasksFromDisk: taskFile="
52618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            + taskFile.getName());
52718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
52818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                final OtherDeviceTask task = OtherDeviceTask.createFromFile(taskFile);
52918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
53018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                if (task == null) {
53118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    // Go ahead and remove the file on disk if we are unable to create a task from
53218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    // it.
53318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    if (DEBUG_RESTORER) Slog.e(TAG, "Unable to create task for file="
53418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                                + taskFile.getName() + "...deleting file.");
53518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    taskFile.delete();
53618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    continue;
53718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                }
53818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
53918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                List<OtherDeviceTask> tasks = tasksByAffiliateIds.get(task.mAffiliatedTaskId);
54018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                if (tasks == null) {
54118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    tasks = new ArrayList<>();
54218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    tasksByAffiliateIds.put(task.mAffiliatedTaskId, tasks);
54318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                }
54418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                tasks.add(task);
54518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                final long taskMtime = taskFile.lastModified();
54618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                if (earliestMtime > taskMtime) {
54718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    earliestMtime = taskMtime;
54818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                }
54918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            }
55018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
55118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            if (tasksByAffiliateIds.size() > 0) {
55218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                // Sort each affiliated tasks chain by taskId which is the order they were created
55318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                // that should always be correct...Then add to task map.
55418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                for (int i = 0; i < tasksByAffiliateIds.size(); i++) {
55518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    List<OtherDeviceTask> chain = tasksByAffiliateIds.valueAt(i);
55618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    Collections.sort(chain);
55718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    // Package name of the root task in the affiliate chain.
55818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    final String packageName =
55918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            chain.get(chain.size()-1).mComponentName.getPackageName();
56018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    List<List<OtherDeviceTask>> chains = mOtherDeviceTasksMap.get(packageName);
56118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    if (chains == null) {
56218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        chains = new ArrayList<>();
56318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        mOtherDeviceTasksMap.put(packageName, chains);
56418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    }
56518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    chains.add(chain);
56618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                }
56718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
56818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                // Set expiration time.
56918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                mExpiredTasksCleanupTime = earliestMtime + MAX_INSTALL_WAIT_TIME;
57018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                if (DEBUG_RESTORER) Slog.d(TAG, "Set Expiration time to "
57118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            + DateUtils.formatDateTime(mService.mContext, mExpiredTasksCleanupTime,
57218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME));
57318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            }
57418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        }
57518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    }
57618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
57718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    /**
57818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale     * Removed any expired tasks from {@link #mOtherDeviceTasksMap} and disk if their expiration
57918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale     * time is less than or equal to {@link #mExpiredTasksCleanupTime}.
58018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale     */
58118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    private void removeExpiredTasksIfNeeded() {
58218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        synchronized (mOtherDeviceTasksMap) {
58318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            final long now = System.currentTimeMillis();
58492dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale            final boolean noMoreTasks = mOtherDeviceTasksMap.isEmpty();
58592dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale            if (noMoreTasks || now < mExpiredTasksCleanupTime) {
58692dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                if (noMoreTasks && mPackageUidMap != null) {
58792dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                    // All done! package->uid map no longer needed.
58892dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                    mPackageUidMap = null;
58992dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                }
59018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                return;
59118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            }
59218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
59318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            long earliestNonExpiredMtime = now;
59418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            mExpiredTasksCleanupTime = Long.MAX_VALUE;
59518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
59618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            // Remove expired backed-up tasks that have not been restored. We only want to
59718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            // remove task if it is safe to remove all tasks in the affiliation chain.
59818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            for (int i = mOtherDeviceTasksMap.size() - 1; i >= 0 ; i--) {
59918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
60018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                List<List<OtherDeviceTask>> chains = mOtherDeviceTasksMap.valueAt(i);
60118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                for (int j = chains.size() - 1; j >= 0 ; j--) {
60218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
60318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    List<OtherDeviceTask> chain = chains.get(j);
60418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    boolean removeChain = true;
60518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    for (int k = chain.size() - 1; k >= 0 ; k--) {
60618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        OtherDeviceTask task = chain.get(k);
60718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        final long taskLastModified = task.mFile.lastModified();
60818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        if ((taskLastModified + MAX_INSTALL_WAIT_TIME) > now) {
60918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            // File has not expired yet...but we keep looping to get the earliest
61018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            // mtime.
61118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            if (earliestNonExpiredMtime > taskLastModified) {
61218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                                earliestNonExpiredMtime = taskLastModified;
61318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            }
61418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            removeChain = false;
61518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        }
61618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    }
61718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    if (removeChain) {
61818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        for (int k = chain.size() - 1; k >= 0; k--) {
61918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            final File file = chain.get(k).mFile;
62018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            if (DEBUG_RESTORER) Slog.d(TAG, "Deleting expired file="
62118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                                    + file.getName() + " mapped to not installed component="
62218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                                    + chain.get(k).mComponentName);
62318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            file.delete();
62418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        }
62518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        chains.remove(j);
62618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    }
62718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                }
62818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                if (chains.isEmpty()) {
62918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    final String packageName = mOtherDeviceTasksMap.keyAt(i);
63018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    mOtherDeviceTasksMap.removeAt(i);
63118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    if (DEBUG_RESTORER) Slog.d(TAG, "Removed package=" + packageName
63218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                                + " from task map");
63318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                }
63418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            }
63518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
63618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            // Reset expiration time if there is any task remaining.
63718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            if (!mOtherDeviceTasksMap.isEmpty()) {
63818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                mExpiredTasksCleanupTime = earliestNonExpiredMtime + MAX_INSTALL_WAIT_TIME;
63918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                if (DEBUG_RESTORER) Slog.d(TAG, "Reset expiration time to "
64018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            + DateUtils.formatDateTime(mService.mContext, mExpiredTasksCleanupTime,
64118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME));
64292dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale            } else {
64392dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                // All done! package->uid map no longer needed.
64492dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                mPackageUidMap = null;
64592dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale            }
64692dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale        }
64792dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale    }
64892dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale
64992dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale    /**
65092dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale     * Removes the input package name from the local package->uid map.
65192dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale     */
65292dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale    void removeFromPackageCache(String packageName) {
65392dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale        synchronized (mOtherDeviceTasksMap) {
65492dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale            if (mPackageUidMap != null) {
65592dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                mPackageUidMap.remove(packageName);
65618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            }
65718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        }
65818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    }
65918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
66018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    /**
66118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale     * Tries to add all backed-up tasks from another device to this device recent's list.
66218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale     */
66318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    private void addOtherDeviceTasksToRecentsLocked() {
66418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        synchronized (mOtherDeviceTasksMap) {
66518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            for (int i = mOtherDeviceTasksMap.size() - 1; i >= 0; i--) {
66618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                addOtherDeviceTasksToRecentsLocked(mOtherDeviceTasksMap.keyAt(i));
66718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            }
66818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        }
66918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    }
67018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
67118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    /**
67218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale     * Tries to add backed-up tasks that are associated with the input package from
67318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale     * another device to this device recent's list.
67418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale     */
67518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    void addOtherDeviceTasksToRecentsLocked(String packageName) {
67618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        synchronized (mOtherDeviceTasksMap) {
67718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            List<List<OtherDeviceTask>> chains = mOtherDeviceTasksMap.get(packageName);
67818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            if (chains == null) {
67918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                return;
68018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            }
68118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
68218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            for (int i = chains.size() - 1; i >= 0; i--) {
68318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                List<OtherDeviceTask> chain = chains.get(i);
68418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                if (!canAddOtherDeviceTaskChain(chain)) {
68518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    if (DEBUG_RESTORER) Slog.d(TAG, "Can't add task chain at index=" + i
68618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            + " for package=" + packageName);
68718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    continue;
68818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                }
68918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
69018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                // Generate task records for this chain.
69118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                List<TaskRecord> tasks = new ArrayList<>();
69218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                TaskRecord prev = null;
69318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                for (int j = chain.size() - 1; j >= 0; j--) {
69418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    TaskRecord task = createTaskRecordLocked(chain.get(j));
69518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    if (task == null) {
69618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        // There was a problem in creating one of this task records in this chain.
69718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        // There is no way we can continue...
69818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        if (DEBUG_RESTORER) Slog.d(TAG, "Can't create task record for file="
69918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                                + chain.get(j).mFile + " for package=" + packageName);
70018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        break;
70118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    }
70218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
70318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    // Wire-up affiliation chain.
70418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    if (prev == null) {
70518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        task.mPrevAffiliate = null;
70618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        task.mPrevAffiliateTaskId = INVALID_TASK_ID;
70718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        task.mAffiliatedTaskId = task.taskId;
70818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    } else {
70918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        prev.mNextAffiliate = task;
71018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        prev.mNextAffiliateTaskId = task.taskId;
71118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        task.mAffiliatedTaskId = prev.mAffiliatedTaskId;
71218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        task.mPrevAffiliate = prev;
71318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        task.mPrevAffiliateTaskId = prev.taskId;
71418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    }
71518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    prev = task;
71618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    tasks.add(0, task);
71718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                }
71818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
71918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                // Add tasks to recent's if we were able to create task records for all the tasks
72018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                // in the chain.
72118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                if (tasks.size() == chain.size()) {
72218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    // Make sure there is space in recent's to add the new task. If there is space
72318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    // to the to the back.
72418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    // TODO: Would be more fancy to interleave the new tasks into recent's based on
72518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    // {@link TaskRecord.mLastTimeMoved} and drop the oldest recent's vs. just
72618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    // adding to the back of the list.
72718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    int spaceLeft =
72818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            ActivityManager.getMaxRecentTasksStatic()
72918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            - mService.mRecentTasks.size();
73018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    if (spaceLeft >= tasks.size()) {
73118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        mService.mRecentTasks.addAll(mService.mRecentTasks.size(), tasks);
73218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        for (int k = tasks.size() - 1; k >= 0; k--) {
73318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            // Persist new tasks.
73418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            wakeup(tasks.get(k), false);
73518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        }
73618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
73718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        if (DEBUG_RESTORER) Slog.d(TAG, "Added " + tasks.size()
73818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                                    + " tasks to recent's for" + " package=" + packageName);
73918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    } else {
74018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        if (DEBUG_RESTORER) Slog.d(TAG, "Didn't add to recents. tasks.size("
74118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                                    + tasks.size() + ") != chain.size(" + chain.size()
74218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                                    + ") for package=" + packageName);
74318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    }
74418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                } else {
74518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    if (DEBUG_RESTORER) Slog.v(TAG, "Unable to add restored tasks to recents "
74618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            + tasks.size() + " tasks for package=" + packageName);
74718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                }
74818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
74918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                // Clean-up structures
75018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                for (int j = chain.size() - 1; j >= 0; j--) {
75118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    chain.get(j).mFile.delete();
75218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                }
75318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                chains.remove(i);
75418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                if (chains.isEmpty()) {
75518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    // The fate of all backed-up tasks associated with this package has been
75618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    // determine. Go ahead and remove it from the to-process list.
75718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    mOtherDeviceTasksMap.remove(packageName);
75818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    if (DEBUG_RESTORER)
75918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            Slog.d(TAG, "Removed package=" + packageName + " from restore map");
76018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                }
76118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            }
76218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        }
76318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    }
76418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
76518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    /**
76618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale     * Creates and returns {@link TaskRecord} for the task from another device that can be used on
76718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale     * this device. Returns null if the operation failed.
76818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale     */
76918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    private TaskRecord createTaskRecordLocked(OtherDeviceTask other) {
77018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        File file = other.mFile;
77118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        BufferedReader reader = null;
77218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        TaskRecord task = null;
77318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        if (DEBUG_RESTORER) Slog.d(TAG, "createTaskRecordLocked: file=" + file.getName());
77418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
77518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        try {
77618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            reader = new BufferedReader(new FileReader(file));
77718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            final XmlPullParser in = Xml.newPullParser();
77818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            in.setInput(reader);
77918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
78018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            int event;
78118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            while (((event = in.next()) != XmlPullParser.END_DOCUMENT)
78218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    && event != XmlPullParser.END_TAG) {
78318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                final String name = in.getName();
78418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                if (event == XmlPullParser.START_TAG) {
78518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
78618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    if (TAG_TASK.equals(name)) {
78718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        // Create a task record using a task id that is valid for this device.
78818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        task = TaskRecord.restoreFromXml(
78918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                                in, mStackSupervisor, mStackSupervisor.getNextTaskId());
79018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        if (DEBUG_RESTORER)
79118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                                Slog.d(TAG, "createTaskRecordLocked: restored task=" + task);
79218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
79318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        if (task != null) {
79418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            task.isPersistable = true;
79518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            task.inRecents = true;
79618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            // Task can/should only be backed-up/restored for device owner.
79718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            task.userId = UserHandle.USER_OWNER;
79818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            // Clear out affiliated ids that are no longer valid on this device.
79918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            task.mAffiliatedTaskId = INVALID_TASK_ID;
80018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            task.mPrevAffiliateTaskId = INVALID_TASK_ID;
80118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            task.mNextAffiliateTaskId = INVALID_TASK_ID;
80292dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                            // Set up uids valid for this device.
80392dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                            Integer uid = mPackageUidMap.get(task.realActivity.getPackageName());
80492dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                            if (uid == null) {
80592dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                                // How did this happen???
80692dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                                Slog.wtf(TAG, "Can't find uid for task=" + task
80792dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                                        + " in mPackageUidMap=" + mPackageUidMap);
80892dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                                return null;
80992dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                            }
81092dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                            task.effectiveUid = task.mCallingUid = uid;
81192dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                            for (int i = task.mActivities.size() - 1; i >= 0; --i) {
81292dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                                final ActivityRecord activity = task.mActivities.get(i);
81392dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                                uid = mPackageUidMap.get(activity.launchedFromPackage);
81492dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                                if (uid == null) {
81592dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                                    // How did this happen??
81692dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                                    Slog.wtf(TAG, "Can't find uid for activity=" + activity
81792dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                                            + " in mPackageUidMap=" + mPackageUidMap);
81892dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                                    return null;
81992dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                                }
82092dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                                activity.launchedFromUid = uid;
82192dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                            }
82292dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale
82318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        } else {
82418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            Slog.e(TAG, "Unable to create task for backed-up file=" + file + ": "
82518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                                        + fileToString(file));
82618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        }
82718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    } else {
82818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        Slog.wtf(TAG, "createTaskRecordLocked Unknown xml event=" + event
82918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                                    + " name=" + name);
83018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    }
83118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                }
83218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                XmlUtils.skipCurrentTag(in);
83318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            }
83418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        } catch (Exception e) {
83518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            Slog.wtf(TAG, "Unable to parse " + file + ". Error ", e);
83618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            Slog.e(TAG, "Failing file: " + fileToString(file));
83718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        } finally {
83818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            IoUtils.closeQuietly(reader);
83918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        }
84018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
84118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        return task;
84218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    }
84318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
84418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    /**
84518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale     * Returns true if the input task chain backed-up from another device can be restored on this
84692dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale     * device. Also, sets the {@link OtherDeviceTask#mUid} on the input tasks if they can be
84792dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale     * restored.
84818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale     */
84918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    private boolean canAddOtherDeviceTaskChain(List<OtherDeviceTask> chain) {
85018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
85192dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale        final ArraySet<ComponentName> validComponents = new ArraySet<>();
85292dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale        final IPackageManager pm = AppGlobals.getPackageManager();
85318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        for (int i = 0; i < chain.size(); i++) {
85418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
85518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            OtherDeviceTask task = chain.get(i);
85618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            // Quick check, we can't add the task chain if any of its task files don't exist.
85718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            if (!task.mFile.exists()) {
85892dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                if (DEBUG_RESTORER) Slog.d(TAG,
85992dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                        "Can't add chain due to missing file=" + task.mFile);
86092dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                return false;
86192dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale            }
86292dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale
86392dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale            // Verify task package is installed.
86492dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale            if (!isPackageInstalled(task.mComponentName.getPackageName())) {
86592dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                return false;
86692dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale            }
86792dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale            // Verify that all the launch packages are installed.
86892dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale            if (task.mLaunchPackages != null) {
86992dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                for (int j = task.mLaunchPackages.size() - 1; j >= 0; --j) {
87092dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                    if (!isPackageInstalled(task.mLaunchPackages.valueAt(j))) {
87192dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                        return false;
87292dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                    }
87392dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                }
87492dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale            }
87592dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale
87692dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale            if (validComponents.contains(task.mComponentName)) {
87792dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                // Existance of component has already been verified.
87892dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                continue;
87992dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale            }
88092dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale
88192dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale            // Check to see if the specific component is installed.
88292dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale            try {
88392dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                if (pm.getActivityInfo(task.mComponentName, 0, UserHandle.USER_OWNER) == null) {
88492dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                    // Component isn't installed...
88592dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                    return false;
88692dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                }
88792dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                validComponents.add(task.mComponentName);
88892dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale            } catch (RemoteException e) {
88992dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                // Should not happen???
89018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                return false;
89118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            }
89218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        }
89318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
89492dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale        return true;
89592dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale    }
89692dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale
89792dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale    /**
89892dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale     * Returns true if the input package name is installed. If the package is installed, an entry
89992dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale     * for the package is added to {@link #mPackageUidMap}.
90092dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale     */
90192dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale    private boolean isPackageInstalled(final String packageName) {
90292dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale        if (mPackageUidMap != null && mPackageUidMap.containsKey(packageName)) {
90392dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale            return true;
90492dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale        }
90518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        try {
90692dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale            int uid = AppGlobals.getPackageManager().getPackageUid(
90792dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                    packageName, UserHandle.USER_OWNER);
90892dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale            if (uid == -1) {
90992dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                // package doesn't exist...
91092dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                return false;
91118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            }
91292dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale            if (mPackageUidMap == null) {
91392dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                mPackageUidMap = new ArrayMap<>();
91492dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale            }
91592dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale            mPackageUidMap.put(packageName, uid);
91692dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale            return true;
91718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        } catch (RemoteException e) {
91818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            // Should not happen???
91992dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale            return false;
92018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        }
92118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    }
92218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
92321d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner    private class LazyTaskWriterThread extends Thread {
92421d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
92521d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        LazyTaskWriterThread(String name) {
92621d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner            super(name);
92721d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        }
92821d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
92921d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        @Override
93021d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        public void run() {
93121d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner            ArraySet<Integer> persistentTaskIds = new ArraySet<Integer>();
93221d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner            while (true) {
933f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                // We can't lock mService while holding TaskPersister.this, but we don't want to
934f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                // call removeObsoleteFiles every time through the loop, only the last time before
935f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                // going to sleep. The risk is that we call removeObsoleteFiles() successively.
936f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                final boolean probablyDone;
937f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                synchronized (TaskPersister.this) {
938f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                    probablyDone = mWriteQueue.isEmpty();
939f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                }
940f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                if (probablyDone) {
94118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    if (DEBUG_PERSISTER) Slog.d(TAG, "Looking for obsolete files.");
942f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                    persistentTaskIds.clear();
943f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                    synchronized (mService) {
944f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                        final ArrayList<TaskRecord> tasks = mService.mRecentTasks;
94518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        if (DEBUG_PERSISTER) Slog.d(TAG, "mRecents=" + tasks);
946f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                        for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
947f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                            final TaskRecord task = tasks.get(taskNdx);
94818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            if (DEBUG_PERSISTER) Slog.d(TAG, "LazyTaskWriter: task=" + task +
949be23ff4949612ecea89d112eff7f5e2c3dbf7685Wale Ogunwale                                    " persistable=" + task.isPersistable);
950be23ff4949612ecea89d112eff7f5e2c3dbf7685Wale Ogunwale                            if ((task.isPersistable || task.inRecents)
95118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                                    && (task.stack == null || !task.stack.isHomeStack())) {
95218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                                if (DEBUG_PERSISTER)
95318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                                        Slog.d(TAG, "adding to persistentTaskIds task=" + task);
954f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                                persistentTaskIds.add(task.taskId);
955f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                            } else {
95618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                                if (DEBUG_PERSISTER) Slog.d(TAG,
957be23ff4949612ecea89d112eff7f5e2c3dbf7685Wale Ogunwale                                        "omitting from persistentTaskIds task=" + task);
958f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                            }
959f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                        }
960f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                    }
961f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                    removeObsoleteFiles(persistentTaskIds);
962f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                }
963f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner
964f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                // If mNextWriteTime, then don't delay between each call to saveToXml().
965f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                final WriteQueueItem item;
96621d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                synchronized (TaskPersister.this) {
96763f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner                    if (mNextWriteTime != FLUSH_QUEUE) {
968f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                        // The next write we don't have to wait so long.
969f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                        mNextWriteTime = SystemClock.uptimeMillis() + INTER_WRITE_DELAY_MS;
97018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        if (DEBUG_PERSISTER) Slog.d(TAG, "Next write time may be in " +
971f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                                INTER_WRITE_DELAY_MS + " msec. (" + mNextWriteTime + ")");
972f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                    }
973f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner
974ce0fd7665f297c5693ee23b3d6daf26baeed4e9dDianne Hackborn
975f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                    while (mWriteQueue.isEmpty()) {
976ce0fd7665f297c5693ee23b3d6daf26baeed4e9dDianne Hackborn                        if (mNextWriteTime != 0) {
977ce0fd7665f297c5693ee23b3d6daf26baeed4e9dDianne Hackborn                            mNextWriteTime = 0; // idle.
978ce0fd7665f297c5693ee23b3d6daf26baeed4e9dDianne Hackborn                            TaskPersister.this.notifyAll(); // wake up flush() if needed.
979ce0fd7665f297c5693ee23b3d6daf26baeed4e9dDianne Hackborn                        }
98018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
98118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        // See if we need to remove any expired back-up tasks before waiting.
98218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        removeExpiredTasksIfNeeded();
98318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
984f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                        try {
98518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            if (DEBUG_PERSISTER)
98618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                                    Slog.d(TAG, "LazyTaskWriter: waiting indefinitely.");
987f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                            TaskPersister.this.wait();
988f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                        } catch (InterruptedException e) {
989f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                        }
99063f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner                        // Invariant: mNextWriteTime is either FLUSH_QUEUE or PRE_WRITE_DELAY_MS
99163f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner                        // from now.
992f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                    }
993f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                    item = mWriteQueue.remove(0);
994f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner
99521d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                    long now = SystemClock.uptimeMillis();
99618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    if (DEBUG_PERSISTER) Slog.d(TAG, "LazyTaskWriter: now=" + now
99718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                                + " mNextWriteTime=" + mNextWriteTime + " mWriteQueue.size="
99818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                                + mWriteQueue.size());
999f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                    while (now < mNextWriteTime) {
100021d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                        try {
100118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            if (DEBUG_PERSISTER) Slog.d(TAG, "LazyTaskWriter: waiting " +
1002f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                                    (mNextWriteTime - now));
1003f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                            TaskPersister.this.wait(mNextWriteTime - now);
100421d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                        } catch (InterruptedException e) {
100521d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                        }
100621d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                        now = SystemClock.uptimeMillis();
100721d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                    }
100821d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner
1009f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                    // Got something to do.
1010c0ffce5ddd6446f1d46a49cdfaeda4a2ce408e1dCraig Mautner                }
1011f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner
1012f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                if (item instanceof ImageWriteQueueItem) {
1013f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                    ImageWriteQueueItem imageWriteQueueItem = (ImageWriteQueueItem) item;
1014f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                    final String filename = imageWriteQueueItem.mFilename;
1015f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                    final Bitmap bitmap = imageWriteQueueItem.mImage;
101618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    if (DEBUG_PERSISTER) Slog.d(TAG, "writing bitmap: filename=" + filename);
1017c0ffce5ddd6446f1d46a49cdfaeda4a2ce408e1dCraig Mautner                    FileOutputStream imageFile = null;
1018c0ffce5ddd6446f1d46a49cdfaeda4a2ce408e1dCraig Mautner                    try {
1019c0ffce5ddd6446f1d46a49cdfaeda4a2ce408e1dCraig Mautner                        imageFile = new FileOutputStream(new File(sImagesDir, filename));
1020f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                        bitmap.compress(Bitmap.CompressFormat.PNG, 100, imageFile);
1021c0ffce5ddd6446f1d46a49cdfaeda4a2ce408e1dCraig Mautner                    } catch (Exception e) {
1022c0ffce5ddd6446f1d46a49cdfaeda4a2ce408e1dCraig Mautner                        Slog.e(TAG, "saveImage: unable to save " + filename, e);
1023c0ffce5ddd6446f1d46a49cdfaeda4a2ce408e1dCraig Mautner                    } finally {
102418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        IoUtils.closeQuietly(imageFile);
1025c0ffce5ddd6446f1d46a49cdfaeda4a2ce408e1dCraig Mautner                    }
1026f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                } else if (item instanceof TaskWriteQueueItem) {
1027f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                    // Write out one task.
1028f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                    StringWriter stringWriter = null;
1029f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                    TaskRecord task = ((TaskWriteQueueItem) item).mTask;
103018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    if (DEBUG_PERSISTER) Slog.d(TAG, "Writing task=" + task);
1031f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                    synchronized (mService) {
103263f10904a17db79cc8da08ff904d45d6d1cf0862Craig Mautner                        if (task.inRecents) {
1033f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                            // Still there.
1034f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                            try {
103518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                                if (DEBUG_PERSISTER) Slog.d(TAG, "Saving task=" + task);
1036f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                                stringWriter = saveToXml(task);
1037f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                            } catch (IOException e) {
1038f4f8bb793fe101af770dc974b29c26722bce285fCraig Mautner                            } catch (XmlPullParserException e) {
103921d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                            }
104021d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                        }
1041852975d5377bfe5f4abc9d2a28e301aa2fa99994Dianne Hackborn                    }
1042852975d5377bfe5f4abc9d2a28e301aa2fa99994Dianne Hackborn                    if (stringWriter != null) {
1043852975d5377bfe5f4abc9d2a28e301aa2fa99994Dianne Hackborn                        // Write out xml file while not holding mService lock.
1044852975d5377bfe5f4abc9d2a28e301aa2fa99994Dianne Hackborn                        FileOutputStream file = null;
1045852975d5377bfe5f4abc9d2a28e301aa2fa99994Dianne Hackborn                        AtomicFile atomicFile = null;
1046852975d5377bfe5f4abc9d2a28e301aa2fa99994Dianne Hackborn                        try {
1047852975d5377bfe5f4abc9d2a28e301aa2fa99994Dianne Hackborn                            atomicFile = new AtomicFile(new File(sTasksDir, String.valueOf(
1048852975d5377bfe5f4abc9d2a28e301aa2fa99994Dianne Hackborn                                    task.taskId) + RECENTS_FILENAME + TASK_EXTENSION));
1049852975d5377bfe5f4abc9d2a28e301aa2fa99994Dianne Hackborn                            file = atomicFile.startWrite();
1050852975d5377bfe5f4abc9d2a28e301aa2fa99994Dianne Hackborn                            file.write(stringWriter.toString().getBytes());
1051852975d5377bfe5f4abc9d2a28e301aa2fa99994Dianne Hackborn                            file.write('\n');
1052852975d5377bfe5f4abc9d2a28e301aa2fa99994Dianne Hackborn                            atomicFile.finishWrite(file);
1053852975d5377bfe5f4abc9d2a28e301aa2fa99994Dianne Hackborn                        } catch (IOException e) {
1054852975d5377bfe5f4abc9d2a28e301aa2fa99994Dianne Hackborn                            if (file != null) {
1055852975d5377bfe5f4abc9d2a28e301aa2fa99994Dianne Hackborn                                atomicFile.failWrite(file);
105621d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                            }
1057852975d5377bfe5f4abc9d2a28e301aa2fa99994Dianne Hackborn                            Slog.e(TAG, "Unable to open " + atomicFile + " for persisting. " +
1058852975d5377bfe5f4abc9d2a28e301aa2fa99994Dianne Hackborn                                    e);
105921d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                        }
106021d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                    }
106121d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner                }
106221d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner            }
106321d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner        }
106421d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner    }
106518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
106618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    /**
106718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale     * Helper class for holding essential information about task that were backed-up on a different
106818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale     * device that can be restored on this device.
106918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale     */
107018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    private static class OtherDeviceTask implements Comparable<OtherDeviceTask> {
107118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        final File mFile;
107218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        // See {@link TaskRecord} for information on the fields below.
107318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        final ComponentName mComponentName;
107418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        final int mTaskId;
107518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        final int mAffiliatedTaskId;
107618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
107792dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale        // Names of packages that launched activities in this task. All packages listed here need
107892dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale        // to be installed on the current device in order for the task to be restored successfully.
107992dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale        final ArraySet<String> mLaunchPackages;
108092dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale
108192dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale        private OtherDeviceTask(File file, ComponentName componentName, int taskId,
108292dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                int affiliatedTaskId, ArraySet<String> launchPackages) {
108318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            mFile = file;
108418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            mComponentName = componentName;
108518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            mTaskId = taskId;
108618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            mAffiliatedTaskId = (affiliatedTaskId == INVALID_TASK_ID) ? taskId: affiliatedTaskId;
108792dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale            mLaunchPackages = launchPackages;
108818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        }
108918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
109018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        @Override
109118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        public int compareTo(OtherDeviceTask another) {
109218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            return mTaskId - another.mTaskId;
109318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        }
109418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
109518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        /**
109618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale         * Creates a new {@link OtherDeviceTask} object based on the contents of the input file.
109718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale         *
109818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale         * @param file input file that contains the complete task information.
109918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale         * @return new {@link OtherDeviceTask} object or null if we failed to create the object.
110018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale         */
110118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        static OtherDeviceTask createFromFile(File file) {
110218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            if (file == null || !file.exists()) {
110318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                if (DEBUG_RESTORER)
110418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    Slog.d(TAG, "createFromFile: file=" + file + " doesn't exist.");
110518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                return null;
110618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            }
110718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
110818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            BufferedReader reader = null;
110918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
111018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            try {
111118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                reader = new BufferedReader(new FileReader(file));
111218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                final XmlPullParser in = Xml.newPullParser();
111318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                in.setInput(reader);
111418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
111518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                int event;
111618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
111718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        event != XmlPullParser.START_TAG) {
111818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    // Skip to the start tag or end of document
111918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                }
112018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
112118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                if (event == XmlPullParser.START_TAG) {
112218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    final String name = in.getName();
112318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
112418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    if (TAG_TASK.equals(name)) {
112592dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                        final int outerDepth = in.getDepth();
112618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        ComponentName componentName = null;
112718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        int taskId = INVALID_TASK_ID;
112818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        int taskAffiliation = INVALID_TASK_ID;
112918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        for (int j = in.getAttributeCount() - 1; j >= 0; --j) {
113018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            final String attrName = in.getAttributeName(j);
113118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            final String attrValue = in.getAttributeValue(j);
113218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            if (TaskRecord.ATTR_REALACTIVITY.equals(attrName)) {
113318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                                componentName = ComponentName.unflattenFromString(attrValue);
113418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            } else if (TaskRecord.ATTR_TASKID.equals(attrName)) {
113518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                                taskId = Integer.valueOf(attrValue);
113618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            } else if (TaskRecord.ATTR_TASK_AFFILIATION.equals(attrName)) {
113718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                                taskAffiliation = Integer.valueOf(attrValue);
113818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            }
113918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        }
114018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        if (componentName == null || taskId == INVALID_TASK_ID) {
114118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            if (DEBUG_RESTORER) Slog.e(TAG,
114218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                                    "createFromFile: FAILED componentName=" + componentName
114318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                                    + " taskId=" + taskId + " file=" + file);
114418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                            return null;
114518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        }
114692dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale
114792dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                        ArraySet<String> launchPackages = null;
114892dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                        while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
114992dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                                (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) {
115092dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                            if (event == XmlPullParser.START_TAG) {
115192dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                                if (TaskRecord.TAG_ACTIVITY.equals(in.getName())) {
115292dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                                    for (int j = in.getAttributeCount() - 1; j >= 0; --j) {
115392dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                                        if (ActivityRecord.ATTR_LAUNCHEDFROMPACKAGE.equals(
115492dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                                                in.getAttributeName(j))) {
115592dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                                            if (launchPackages == null) {
115692dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                                                launchPackages = new ArraySet();
115792dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                                            }
115892dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                                            launchPackages.add(in.getAttributeValue(j));
115992dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                                        }
116092dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                                    }
116192dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                                } else {
116292dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                                    XmlUtils.skipCurrentTag(in);
116392dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                                }
116492dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                            }
116592dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                        }
116618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        if (DEBUG_RESTORER) Slog.d(TAG, "creating OtherDeviceTask from file="
116718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                                + file.getName() + " componentName=" + componentName
116892dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                                + " taskId=" + taskId + " launchPackages=" + launchPackages);
116992dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                        return new OtherDeviceTask(file, componentName, taskId,
117092dd1abef4c0a22db40c5f7bbd100e6b471a1ad3Wale Ogunwale                                taskAffiliation, launchPackages);
117118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    } else {
117218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                        Slog.wtf(TAG,
117318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                                "createFromFile: Unknown xml event=" + event + " name=" + name);
117418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    }
117518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                } else {
117618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                    Slog.wtf(TAG, "createFromFile: Unable to find start tag in file=" + file);
117718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                }
117818795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            } catch (IOException | XmlPullParserException e) {
117918795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                Slog.wtf(TAG, "Unable to parse " + file + ". Error ", e);
118018795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            } finally {
118118795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale                IoUtils.closeQuietly(reader);
118218795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            }
118318795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale
118418795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            // Something went wrong...
118518795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale            return null;
118618795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale        }
118718795a2299fefd88ee16393f22324b999ace6ce4Wale Ogunwale    }
118821d24a21ea4aaadd78e73de54168e8a8a8973e4dCraig Mautner}
1189