am a2968ad5: Merge "Revert "Backup/restore recents task list"" into mnc-dev
* commit 'a2968ad51e36190ad8042ec330237905bc7fe5c1': Revert "Backup/restore recents task list"
This commit is contained in:
@@ -2466,13 +2466,6 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
|
||||
return true;
|
||||
}
|
||||
|
||||
case SYSTEM_BACKUP_RESTORED: {
|
||||
data.enforceInterface(IActivityManager.descriptor);
|
||||
systemBackupRestored();
|
||||
reply.writeNoException();
|
||||
return true;
|
||||
}
|
||||
|
||||
case NOTIFY_CLEARTEXT_NETWORK_TRANSACTION: {
|
||||
data.enforceInterface(IActivityManager.descriptor);
|
||||
final int uid = data.readInt();
|
||||
@@ -5758,17 +5751,6 @@ class ActivityManagerProxy implements IActivityManager
|
||||
reply.recycle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void systemBackupRestored() throws RemoteException {
|
||||
Parcel data = Parcel.obtain();
|
||||
Parcel reply = Parcel.obtain();
|
||||
data.writeInterfaceToken(IActivityManager.descriptor);
|
||||
mRemote.transact(SYSTEM_BACKUP_RESTORED, data, reply, 0);
|
||||
reply.readException();
|
||||
data.recycle();
|
||||
reply.recycle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyCleartextNetwork(int uid, byte[] firstPacket) throws RemoteException {
|
||||
Parcel data = Parcel.obtain();
|
||||
|
||||
@@ -488,7 +488,6 @@ public interface IActivityManager extends IInterface {
|
||||
public void notifyLaunchTaskBehindComplete(IBinder token) throws RemoteException;
|
||||
public void notifyEnterAnimationComplete(IBinder token) throws RemoteException;
|
||||
|
||||
public void systemBackupRestored() throws RemoteException;
|
||||
public void notifyCleartextNetwork(int uid, byte[] firstPacket) throws RemoteException;
|
||||
|
||||
public void setDumpHeapDebugLimit(String processName, int uid, long maxMemSize,
|
||||
@@ -825,7 +824,6 @@ public interface IActivityManager extends IInterface {
|
||||
int START_IN_PLACE_ANIMATION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+240;
|
||||
int CHECK_PERMISSION_WITH_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+241;
|
||||
int REGISTER_TASK_STACK_LISTENER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+242;
|
||||
int SYSTEM_BACKUP_RESTORED = IBinder.FIRST_CALL_TRANSACTION+243;
|
||||
|
||||
// Start of M transactions
|
||||
int NOTIFY_CLEARTEXT_NETWORK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+280;
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.backup;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Environment;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.util.Slog;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Helper for saving/restoring 'recent tasks' infrastructure.
|
||||
* @hide
|
||||
*/
|
||||
public class RecentsBackupHelper implements BackupHelper {
|
||||
private static final String TAG = "RecentsBackup";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
// This must match TaskPersister.TASKS_DIRNAME, but that class is not accessible from here
|
||||
private static final String RECENTS_TASK_DIR = "recent_tasks";
|
||||
|
||||
// Must match TaskPersister.IMAGES_DIRNAME, as above
|
||||
private static final String RECENTS_IMAGE_DIR = "recent_images";
|
||||
|
||||
// At restore time, tasks/thumbnails are placed in these directories alongside
|
||||
// the "live" recents dirs named above.
|
||||
private static final String RECENTS_TASK_RESTORE_DIR = "restored_" + RECENTS_TASK_DIR;
|
||||
private static final String RECENTS_IMAGE_RESTORE_DIR = "restored_" + RECENTS_IMAGE_DIR;
|
||||
|
||||
// Prefixes for tagging the two kinds of recents backup records that we might generate
|
||||
private static final String RECENTS_TASK_KEY = "task:";
|
||||
private static final String RECENTS_IMAGE_KEY = "image:";
|
||||
|
||||
FileBackupHelperBase mTaskFileHelper;
|
||||
|
||||
final File mSystemDir;
|
||||
final File mTasksDir;
|
||||
final File mRestoredTasksDir;
|
||||
final File mRestoredImagesDir;
|
||||
final String[] mRecentFiles;
|
||||
final String[] mRecentKeys;
|
||||
|
||||
/**
|
||||
* @param context The agent context in which this helper instance will run
|
||||
*/
|
||||
public RecentsBackupHelper(Context context) {
|
||||
mTaskFileHelper = new FileBackupHelperBase(context);
|
||||
|
||||
mSystemDir = new File(Environment.getDataDirectory(), "system");
|
||||
mTasksDir = new File(mSystemDir, RECENTS_TASK_DIR);
|
||||
mRestoredTasksDir = new File(mSystemDir, RECENTS_TASK_RESTORE_DIR);
|
||||
mRestoredImagesDir = new File(mSystemDir, RECENTS_IMAGE_RESTORE_DIR);
|
||||
|
||||
// Currently we back up only the recent-task descriptions, not the thumbnails
|
||||
File[] recentFiles = mTasksDir.listFiles();
|
||||
if (recentFiles != null) {
|
||||
// We explicitly proceed even if this is a zero-size array
|
||||
final int N = recentFiles.length;
|
||||
mRecentKeys = new String[N];
|
||||
mRecentFiles = new String[N];
|
||||
if (DEBUG) {
|
||||
Slog.i(TAG, "Identifying recents for backup: " + N);
|
||||
}
|
||||
for (int i = 0; i < N; i++) {
|
||||
mRecentKeys[i] = new String(RECENTS_TASK_KEY + recentFiles[i].getName());
|
||||
mRecentFiles[i] = recentFiles[i].getAbsolutePath();
|
||||
if (DEBUG) {
|
||||
Slog.i(TAG, " " + mRecentKeys[i]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mRecentFiles = mRecentKeys = new String[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Task-file key: RECENTS_TASK_KEY + leaf filename
|
||||
* Thumbnail-file key: RECENTS_IMAGE_KEY + leaf filename
|
||||
*/
|
||||
@Override
|
||||
public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
|
||||
ParcelFileDescriptor newState) {
|
||||
FileBackupHelperBase.performBackup_checked(oldState, data, newState,
|
||||
mRecentFiles, mRecentKeys);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void restoreEntity(BackupDataInputStream data) {
|
||||
final String key = data.getKey();
|
||||
File output = null;
|
||||
if (key.startsWith(RECENTS_TASK_KEY)) {
|
||||
String name = key.substring(RECENTS_TASK_KEY.length());
|
||||
output = new File(mRestoredTasksDir, name);
|
||||
mRestoredTasksDir.mkdirs();
|
||||
} else if (key.startsWith(RECENTS_IMAGE_KEY)) {
|
||||
String name = key.substring(RECENTS_IMAGE_KEY.length());
|
||||
output = new File(mRestoredImagesDir, name);
|
||||
mRestoredImagesDir.mkdirs();
|
||||
}
|
||||
|
||||
if (output != null) {
|
||||
if (DEBUG) {
|
||||
Slog.i(TAG, "Restoring key='"
|
||||
+ key + "' to " + output.getAbsolutePath());
|
||||
}
|
||||
mTaskFileHelper.writeFile(output, data);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeNewStateDescription(ParcelFileDescriptor newState) {
|
||||
mTaskFileHelper.writeNewStateDescription(newState);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,14 +16,12 @@
|
||||
|
||||
package com.android.server.backup;
|
||||
|
||||
import android.app.ActivityManagerNative;
|
||||
import android.app.IWallpaperManager;
|
||||
import android.app.backup.BackupDataInput;
|
||||
import android.app.backup.BackupDataOutput;
|
||||
import android.app.backup.BackupAgentHelper;
|
||||
import android.app.backup.FullBackup;
|
||||
import android.app.backup.FullBackupDataOutput;
|
||||
import android.app.backup.RecentsBackupHelper;
|
||||
import android.app.backup.WallpaperBackupHelper;
|
||||
import android.content.Context;
|
||||
import android.os.Environment;
|
||||
@@ -45,7 +43,6 @@ public class SystemBackupAgent extends BackupAgentHelper {
|
||||
// Names of the helper tags within the dataset. Changing one of these names will
|
||||
// break the ability to restore from datasets that predate the change.
|
||||
private static final String WALLPAPER_HELPER = "wallpaper";
|
||||
private static final String RECENTS_HELPER = "recents";
|
||||
private static final String SYNC_SETTINGS_HELPER = "account_sync_settings";
|
||||
private static final String PREFERRED_HELPER = "preferred_activities";
|
||||
private static final String NOTIFICATION_HELPER = "notifications";
|
||||
@@ -92,7 +89,6 @@ public class SystemBackupAgent extends BackupAgentHelper {
|
||||
}
|
||||
}
|
||||
addHelper(WALLPAPER_HELPER, new WallpaperBackupHelper(this, files, keys));
|
||||
addHelper(RECENTS_HELPER, new RecentsBackupHelper(this));
|
||||
addHelper(SYNC_SETTINGS_HELPER, new AccountSyncSettingsBackupHelper(this));
|
||||
addHelper(PREFERRED_HELPER, new PreferredActivityBackupHelper());
|
||||
addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(this));
|
||||
@@ -127,7 +123,6 @@ public class SystemBackupAgent extends BackupAgentHelper {
|
||||
addHelper("system_files", new WallpaperBackupHelper(this,
|
||||
new String[] { WALLPAPER_IMAGE },
|
||||
new String[] { WALLPAPER_IMAGE_KEY} ));
|
||||
addHelper(RECENTS_HELPER, new RecentsBackupHelper(this));
|
||||
addHelper(SYNC_SETTINGS_HELPER, new AccountSyncSettingsBackupHelper(this));
|
||||
addHelper(PREFERRED_HELPER, new PreferredActivityBackupHelper());
|
||||
addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(this));
|
||||
@@ -200,13 +195,4 @@ public class SystemBackupAgent extends BackupAgentHelper {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestoreFinished() {
|
||||
try {
|
||||
ActivityManagerNative.getDefault().systemBackupRestored();
|
||||
} catch (RemoteException e) {
|
||||
// Not possible since this code is running in the system process.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6164,17 +6164,6 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void systemBackupRestored() {
|
||||
synchronized (this) {
|
||||
if (mSystemReady) {
|
||||
mTaskPersister.restoreTasksFromOtherDeviceLocked();
|
||||
} else {
|
||||
Slog.w(TAG, "System backup restored before system is ready");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final void ensureBootCompleted() {
|
||||
boolean booting;
|
||||
boolean enableScreen;
|
||||
@@ -11327,7 +11316,6 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
|
||||
mRecentTasks.clear();
|
||||
mRecentTasks.addAll(mTaskPersister.restoreTasksLocked());
|
||||
mTaskPersister.restoreTasksFromOtherDeviceLocked();
|
||||
mRecentTasks.cleanupLocked(UserHandle.USER_ALL);
|
||||
mTaskPersister.startPersisting();
|
||||
|
||||
@@ -16191,18 +16179,12 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
removeUriPermissionsForPackageLocked(ssp, userId, true);
|
||||
|
||||
removeTasksByPackageNameLocked(ssp, userId);
|
||||
if (userId == UserHandle.USER_OWNER) {
|
||||
mTaskPersister.removeFromPackageCache(ssp);
|
||||
}
|
||||
mBatteryStatsService.notePackageUninstalled(ssp);
|
||||
}
|
||||
} else {
|
||||
cleanupDisabledPackageComponentsLocked(ssp, userId,
|
||||
intent.getStringArrayExtra(
|
||||
Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST));
|
||||
if (userId == UserHandle.USER_OWNER) {
|
||||
mTaskPersister.addOtherDeviceTasksToRecentsLocked(ssp);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -16217,8 +16199,8 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
|
||||
mCompatModePackages.handlePackageAddedLocked(ssp, replacing);
|
||||
|
||||
if (userId == UserHandle.USER_OWNER) {
|
||||
mTaskPersister.addOtherDeviceTasksToRecentsLocked(ssp);
|
||||
if (replacing) {
|
||||
removeTasksByRemovedPackageComponentsLocked(ssp, userId);
|
||||
}
|
||||
try {
|
||||
ApplicationInfo ai = AppGlobals.getPackageManager().
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
package com.android.server.am;
|
||||
|
||||
import static com.android.server.am.ActivityManagerDebugConfig.*;
|
||||
import static com.android.server.am.TaskPersister.DEBUG_PERSISTER;
|
||||
import static com.android.server.am.TaskPersister.DEBUG_RESTORER;
|
||||
import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
|
||||
|
||||
import android.app.ActivityManager.TaskDescription;
|
||||
@@ -85,7 +83,7 @@ final class ActivityRecord {
|
||||
private static final String ATTR_USERID = "user_id";
|
||||
private static final String TAG_PERSISTABLEBUNDLE = "persistable_bundle";
|
||||
private static final String ATTR_LAUNCHEDFROMUID = "launched_from_uid";
|
||||
static final String ATTR_LAUNCHEDFROMPACKAGE = "launched_from_package";
|
||||
private static final String ATTR_LAUNCHEDFROMPACKAGE = "launched_from_package";
|
||||
private static final String ATTR_RESOLVEDTYPE = "resolved_type";
|
||||
private static final String ATTR_COMPONENTSPECIFIED = "component_specified";
|
||||
static final String ACTIVITY_ICON_SUFFIX = "_activity_icon_";
|
||||
@@ -94,7 +92,7 @@ final class ActivityRecord {
|
||||
final IApplicationToken.Stub appToken; // window manager token
|
||||
final ActivityInfo info; // all about me
|
||||
final ApplicationInfo appInfo; // information about activity's app
|
||||
int launchedFromUid; // always the uid who started the activity.
|
||||
final int launchedFromUid; // always the uid who started the activity.
|
||||
final String launchedFromPackage; // always the package who started the activity.
|
||||
final int userId; // Which user is this running for?
|
||||
final Intent intent; // the original intent that generated us
|
||||
@@ -1178,8 +1176,8 @@ final class ActivityRecord {
|
||||
}
|
||||
}
|
||||
|
||||
static ActivityRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
|
||||
throws IOException, XmlPullParserException {
|
||||
static ActivityRecord restoreFromXml(XmlPullParser in,
|
||||
ActivityStackSupervisor stackSupervisor) throws IOException, XmlPullParserException {
|
||||
Intent intent = null;
|
||||
PersistableBundle persistentState = null;
|
||||
int launchedFromUid = 0;
|
||||
@@ -1194,7 +1192,7 @@ final class ActivityRecord {
|
||||
for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
|
||||
final String attrName = in.getAttributeName(attrNdx);
|
||||
final String attrValue = in.getAttributeValue(attrNdx);
|
||||
if (DEBUG_PERSISTER || DEBUG_RESTORER) Slog.d(TaskPersister.TAG,
|
||||
if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG,
|
||||
"ActivityRecord: attribute name=" + attrName + " value=" + attrValue);
|
||||
if (ATTR_ID.equals(attrName)) {
|
||||
createTime = Long.valueOf(attrValue);
|
||||
@@ -1220,15 +1218,15 @@ final class ActivityRecord {
|
||||
(event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) {
|
||||
if (event == XmlPullParser.START_TAG) {
|
||||
final String name = in.getName();
|
||||
if (DEBUG_PERSISTER || DEBUG_RESTORER)
|
||||
if (TaskPersister.DEBUG)
|
||||
Slog.d(TaskPersister.TAG, "ActivityRecord: START_TAG name=" + name);
|
||||
if (TAG_INTENT.equals(name)) {
|
||||
intent = Intent.restoreFromXml(in);
|
||||
if (DEBUG_PERSISTER || DEBUG_RESTORER)
|
||||
if (TaskPersister.DEBUG)
|
||||
Slog.d(TaskPersister.TAG, "ActivityRecord: intent=" + intent);
|
||||
} else if (TAG_PERSISTABLEBUNDLE.equals(name)) {
|
||||
persistentState = PersistableBundle.restoreFromXml(in);
|
||||
if (DEBUG_PERSISTER || DEBUG_RESTORER) Slog.d(TaskPersister.TAG,
|
||||
if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG,
|
||||
"ActivityRecord: persistentState=" + persistentState);
|
||||
} else {
|
||||
Slog.w(TAG, "restoreActivity: unexpected name=" + name);
|
||||
|
||||
@@ -59,8 +59,7 @@ import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
|
||||
|
||||
public class TaskPersister {
|
||||
static final String TAG = "TaskPersister";
|
||||
static final boolean DEBUG_PERSISTER = false;
|
||||
static final boolean DEBUG_RESTORER = false;
|
||||
static final boolean DEBUG = false;
|
||||
|
||||
/** When not flushing don't write out files faster than this */
|
||||
private static final long INTER_WRITE_DELAY_MS = 500;
|
||||
@@ -81,21 +80,10 @@ public class TaskPersister {
|
||||
private static final String IMAGES_DIRNAME = "recent_images";
|
||||
static final String IMAGE_EXTENSION = ".png";
|
||||
|
||||
// Directory where restored historical task XML/PNG files are placed. This directory
|
||||
// contains subdirs named after TASKS_DIRNAME and IMAGES_DIRNAME mirroring the
|
||||
// ancestral device's dataset. This needs to match the RECENTS_TASK_RESTORE_DIR
|
||||
// value in RecentsBackupHelper.
|
||||
private static final String RESTORED_TASKS_DIRNAME = "restored_" + TASKS_DIRNAME;
|
||||
|
||||
// Max time to wait for the application/package of a restored task to be installed
|
||||
// before giving up.
|
||||
private static final long MAX_INSTALL_WAIT_TIME = DateUtils.DAY_IN_MILLIS;
|
||||
|
||||
private static final String TAG_TASK = "task";
|
||||
|
||||
static File sImagesDir;
|
||||
static File sTasksDir;
|
||||
static File sRestoredTasksDir;
|
||||
|
||||
private final ActivityManagerService mService;
|
||||
private final ActivityStackSupervisor mStackSupervisor;
|
||||
@@ -129,23 +117,11 @@ public class TaskPersister {
|
||||
|
||||
ArrayList<WriteQueueItem> mWriteQueue = new ArrayList<WriteQueueItem>();
|
||||
|
||||
// Map of tasks that were backed-up on a different device that can be restored on this device.
|
||||
// Data organization: <packageNameOfAffiliateTask, listOfAffiliatedTasksChains>
|
||||
private ArrayMap<String, List<List<OtherDeviceTask>>> mOtherDeviceTasksMap =
|
||||
new ArrayMap<>(10);
|
||||
// Local cache of package names to uid used when restoring a task from another device.
|
||||
private ArrayMap<String, Integer> mPackageUidMap;
|
||||
|
||||
// The next time in milliseconds we will remove expired task from
|
||||
// {@link #mOtherDeviceTasksMap} and disk. Set to {@link Long.MAX_VALUE} to never clean-up
|
||||
// tasks.
|
||||
private long mExpiredTasksCleanupTime = Long.MAX_VALUE;
|
||||
|
||||
TaskPersister(File systemDir, ActivityStackSupervisor stackSupervisor,
|
||||
RecentTasks recentTasks) {
|
||||
sTasksDir = new File(systemDir, TASKS_DIRNAME);
|
||||
if (!sTasksDir.exists()) {
|
||||
if (DEBUG_PERSISTER) Slog.d(TAG, "Creating tasks directory " + sTasksDir);
|
||||
if (DEBUG) Slog.d(TAG, "Creating tasks directory " + sTasksDir);
|
||||
if (!sTasksDir.mkdir()) {
|
||||
Slog.e(TAG, "Failure creating tasks directory " + sTasksDir);
|
||||
}
|
||||
@@ -153,14 +129,12 @@ public class TaskPersister {
|
||||
|
||||
sImagesDir = new File(systemDir, IMAGES_DIRNAME);
|
||||
if (!sImagesDir.exists()) {
|
||||
if (DEBUG_PERSISTER) Slog.d(TAG, "Creating images directory " + sTasksDir);
|
||||
if (DEBUG) Slog.d(TAG, "Creating images directory " + sTasksDir);
|
||||
if (!sImagesDir.mkdir()) {
|
||||
Slog.e(TAG, "Failure creating images directory " + sImagesDir);
|
||||
}
|
||||
}
|
||||
|
||||
sRestoredTasksDir = new File(systemDir, RESTORED_TASKS_DIRNAME);
|
||||
|
||||
mStackSupervisor = stackSupervisor;
|
||||
mService = stackSupervisor.mService;
|
||||
mRecentTasks = recentTasks;
|
||||
@@ -179,8 +153,8 @@ public class TaskPersister {
|
||||
final WriteQueueItem item = mWriteQueue.get(queueNdx);
|
||||
if (item instanceof ImageWriteQueueItem &&
|
||||
((ImageWriteQueueItem) item).mFilename.startsWith(taskString)) {
|
||||
if (DEBUG_PERSISTER) Slog.d(TAG, "Removing "
|
||||
+ ((ImageWriteQueueItem) item).mFilename + " from write queue");
|
||||
if (DEBUG) Slog.d(TAG, "Removing " + ((ImageWriteQueueItem) item).mFilename +
|
||||
" from write queue");
|
||||
mWriteQueue.remove(queueNdx);
|
||||
}
|
||||
}
|
||||
@@ -225,9 +199,9 @@ public class TaskPersister {
|
||||
} else if (mNextWriteTime == 0) {
|
||||
mNextWriteTime = SystemClock.uptimeMillis() + PRE_TASK_DELAY_MS;
|
||||
}
|
||||
if (DEBUG_PERSISTER) Slog.d(TAG, "wakeup: task=" + task + " flush=" + flush
|
||||
+ " mNextWriteTime=" + mNextWriteTime + " mWriteQueue.size="
|
||||
+ mWriteQueue.size() + " Callers=" + Debug.getCallers(4));
|
||||
if (DEBUG) Slog.d(TAG, "wakeup: task=" + task + " flush=" + flush + " mNextWriteTime="
|
||||
+ mNextWriteTime + " mWriteQueue.size=" + mWriteQueue.size()
|
||||
+ " Callers=" + Debug.getCallers(4));
|
||||
notifyAll();
|
||||
}
|
||||
|
||||
@@ -269,7 +243,7 @@ public class TaskPersister {
|
||||
} else if (mNextWriteTime == 0) {
|
||||
mNextWriteTime = SystemClock.uptimeMillis() + PRE_TASK_DELAY_MS;
|
||||
}
|
||||
if (DEBUG_PERSISTER) Slog.d(TAG, "saveImage: filename=" + filename + " now=" +
|
||||
if (DEBUG) Slog.d(TAG, "saveImage: filename=" + filename + " now=" +
|
||||
SystemClock.uptimeMillis() + " mNextWriteTime=" +
|
||||
mNextWriteTime + " Callers=" + Debug.getCallers(4));
|
||||
notifyAll();
|
||||
@@ -303,12 +277,12 @@ public class TaskPersister {
|
||||
}
|
||||
|
||||
private StringWriter saveToXml(TaskRecord task) throws IOException, XmlPullParserException {
|
||||
if (DEBUG_PERSISTER) Slog.d(TAG, "saveToXml: task=" + task);
|
||||
if (DEBUG) Slog.d(TAG, "saveToXml: task=" + task);
|
||||
final XmlSerializer xmlSerializer = new FastXmlSerializer();
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
xmlSerializer.setOutput(stringWriter);
|
||||
|
||||
if (DEBUG_PERSISTER) xmlSerializer.setFeature(
|
||||
if (DEBUG) xmlSerializer.setFeature(
|
||||
"http://xmlpull.org/v1/doc/features.html#indent-output", true);
|
||||
|
||||
// save task
|
||||
@@ -367,7 +341,7 @@ public class TaskPersister {
|
||||
|
||||
for (int taskNdx = 0; taskNdx < recentFiles.length; ++taskNdx) {
|
||||
File taskFile = recentFiles[taskNdx];
|
||||
if (DEBUG_PERSISTER) Slog.d(TAG, "restoreTasksLocked: taskFile=" + taskFile.getName());
|
||||
if (DEBUG) Slog.d(TAG, "restoreTasksLocked: taskFile=" + taskFile.getName());
|
||||
BufferedReader reader = null;
|
||||
boolean deleteFile = false;
|
||||
try {
|
||||
@@ -380,12 +354,11 @@ public class TaskPersister {
|
||||
event != XmlPullParser.END_TAG) {
|
||||
final String name = in.getName();
|
||||
if (event == XmlPullParser.START_TAG) {
|
||||
if (DEBUG_PERSISTER)
|
||||
Slog.d(TAG, "restoreTasksLocked: START_TAG name=" + name);
|
||||
if (DEBUG) Slog.d(TAG, "restoreTasksLocked: START_TAG name=" + name);
|
||||
if (TAG_TASK.equals(name)) {
|
||||
final TaskRecord task =
|
||||
TaskRecord.restoreFromXml(in, mStackSupervisor);
|
||||
if (DEBUG_PERSISTER) Slog.d(TAG, "restoreTasksLocked: restored task=" +
|
||||
if (DEBUG) Slog.d(TAG, "restoreTasksLocked: restored task=" +
|
||||
task);
|
||||
if (task != null) {
|
||||
task.isPersistable = true;
|
||||
@@ -414,15 +387,14 @@ public class TaskPersister {
|
||||
deleteFile = true;
|
||||
} finally {
|
||||
IoUtils.closeQuietly(reader);
|
||||
if (!DEBUG_PERSISTER && deleteFile) {
|
||||
if (true || DEBUG_PERSISTER)
|
||||
Slog.d(TAG, "Deleting file=" + taskFile.getName());
|
||||
if (deleteFile) {
|
||||
if (DEBUG) Slog.d(TAG, "Deleting file=" + taskFile.getName());
|
||||
taskFile.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!DEBUG_PERSISTER) {
|
||||
if (!DEBUG) {
|
||||
removeObsoleteFiles(recoveredTaskIds);
|
||||
}
|
||||
|
||||
@@ -453,8 +425,8 @@ public class TaskPersister {
|
||||
}
|
||||
|
||||
private static void removeObsoleteFiles(ArraySet<Integer> persistentTaskIds, File[] files) {
|
||||
if (DEBUG_PERSISTER) Slog.d(TAG, "removeObsoleteFile: persistentTaskIds="
|
||||
+ persistentTaskIds + " files=" + files);
|
||||
if (DEBUG) Slog.d(TAG, "removeObsoleteFile: persistentTaskIds=" + persistentTaskIds +
|
||||
" files=" + files);
|
||||
if (files == null) {
|
||||
Slog.e(TAG, "File error accessing recents directory (too many files open?).");
|
||||
return;
|
||||
@@ -467,15 +439,14 @@ public class TaskPersister {
|
||||
final int taskId;
|
||||
try {
|
||||
taskId = Integer.valueOf(filename.substring(0, taskIdEnd));
|
||||
if (DEBUG_PERSISTER) Slog.d(TAG, "removeObsoleteFile: Found taskId=" + taskId);
|
||||
if (DEBUG) Slog.d(TAG, "removeObsoleteFile: Found taskId=" + taskId);
|
||||
} catch (Exception e) {
|
||||
Slog.wtf(TAG, "removeObsoleteFile: Can't parse file=" + file.getName());
|
||||
file.delete();
|
||||
continue;
|
||||
}
|
||||
if (!persistentTaskIds.contains(taskId)) {
|
||||
if (true || DEBUG_PERSISTER) Slog.d(TAG, "removeObsoleteFile: deleting file=" +
|
||||
file.getName());
|
||||
if (DEBUG) Slog.d(TAG, "removeObsoleteFile: deleting file=" + file.getName());
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
@@ -488,441 +459,10 @@ public class TaskPersister {
|
||||
}
|
||||
|
||||
static Bitmap restoreImage(String filename) {
|
||||
if (DEBUG_PERSISTER) Slog.d(TAG, "restoreImage: restoring " + filename);
|
||||
if (DEBUG) Slog.d(TAG, "restoreImage: restoring " + filename);
|
||||
return BitmapFactory.decodeFile(sImagesDir + File.separator + filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to restore task that were backed-up on a different device onto this device.
|
||||
*/
|
||||
void restoreTasksFromOtherDeviceLocked() {
|
||||
readOtherDeviceTasksFromDisk();
|
||||
addOtherDeviceTasksToRecentsLocked();
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the tasks that were backed-up on a different device and can be restored to this device
|
||||
* from disk and populated {@link #mOtherDeviceTasksMap} with the information. Also sets up
|
||||
* time to clear out other device tasks that have not been restored on this device
|
||||
* within the allotted time.
|
||||
*/
|
||||
private void readOtherDeviceTasksFromDisk() {
|
||||
synchronized (mOtherDeviceTasksMap) {
|
||||
// Clear out current map and expiration time.
|
||||
mOtherDeviceTasksMap.clear();
|
||||
mExpiredTasksCleanupTime = Long.MAX_VALUE;
|
||||
|
||||
final File[] taskFiles;
|
||||
if (!sRestoredTasksDir.exists()
|
||||
|| (taskFiles = sRestoredTasksDir.listFiles()) == null) {
|
||||
// Nothing to do if there are no tasks to restore.
|
||||
return;
|
||||
}
|
||||
|
||||
long earliestMtime = System.currentTimeMillis();
|
||||
SparseArray<List<OtherDeviceTask>> tasksByAffiliateIds =
|
||||
new SparseArray<>(taskFiles.length);
|
||||
|
||||
// Read new tasks from disk
|
||||
for (int i = 0; i < taskFiles.length; ++i) {
|
||||
final File taskFile = taskFiles[i];
|
||||
if (DEBUG_RESTORER) Slog.d(TAG, "readOtherDeviceTasksFromDisk: taskFile="
|
||||
+ taskFile.getName());
|
||||
|
||||
final OtherDeviceTask task = OtherDeviceTask.createFromFile(taskFile);
|
||||
|
||||
if (task == null) {
|
||||
// Go ahead and remove the file on disk if we are unable to create a task from
|
||||
// it.
|
||||
if (DEBUG_RESTORER) Slog.e(TAG, "Unable to create task for file="
|
||||
+ taskFile.getName() + "...deleting file.");
|
||||
taskFile.delete();
|
||||
continue;
|
||||
}
|
||||
|
||||
List<OtherDeviceTask> tasks = tasksByAffiliateIds.get(task.mAffiliatedTaskId);
|
||||
if (tasks == null) {
|
||||
tasks = new ArrayList<>();
|
||||
tasksByAffiliateIds.put(task.mAffiliatedTaskId, tasks);
|
||||
}
|
||||
tasks.add(task);
|
||||
final long taskMtime = taskFile.lastModified();
|
||||
if (earliestMtime > taskMtime) {
|
||||
earliestMtime = taskMtime;
|
||||
}
|
||||
}
|
||||
|
||||
if (tasksByAffiliateIds.size() > 0) {
|
||||
// Sort each affiliated tasks chain by taskId which is the order they were created
|
||||
// that should always be correct...Then add to task map.
|
||||
for (int i = 0; i < tasksByAffiliateIds.size(); i++) {
|
||||
List<OtherDeviceTask> chain = tasksByAffiliateIds.valueAt(i);
|
||||
Collections.sort(chain);
|
||||
// Package name of the root task in the affiliate chain.
|
||||
final String packageName =
|
||||
chain.get(chain.size()-1).mComponentName.getPackageName();
|
||||
List<List<OtherDeviceTask>> chains = mOtherDeviceTasksMap.get(packageName);
|
||||
if (chains == null) {
|
||||
chains = new ArrayList<>();
|
||||
mOtherDeviceTasksMap.put(packageName, chains);
|
||||
}
|
||||
chains.add(chain);
|
||||
}
|
||||
|
||||
// Set expiration time.
|
||||
mExpiredTasksCleanupTime = earliestMtime + MAX_INSTALL_WAIT_TIME;
|
||||
if (DEBUG_RESTORER) Slog.d(TAG, "Set Expiration time to "
|
||||
+ DateUtils.formatDateTime(mService.mContext, mExpiredTasksCleanupTime,
|
||||
DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removed any expired tasks from {@link #mOtherDeviceTasksMap} and disk if their expiration
|
||||
* time is less than or equal to {@link #mExpiredTasksCleanupTime}.
|
||||
*/
|
||||
private void removeExpiredTasksIfNeeded() {
|
||||
synchronized (mOtherDeviceTasksMap) {
|
||||
final long now = System.currentTimeMillis();
|
||||
final boolean noMoreTasks = mOtherDeviceTasksMap.isEmpty();
|
||||
if (noMoreTasks || now < mExpiredTasksCleanupTime) {
|
||||
if (noMoreTasks && mPackageUidMap != null) {
|
||||
// All done! package->uid map no longer needed.
|
||||
mPackageUidMap = null;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
long earliestNonExpiredMtime = now;
|
||||
mExpiredTasksCleanupTime = Long.MAX_VALUE;
|
||||
|
||||
// Remove expired backed-up tasks that have not been restored. We only want to
|
||||
// remove task if it is safe to remove all tasks in the affiliation chain.
|
||||
for (int i = mOtherDeviceTasksMap.size() - 1; i >= 0 ; i--) {
|
||||
|
||||
List<List<OtherDeviceTask>> chains = mOtherDeviceTasksMap.valueAt(i);
|
||||
for (int j = chains.size() - 1; j >= 0 ; j--) {
|
||||
|
||||
List<OtherDeviceTask> chain = chains.get(j);
|
||||
boolean removeChain = true;
|
||||
for (int k = chain.size() - 1; k >= 0 ; k--) {
|
||||
OtherDeviceTask task = chain.get(k);
|
||||
final long taskLastModified = task.mFile.lastModified();
|
||||
if ((taskLastModified + MAX_INSTALL_WAIT_TIME) > now) {
|
||||
// File has not expired yet...but we keep looping to get the earliest
|
||||
// mtime.
|
||||
if (earliestNonExpiredMtime > taskLastModified) {
|
||||
earliestNonExpiredMtime = taskLastModified;
|
||||
}
|
||||
removeChain = false;
|
||||
}
|
||||
}
|
||||
if (removeChain) {
|
||||
for (int k = chain.size() - 1; k >= 0; k--) {
|
||||
final File file = chain.get(k).mFile;
|
||||
if (DEBUG_RESTORER) Slog.d(TAG, "Deleting expired file="
|
||||
+ file.getName() + " mapped to not installed component="
|
||||
+ chain.get(k).mComponentName);
|
||||
file.delete();
|
||||
}
|
||||
chains.remove(j);
|
||||
}
|
||||
}
|
||||
if (chains.isEmpty()) {
|
||||
final String packageName = mOtherDeviceTasksMap.keyAt(i);
|
||||
mOtherDeviceTasksMap.removeAt(i);
|
||||
if (DEBUG_RESTORER) Slog.d(TAG, "Removed package=" + packageName
|
||||
+ " from task map");
|
||||
}
|
||||
}
|
||||
|
||||
// Reset expiration time if there is any task remaining.
|
||||
if (!mOtherDeviceTasksMap.isEmpty()) {
|
||||
mExpiredTasksCleanupTime = earliestNonExpiredMtime + MAX_INSTALL_WAIT_TIME;
|
||||
if (DEBUG_RESTORER) Slog.d(TAG, "Reset expiration time to "
|
||||
+ DateUtils.formatDateTime(mService.mContext, mExpiredTasksCleanupTime,
|
||||
DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME));
|
||||
} else {
|
||||
// All done! package->uid map no longer needed.
|
||||
mPackageUidMap = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the input package name from the local package->uid map.
|
||||
*/
|
||||
void removeFromPackageCache(String packageName) {
|
||||
synchronized (mOtherDeviceTasksMap) {
|
||||
if (mPackageUidMap != null) {
|
||||
mPackageUidMap.remove(packageName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to add all backed-up tasks from another device to this device recent's list.
|
||||
*/
|
||||
private void addOtherDeviceTasksToRecentsLocked() {
|
||||
synchronized (mOtherDeviceTasksMap) {
|
||||
for (int i = mOtherDeviceTasksMap.size() - 1; i >= 0; i--) {
|
||||
addOtherDeviceTasksToRecentsLocked(mOtherDeviceTasksMap.keyAt(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to add backed-up tasks that are associated with the input package from
|
||||
* another device to this device recent's list.
|
||||
*/
|
||||
void addOtherDeviceTasksToRecentsLocked(String packageName) {
|
||||
synchronized (mOtherDeviceTasksMap) {
|
||||
List<List<OtherDeviceTask>> chains = mOtherDeviceTasksMap.get(packageName);
|
||||
if (chains == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = chains.size() - 1; i >= 0; i--) {
|
||||
List<OtherDeviceTask> chain = chains.get(i);
|
||||
if (!canAddOtherDeviceTaskChain(chain)) {
|
||||
if (DEBUG_RESTORER) Slog.d(TAG, "Can't add task chain at index=" + i
|
||||
+ " for package=" + packageName);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Generate task records for this chain.
|
||||
List<TaskRecord> tasks = new ArrayList<>();
|
||||
TaskRecord prev = null;
|
||||
for (int j = chain.size() - 1; j >= 0; j--) {
|
||||
TaskRecord task = createTaskRecordLocked(chain.get(j));
|
||||
if (task == null) {
|
||||
// There was a problem in creating one of this task records in this chain.
|
||||
// There is no way we can continue...
|
||||
if (DEBUG_RESTORER) Slog.d(TAG, "Can't create task record for file="
|
||||
+ chain.get(j).mFile + " for package=" + packageName);
|
||||
break;
|
||||
}
|
||||
|
||||
// Wire-up affiliation chain.
|
||||
if (prev == null) {
|
||||
task.mPrevAffiliate = null;
|
||||
task.mPrevAffiliateTaskId = INVALID_TASK_ID;
|
||||
task.mAffiliatedTaskId = task.taskId;
|
||||
} else {
|
||||
prev.mNextAffiliate = task;
|
||||
prev.mNextAffiliateTaskId = task.taskId;
|
||||
task.mAffiliatedTaskId = prev.mAffiliatedTaskId;
|
||||
task.mPrevAffiliate = prev;
|
||||
task.mPrevAffiliateTaskId = prev.taskId;
|
||||
}
|
||||
prev = task;
|
||||
tasks.add(0, task);
|
||||
}
|
||||
|
||||
// Add tasks to recent's if we were able to create task records for all the tasks
|
||||
// in the chain.
|
||||
if (tasks.size() == chain.size()) {
|
||||
// Make sure there is space in recent's to add the new task. If there is space
|
||||
// to the to the back.
|
||||
// TODO: Would be more fancy to interleave the new tasks into recent's based on
|
||||
// {@link TaskRecord.mLastTimeMoved} and drop the oldest recent's vs. just
|
||||
// adding to the back of the list.
|
||||
int spaceLeft =
|
||||
ActivityManager.getMaxRecentTasksStatic() - mRecentTasks.size();
|
||||
if (spaceLeft >= tasks.size()) {
|
||||
mRecentTasks.addAll(mRecentTasks.size(), tasks);
|
||||
for (int k = tasks.size() - 1; k >= 0; k--) {
|
||||
// Persist new tasks.
|
||||
wakeup(tasks.get(k), false);
|
||||
}
|
||||
|
||||
if (DEBUG_RESTORER) Slog.d(TAG, "Added " + tasks.size()
|
||||
+ " tasks to recent's for" + " package=" + packageName);
|
||||
} else {
|
||||
if (DEBUG_RESTORER) Slog.d(TAG, "Didn't add to recents. tasks.size("
|
||||
+ tasks.size() + ") != chain.size(" + chain.size()
|
||||
+ ") for package=" + packageName);
|
||||
}
|
||||
} else {
|
||||
if (DEBUG_RESTORER) Slog.v(TAG, "Unable to add restored tasks to recents "
|
||||
+ tasks.size() + " tasks for package=" + packageName);
|
||||
}
|
||||
|
||||
// Clean-up structures
|
||||
for (int j = chain.size() - 1; j >= 0; j--) {
|
||||
chain.get(j).mFile.delete();
|
||||
}
|
||||
chains.remove(i);
|
||||
if (chains.isEmpty()) {
|
||||
// The fate of all backed-up tasks associated with this package has been
|
||||
// determine. Go ahead and remove it from the to-process list.
|
||||
mOtherDeviceTasksMap.remove(packageName);
|
||||
if (DEBUG_RESTORER)
|
||||
Slog.d(TAG, "Removed package=" + packageName + " from restore map");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns {@link TaskRecord} for the task from another device that can be used on
|
||||
* this device. Returns null if the operation failed.
|
||||
*/
|
||||
private TaskRecord createTaskRecordLocked(OtherDeviceTask other) {
|
||||
File file = other.mFile;
|
||||
BufferedReader reader = null;
|
||||
TaskRecord task = null;
|
||||
if (DEBUG_RESTORER) Slog.d(TAG, "createTaskRecordLocked: file=" + file.getName());
|
||||
|
||||
try {
|
||||
reader = new BufferedReader(new FileReader(file));
|
||||
final XmlPullParser in = Xml.newPullParser();
|
||||
in.setInput(reader);
|
||||
|
||||
int event;
|
||||
while (((event = in.next()) != XmlPullParser.END_DOCUMENT)
|
||||
&& event != XmlPullParser.END_TAG) {
|
||||
final String name = in.getName();
|
||||
if (event == XmlPullParser.START_TAG) {
|
||||
|
||||
if (TAG_TASK.equals(name)) {
|
||||
// Create a task record using a task id that is valid for this device.
|
||||
task = TaskRecord.restoreFromXml(
|
||||
in, mStackSupervisor, mStackSupervisor.getNextTaskId());
|
||||
if (DEBUG_RESTORER)
|
||||
Slog.d(TAG, "createTaskRecordLocked: restored task=" + task);
|
||||
|
||||
if (task != null) {
|
||||
task.isPersistable = true;
|
||||
task.inRecents = true;
|
||||
// Task can/should only be backed-up/restored for device owner.
|
||||
task.userId = UserHandle.USER_OWNER;
|
||||
// Clear out affiliated ids that are no longer valid on this device.
|
||||
task.mAffiliatedTaskId = INVALID_TASK_ID;
|
||||
task.mPrevAffiliateTaskId = INVALID_TASK_ID;
|
||||
task.mNextAffiliateTaskId = INVALID_TASK_ID;
|
||||
// Set up uids valid for this device.
|
||||
Integer uid = mPackageUidMap.get(task.realActivity.getPackageName());
|
||||
if (uid == null) {
|
||||
// How did this happen???
|
||||
Slog.wtf(TAG, "Can't find uid for task=" + task
|
||||
+ " in mPackageUidMap=" + mPackageUidMap);
|
||||
return null;
|
||||
}
|
||||
task.effectiveUid = task.mCallingUid = uid;
|
||||
for (int i = task.mActivities.size() - 1; i >= 0; --i) {
|
||||
final ActivityRecord activity = task.mActivities.get(i);
|
||||
uid = mPackageUidMap.get(activity.launchedFromPackage);
|
||||
if (uid == null) {
|
||||
// How did this happen??
|
||||
Slog.wtf(TAG, "Can't find uid for activity=" + activity
|
||||
+ " in mPackageUidMap=" + mPackageUidMap);
|
||||
return null;
|
||||
}
|
||||
activity.launchedFromUid = uid;
|
||||
}
|
||||
|
||||
} else {
|
||||
Slog.e(TAG, "Unable to create task for backed-up file=" + file + ": "
|
||||
+ fileToString(file));
|
||||
}
|
||||
} else {
|
||||
Slog.wtf(TAG, "createTaskRecordLocked Unknown xml event=" + event
|
||||
+ " name=" + name);
|
||||
}
|
||||
}
|
||||
XmlUtils.skipCurrentTag(in);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Slog.wtf(TAG, "Unable to parse " + file + ". Error ", e);
|
||||
Slog.e(TAG, "Failing file: " + fileToString(file));
|
||||
} finally {
|
||||
IoUtils.closeQuietly(reader);
|
||||
}
|
||||
|
||||
return task;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the input task chain backed-up from another device can be restored on this
|
||||
* device. Also, sets the {@link OtherDeviceTask#mUid} on the input tasks if they can be
|
||||
* restored.
|
||||
*/
|
||||
private boolean canAddOtherDeviceTaskChain(List<OtherDeviceTask> chain) {
|
||||
|
||||
final ArraySet<ComponentName> validComponents = new ArraySet<>();
|
||||
final IPackageManager pm = AppGlobals.getPackageManager();
|
||||
for (int i = 0; i < chain.size(); i++) {
|
||||
|
||||
OtherDeviceTask task = chain.get(i);
|
||||
// Quick check, we can't add the task chain if any of its task files don't exist.
|
||||
if (!task.mFile.exists()) {
|
||||
if (DEBUG_RESTORER) Slog.d(TAG,
|
||||
"Can't add chain due to missing file=" + task.mFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify task package is installed.
|
||||
if (!isPackageInstalled(task.mComponentName.getPackageName())) {
|
||||
return false;
|
||||
}
|
||||
// Verify that all the launch packages are installed.
|
||||
if (task.mLaunchPackages != null) {
|
||||
for (int j = task.mLaunchPackages.size() - 1; j >= 0; --j) {
|
||||
if (!isPackageInstalled(task.mLaunchPackages.valueAt(j))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (validComponents.contains(task.mComponentName)) {
|
||||
// Existance of component has already been verified.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check to see if the specific component is installed.
|
||||
try {
|
||||
if (pm.getActivityInfo(task.mComponentName, 0, UserHandle.USER_OWNER) == null) {
|
||||
// Component isn't installed...
|
||||
return false;
|
||||
}
|
||||
validComponents.add(task.mComponentName);
|
||||
} catch (RemoteException e) {
|
||||
// Should not happen???
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the input package name is installed. If the package is installed, an entry
|
||||
* for the package is added to {@link #mPackageUidMap}.
|
||||
*/
|
||||
private boolean isPackageInstalled(final String packageName) {
|
||||
if (mPackageUidMap != null && mPackageUidMap.containsKey(packageName)) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
int uid = AppGlobals.getPackageManager().getPackageUid(
|
||||
packageName, UserHandle.USER_OWNER);
|
||||
if (uid == -1) {
|
||||
// package doesn't exist...
|
||||
return false;
|
||||
}
|
||||
if (mPackageUidMap == null) {
|
||||
mPackageUidMap = new ArrayMap<>();
|
||||
}
|
||||
mPackageUidMap.put(packageName, uid);
|
||||
return true;
|
||||
} catch (RemoteException e) {
|
||||
// Should not happen???
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private class LazyTaskWriterThread extends Thread {
|
||||
|
||||
LazyTaskWriterThread(String name) {
|
||||
@@ -941,21 +481,20 @@ public class TaskPersister {
|
||||
probablyDone = mWriteQueue.isEmpty();
|
||||
}
|
||||
if (probablyDone) {
|
||||
if (DEBUG_PERSISTER) Slog.d(TAG, "Looking for obsolete files.");
|
||||
if (DEBUG) Slog.d(TAG, "Looking for obsolete files.");
|
||||
persistentTaskIds.clear();
|
||||
synchronized (mService) {
|
||||
if (DEBUG_PERSISTER) Slog.d(TAG, "mRecents=" + mRecentTasks);
|
||||
if (DEBUG) Slog.d(TAG, "mRecents=" + mRecentTasks);
|
||||
for (int taskNdx = mRecentTasks.size() - 1; taskNdx >= 0; --taskNdx) {
|
||||
final TaskRecord task = mRecentTasks.get(taskNdx);
|
||||
if (DEBUG_PERSISTER) Slog.d(TAG, "LazyTaskWriter: task=" + task +
|
||||
if (DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task +
|
||||
" persistable=" + task.isPersistable);
|
||||
if ((task.isPersistable || task.inRecents)
|
||||
&& (task.stack == null || !task.stack.isHomeStack())) {
|
||||
if (DEBUG_PERSISTER)
|
||||
Slog.d(TAG, "adding to persistentTaskIds task=" + task);
|
||||
if (DEBUG) Slog.d(TAG, "adding to persistentTaskIds task=" + task);
|
||||
persistentTaskIds.add(task.taskId);
|
||||
} else {
|
||||
if (DEBUG_PERSISTER) Slog.d(TAG,
|
||||
if (DEBUG) Slog.d(TAG,
|
||||
"omitting from persistentTaskIds task=" + task);
|
||||
}
|
||||
}
|
||||
@@ -969,7 +508,7 @@ public class TaskPersister {
|
||||
if (mNextWriteTime != FLUSH_QUEUE) {
|
||||
// The next write we don't have to wait so long.
|
||||
mNextWriteTime = SystemClock.uptimeMillis() + INTER_WRITE_DELAY_MS;
|
||||
if (DEBUG_PERSISTER) Slog.d(TAG, "Next write time may be in " +
|
||||
if (DEBUG) Slog.d(TAG, "Next write time may be in " +
|
||||
INTER_WRITE_DELAY_MS + " msec. (" + mNextWriteTime + ")");
|
||||
}
|
||||
|
||||
@@ -979,13 +518,8 @@ public class TaskPersister {
|
||||
mNextWriteTime = 0; // idle.
|
||||
TaskPersister.this.notifyAll(); // wake up flush() if needed.
|
||||
}
|
||||
|
||||
// See if we need to remove any expired back-up tasks before waiting.
|
||||
removeExpiredTasksIfNeeded();
|
||||
|
||||
try {
|
||||
if (DEBUG_PERSISTER)
|
||||
Slog.d(TAG, "LazyTaskWriter: waiting indefinitely.");
|
||||
if (DEBUG) Slog.d(TAG, "LazyTaskWriter: waiting indefinitely.");
|
||||
TaskPersister.this.wait();
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
@@ -995,12 +529,11 @@ public class TaskPersister {
|
||||
item = mWriteQueue.remove(0);
|
||||
|
||||
long now = SystemClock.uptimeMillis();
|
||||
if (DEBUG_PERSISTER) Slog.d(TAG, "LazyTaskWriter: now=" + now
|
||||
+ " mNextWriteTime=" + mNextWriteTime + " mWriteQueue.size="
|
||||
+ mWriteQueue.size());
|
||||
if (DEBUG) Slog.d(TAG, "LazyTaskWriter: now=" + now + " mNextWriteTime=" +
|
||||
mNextWriteTime + " mWriteQueue.size=" + mWriteQueue.size());
|
||||
while (now < mNextWriteTime) {
|
||||
try {
|
||||
if (DEBUG_PERSISTER) Slog.d(TAG, "LazyTaskWriter: waiting " +
|
||||
if (DEBUG) Slog.d(TAG, "LazyTaskWriter: waiting " +
|
||||
(mNextWriteTime - now));
|
||||
TaskPersister.this.wait(mNextWriteTime - now);
|
||||
} catch (InterruptedException e) {
|
||||
@@ -1015,7 +548,7 @@ public class TaskPersister {
|
||||
ImageWriteQueueItem imageWriteQueueItem = (ImageWriteQueueItem) item;
|
||||
final String filename = imageWriteQueueItem.mFilename;
|
||||
final Bitmap bitmap = imageWriteQueueItem.mImage;
|
||||
if (DEBUG_PERSISTER) Slog.d(TAG, "writing bitmap: filename=" + filename);
|
||||
if (DEBUG) Slog.d(TAG, "writing bitmap: filename=" + filename);
|
||||
FileOutputStream imageFile = null;
|
||||
try {
|
||||
imageFile = new FileOutputStream(new File(sImagesDir, filename));
|
||||
@@ -1029,12 +562,12 @@ public class TaskPersister {
|
||||
// Write out one task.
|
||||
StringWriter stringWriter = null;
|
||||
TaskRecord task = ((TaskWriteQueueItem) item).mTask;
|
||||
if (DEBUG_PERSISTER) Slog.d(TAG, "Writing task=" + task);
|
||||
if (DEBUG) Slog.d(TAG, "Writing task=" + task);
|
||||
synchronized (mService) {
|
||||
if (task.inRecents) {
|
||||
// Still there.
|
||||
try {
|
||||
if (DEBUG_PERSISTER) Slog.d(TAG, "Saving task=" + task);
|
||||
if (DEBUG) Slog.d(TAG, "Saving task=" + task);
|
||||
stringWriter = saveToXml(task);
|
||||
} catch (IOException e) {
|
||||
} catch (XmlPullParserException e) {
|
||||
@@ -1064,127 +597,4 @@ public class TaskPersister {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class for holding essential information about task that were backed-up on a different
|
||||
* device that can be restored on this device.
|
||||
*/
|
||||
private static class OtherDeviceTask implements Comparable<OtherDeviceTask> {
|
||||
final File mFile;
|
||||
// See {@link TaskRecord} for information on the fields below.
|
||||
final ComponentName mComponentName;
|
||||
final int mTaskId;
|
||||
final int mAffiliatedTaskId;
|
||||
|
||||
// Names of packages that launched activities in this task. All packages listed here need
|
||||
// to be installed on the current device in order for the task to be restored successfully.
|
||||
final ArraySet<String> mLaunchPackages;
|
||||
|
||||
private OtherDeviceTask(File file, ComponentName componentName, int taskId,
|
||||
int affiliatedTaskId, ArraySet<String> launchPackages) {
|
||||
mFile = file;
|
||||
mComponentName = componentName;
|
||||
mTaskId = taskId;
|
||||
mAffiliatedTaskId = (affiliatedTaskId == INVALID_TASK_ID) ? taskId: affiliatedTaskId;
|
||||
mLaunchPackages = launchPackages;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(OtherDeviceTask another) {
|
||||
return mTaskId - another.mTaskId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link OtherDeviceTask} object based on the contents of the input file.
|
||||
*
|
||||
* @param file input file that contains the complete task information.
|
||||
* @return new {@link OtherDeviceTask} object or null if we failed to create the object.
|
||||
*/
|
||||
static OtherDeviceTask createFromFile(File file) {
|
||||
if (file == null || !file.exists()) {
|
||||
if (DEBUG_RESTORER)
|
||||
Slog.d(TAG, "createFromFile: file=" + file + " doesn't exist.");
|
||||
return null;
|
||||
}
|
||||
|
||||
BufferedReader reader = null;
|
||||
|
||||
try {
|
||||
reader = new BufferedReader(new FileReader(file));
|
||||
final XmlPullParser in = Xml.newPullParser();
|
||||
in.setInput(reader);
|
||||
|
||||
int event;
|
||||
while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
|
||||
event != XmlPullParser.START_TAG) {
|
||||
// Skip to the start tag or end of document
|
||||
}
|
||||
|
||||
if (event == XmlPullParser.START_TAG) {
|
||||
final String name = in.getName();
|
||||
|
||||
if (TAG_TASK.equals(name)) {
|
||||
final int outerDepth = in.getDepth();
|
||||
ComponentName componentName = null;
|
||||
int taskId = INVALID_TASK_ID;
|
||||
int taskAffiliation = INVALID_TASK_ID;
|
||||
for (int j = in.getAttributeCount() - 1; j >= 0; --j) {
|
||||
final String attrName = in.getAttributeName(j);
|
||||
final String attrValue = in.getAttributeValue(j);
|
||||
if (TaskRecord.ATTR_REALACTIVITY.equals(attrName)) {
|
||||
componentName = ComponentName.unflattenFromString(attrValue);
|
||||
} else if (TaskRecord.ATTR_TASKID.equals(attrName)) {
|
||||
taskId = Integer.valueOf(attrValue);
|
||||
} else if (TaskRecord.ATTR_TASK_AFFILIATION.equals(attrName)) {
|
||||
taskAffiliation = Integer.valueOf(attrValue);
|
||||
}
|
||||
}
|
||||
if (componentName == null || taskId == INVALID_TASK_ID) {
|
||||
if (DEBUG_RESTORER) Slog.e(TAG,
|
||||
"createFromFile: FAILED componentName=" + componentName
|
||||
+ " taskId=" + taskId + " file=" + file);
|
||||
return null;
|
||||
}
|
||||
|
||||
ArraySet<String> launchPackages = null;
|
||||
while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
|
||||
(event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) {
|
||||
if (event == XmlPullParser.START_TAG) {
|
||||
if (TaskRecord.TAG_ACTIVITY.equals(in.getName())) {
|
||||
for (int j = in.getAttributeCount() - 1; j >= 0; --j) {
|
||||
if (ActivityRecord.ATTR_LAUNCHEDFROMPACKAGE.equals(
|
||||
in.getAttributeName(j))) {
|
||||
if (launchPackages == null) {
|
||||
launchPackages = new ArraySet();
|
||||
}
|
||||
launchPackages.add(in.getAttributeValue(j));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
XmlUtils.skipCurrentTag(in);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (DEBUG_RESTORER) Slog.d(TAG, "creating OtherDeviceTask from file="
|
||||
+ file.getName() + " componentName=" + componentName
|
||||
+ " taskId=" + taskId + " launchPackages=" + launchPackages);
|
||||
return new OtherDeviceTask(file, componentName, taskId,
|
||||
taskAffiliation, launchPackages);
|
||||
} else {
|
||||
Slog.wtf(TAG,
|
||||
"createFromFile: Unknown xml event=" + event + " name=" + name);
|
||||
}
|
||||
} else {
|
||||
Slog.wtf(TAG, "createFromFile: Unable to find start tag in file=" + file);
|
||||
}
|
||||
} catch (IOException | XmlPullParserException e) {
|
||||
Slog.wtf(TAG, "Unable to parse " + file + ". Error ", e);
|
||||
} finally {
|
||||
IoUtils.closeQuietly(reader);
|
||||
}
|
||||
|
||||
// Something went wrong...
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,8 +28,6 @@ import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
|
||||
import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
|
||||
import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
|
||||
import static com.android.server.am.ActivityStackSupervisor.DEBUG_ADD_REMOVE;
|
||||
import static com.android.server.am.TaskPersister.DEBUG_PERSISTER;
|
||||
import static com.android.server.am.TaskPersister.DEBUG_RESTORER;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
@@ -71,7 +69,7 @@ final class TaskRecord {
|
||||
private static final String TAG_AFFINITYINTENT = "affinity_intent";
|
||||
static final String ATTR_REALACTIVITY = "real_activity";
|
||||
private static final String ATTR_ORIGACTIVITY = "orig_activity";
|
||||
static final String TAG_ACTIVITY = "activity";
|
||||
private static final String TAG_ACTIVITY = "activity";
|
||||
private static final String ATTR_AFFINITY = "affinity";
|
||||
private static final String ATTR_ROOT_AFFINITY = "root_affinity";
|
||||
private static final String ATTR_ROOTHASRESET = "root_has_reset";
|
||||
@@ -970,10 +968,6 @@ final class TaskRecord {
|
||||
|
||||
static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor)
|
||||
throws IOException, XmlPullParserException {
|
||||
return restoreFromXml(in, stackSupervisor, INVALID_TASK_ID);
|
||||
}
|
||||
static TaskRecord restoreFromXml(XmlPullParser in, ActivityStackSupervisor stackSupervisor,
|
||||
int inTaskId) throws IOException, XmlPullParserException {
|
||||
Intent intent = null;
|
||||
Intent affinityIntent = null;
|
||||
ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>();
|
||||
@@ -993,7 +987,7 @@ final class TaskRecord {
|
||||
long lastActiveTime = -1;
|
||||
long lastTimeOnTop = 0;
|
||||
boolean neverRelinquishIdentity = true;
|
||||
int taskId = inTaskId;
|
||||
int taskId = INVALID_TASK_ID;
|
||||
final int outerDepth = in.getDepth();
|
||||
TaskDescription taskDescription = new TaskDescription();
|
||||
int taskAffiliation = INVALID_TASK_ID;
|
||||
@@ -1008,8 +1002,8 @@ final class TaskRecord {
|
||||
for (int attrNdx = in.getAttributeCount() - 1; attrNdx >= 0; --attrNdx) {
|
||||
final String attrName = in.getAttributeName(attrNdx);
|
||||
final String attrValue = in.getAttributeValue(attrNdx);
|
||||
if (DEBUG_PERSISTER || DEBUG_RESTORER) Slog.d(TaskPersister.TAG,
|
||||
"TaskRecord: attribute name=" + attrName + " value=" + attrValue);
|
||||
if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: attribute name=" +
|
||||
attrName + " value=" + attrValue);
|
||||
if (ATTR_TASKID.equals(attrName)) {
|
||||
if (taskId == INVALID_TASK_ID) taskId = Integer.valueOf(attrValue);
|
||||
} else if (ATTR_REALACTIVITY.equals(attrName)) {
|
||||
@@ -1071,16 +1065,16 @@ final class TaskRecord {
|
||||
(event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) {
|
||||
if (event == XmlPullParser.START_TAG) {
|
||||
final String name = in.getName();
|
||||
if (DEBUG_PERSISTER || DEBUG_RESTORER)
|
||||
Slog.d(TaskPersister.TAG, "TaskRecord: START_TAG name=" + name);
|
||||
if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: START_TAG name=" +
|
||||
name);
|
||||
if (TAG_AFFINITYINTENT.equals(name)) {
|
||||
affinityIntent = Intent.restoreFromXml(in);
|
||||
} else if (TAG_INTENT.equals(name)) {
|
||||
intent = Intent.restoreFromXml(in);
|
||||
} else if (TAG_ACTIVITY.equals(name)) {
|
||||
ActivityRecord activity = ActivityRecord.restoreFromXml(in, stackSupervisor);
|
||||
if (DEBUG_PERSISTER || DEBUG_RESTORER)
|
||||
Slog.d(TaskPersister.TAG, "TaskRecord: activity=" + activity);
|
||||
if (TaskPersister.DEBUG) Slog.d(TaskPersister.TAG, "TaskRecord: activity=" +
|
||||
activity);
|
||||
if (activity != null) {
|
||||
activities.add(activity);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user