diff options
-rw-r--r-- | services/backup/java/com/android/server/backup/BackupManagerService.java | 165 |
1 files changed, 99 insertions, 66 deletions
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index 01cc2ca..ff8fb83 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -88,13 +88,13 @@ import android.util.Slog; import android.util.SparseArray; import android.util.StringBuilderPrinter; +import com.android.internal.annotations.GuardedBy; import com.android.internal.backup.IBackupTransport; import com.android.internal.backup.IObbBackupService; import com.android.server.AppWidgetBackupBridge; import com.android.server.EventLogTags; import com.android.server.SystemService; import com.android.server.backup.PackageManagerBackupAgent.Metadata; -import com.android.server.pm.PackageManagerService; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; @@ -589,8 +589,12 @@ public class BackupManagerService { File mFullBackupScheduleFile; // If we're running a schedule-driven full backup, this is the task instance doing it - PerformFullTransportBackupTask mRunningFullBackupTask; // inside mQueueLock - ArrayList<FullBackupEntry> mFullBackupQueue; // inside mQueueLock + + @GuardedBy("mQueueLock") + PerformFullTransportBackupTask mRunningFullBackupTask; + + @GuardedBy("mQueueLock") + ArrayList<FullBackupEntry> mFullBackupQueue; // Utility: build a new random integer token int generateToken() { @@ -1229,8 +1233,10 @@ public class BackupManagerService { } } - // Resume the full-data backup queue - mFullBackupQueue = readFullBackupSchedule(); + synchronized (mQueueLock) { + // Resume the full-data backup queue + mFullBackupQueue = readFullBackupSchedule(); + } // Register for broadcasts about package install, etc., so we can // update the provider list. @@ -1248,74 +1254,98 @@ public class BackupManagerService { } private ArrayList<FullBackupEntry> readFullBackupSchedule() { + boolean changed = false; ArrayList<FullBackupEntry> schedule = null; - synchronized (mQueueLock) { - if (mFullBackupScheduleFile.exists()) { - FileInputStream fstream = null; - BufferedInputStream bufStream = null; - DataInputStream in = null; - try { - fstream = new FileInputStream(mFullBackupScheduleFile); - bufStream = new BufferedInputStream(fstream); - in = new DataInputStream(bufStream); + List<PackageInfo> apps = + PackageManagerBackupAgent.getStorableApplications(mPackageManager); - int version = in.readInt(); - if (version != SCHEDULE_FILE_VERSION) { - Slog.e(TAG, "Unknown backup schedule version " + version); - return null; - } + if (mFullBackupScheduleFile.exists()) { + FileInputStream fstream = null; + BufferedInputStream bufStream = null; + DataInputStream in = null; + try { + fstream = new FileInputStream(mFullBackupScheduleFile); + bufStream = new BufferedInputStream(fstream); + in = new DataInputStream(bufStream); - int N = in.readInt(); - schedule = new ArrayList<FullBackupEntry>(N); - for (int i = 0; i < N; i++) { - String pkgName = in.readUTF(); - long lastBackup = in.readLong(); - try { - PackageInfo pkg = mPackageManager.getPackageInfo(pkgName, 0); - if (appGetsFullBackup(pkg) - && appIsEligibleForBackup(pkg.applicationInfo)) { - schedule.add(new FullBackupEntry(pkgName, lastBackup)); - } else { - if (DEBUG) { - Slog.i(TAG, "Package " + pkgName - + " no longer eligible for full backup"); - } - } - } catch (NameNotFoundException e) { + int version = in.readInt(); + if (version != SCHEDULE_FILE_VERSION) { + Slog.e(TAG, "Unknown backup schedule version " + version); + return null; + } + + final int N = in.readInt(); + schedule = new ArrayList<FullBackupEntry>(N); + + // HashSet instead of ArraySet specifically because we want the eventual + // lookups against O(hundreds) of entries to be as fast as possible, and + // we discard the set immediately after the scan so the extra memory + // overhead is transient. + HashSet<String> foundApps = new HashSet<String>(N); + + for (int i = 0; i < N; i++) { + String pkgName = in.readUTF(); + long lastBackup = in.readLong(); + foundApps.add(pkgName); // all apps that we've addressed already + try { + PackageInfo pkg = mPackageManager.getPackageInfo(pkgName, 0); + if (appGetsFullBackup(pkg) && appIsEligibleForBackup(pkg.applicationInfo)) { + schedule.add(new FullBackupEntry(pkgName, lastBackup)); + } else { if (DEBUG) { Slog.i(TAG, "Package " + pkgName - + " not installed; dropping from full backup"); + + " no longer eligible for full backup"); } } + } catch (NameNotFoundException e) { + if (DEBUG) { + Slog.i(TAG, "Package " + pkgName + + " not installed; dropping from full backup"); + } } - Collections.sort(schedule); - } catch (Exception e) { - Slog.e(TAG, "Unable to read backup schedule", e); - mFullBackupScheduleFile.delete(); - schedule = null; - } finally { - IoUtils.closeQuietly(in); - IoUtils.closeQuietly(bufStream); - IoUtils.closeQuietly(fstream); } - } - if (schedule == null) { - // no prior queue record, or unable to read it. Set up the queue - // from scratch. - List<PackageInfo> apps = - PackageManagerBackupAgent.getStorableApplications(mPackageManager); - final int N = apps.size(); - schedule = new ArrayList<FullBackupEntry>(N); - for (int i = 0; i < N; i++) { - PackageInfo info = apps.get(i); - if (appGetsFullBackup(info) && appIsEligibleForBackup(info.applicationInfo)) { - schedule.add(new FullBackupEntry(info.packageName, 0)); + // New apps can arrive "out of band" via OTA and similar, so we also need to + // scan to make sure that we're tracking all full-backup candidates properly + for (PackageInfo app : apps) { + if (appGetsFullBackup(app) && appIsEligibleForBackup(app.applicationInfo)) { + if (!foundApps.contains(app.packageName)) { + if (DEBUG) { + Slog.i(TAG, "New full backup app " + app.packageName + " found"); + } + schedule.add(new FullBackupEntry(app.packageName, 0)); + changed = true; + } } } - writeFullBackupScheduleAsync(); + + Collections.sort(schedule); + } catch (Exception e) { + Slog.e(TAG, "Unable to read backup schedule", e); + mFullBackupScheduleFile.delete(); + schedule = null; + } finally { + IoUtils.closeQuietly(in); + IoUtils.closeQuietly(bufStream); + IoUtils.closeQuietly(fstream); + } + } + + if (schedule == null) { + // no prior queue record, or unable to read it. Set up the queue + // from scratch. + changed = true; + schedule = new ArrayList<FullBackupEntry>(apps.size()); + for (PackageInfo info : apps) { + if (appGetsFullBackup(info) && appIsEligibleForBackup(info.applicationInfo)) { + schedule.add(new FullBackupEntry(info.packageName, 0)); + } } } + + if (changed) { + writeFullBackupScheduleAsync(); + } return schedule; } @@ -4313,13 +4343,16 @@ public class BackupManagerService { // This is also slow but easy for modest numbers of apps: work backwards // from the end of the queue until we find an item whose last backup - // time was before this one, then insert this new entry after it. - int which; - for (which = mFullBackupQueue.size() - 1; which >= 0; which--) { - final FullBackupEntry entry = mFullBackupQueue.get(which); - if (entry.lastBackup <= lastBackedUp) { - mFullBackupQueue.add(which + 1, newEntry); - break; + // time was before this one, then insert this new entry after it. If we're + // adding something new we don't bother scanning, and just prepend. + int which = -1; + if (lastBackedUp > 0) { + for (which = mFullBackupQueue.size() - 1; which >= 0; which--) { + final FullBackupEntry entry = mFullBackupQueue.get(which); + if (entry.lastBackup <= lastBackedUp) { + mFullBackupQueue.add(which + 1, newEntry); + break; + } } } if (which < 0) { |