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