diff options
author | Christopher Tate <ctate@android.com> | 2009-07-15 14:18:26 -0700 |
---|---|---|
committer | Christopher Tate <ctate@android.com> | 2009-07-15 14:18:26 -0700 |
commit | 73e025296fd8712c775fe75c5f5d6981155b0867 (patch) | |
tree | 9902424ae1d32d335ff71a3f951fcdceca862e54 /services | |
parent | 2debd56b5b24d7f4c385f64bfcaf23d00d4d986a (diff) | |
download | frameworks_base-73e025296fd8712c775fe75c5f5d6981155b0867.zip frameworks_base-73e025296fd8712c775fe75c5f5d6981155b0867.tar.gz frameworks_base-73e025296fd8712c775fe75c5f5d6981155b0867.tar.bz2 |
Ensure that everything gets backed up at least once
We now schedule a backup pass for any new application we see (at boot or
package-install time) for which we have never performed a backup. The
bookkeeping is a log file with the names of all the packages we've successfully
completed a backup pass on, maintained with synchronous journal-type behavior.
Also, make a bunch of private fields package-scoped to permit cheaper access
from the various worker / binder threads that run under the Backup Manager's
aegis.
Diffstat (limited to 'services')
-rw-r--r-- | services/java/com/android/server/BackupManagerService.java | 149 |
1 files changed, 111 insertions, 38 deletions
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java index 20f0750..6eba783 100644 --- a/services/java/com/android/server/BackupManagerService.java +++ b/services/java/com/android/server/BackupManagerService.java @@ -100,18 +100,18 @@ class BackupManagerService extends IBackupManager.Stub { private PowerManager mPowerManager; private AlarmManager mAlarmManager; - private boolean mEnabled; // access to this is synchronized on 'this' - private boolean mProvisioned; - private PowerManager.WakeLock mWakelock; - private final BackupHandler mBackupHandler = new BackupHandler(); - private PendingIntent mRunBackupIntent; - private BroadcastReceiver mRunBackupReceiver; - private IntentFilter mRunBackupFilter; + boolean mEnabled; // access to this is synchronized on 'this' + boolean mProvisioned; + PowerManager.WakeLock mWakelock; + final BackupHandler mBackupHandler = new BackupHandler(); + PendingIntent mRunBackupIntent; + BroadcastReceiver mRunBackupReceiver; + IntentFilter mRunBackupFilter; // map UIDs to the set of backup client services within that UID's app set - private final SparseArray<HashSet<ApplicationInfo>> mBackupParticipants + final SparseArray<HashSet<ApplicationInfo>> mBackupParticipants = new SparseArray<HashSet<ApplicationInfo>>(); // set of backup services that have pending changes - private class BackupRequest { + class BackupRequest { public ApplicationInfo appInfo; public boolean fullBackup; @@ -125,35 +125,35 @@ class BackupManagerService extends IBackupManager.Stub { } } // Backups that we haven't started yet. - private HashMap<ApplicationInfo,BackupRequest> mPendingBackups + HashMap<ApplicationInfo,BackupRequest> mPendingBackups = new HashMap<ApplicationInfo,BackupRequest>(); // Pseudoname that we use for the Package Manager metadata "package" - private static final String PACKAGE_MANAGER_SENTINEL = "@pm@"; + static final String PACKAGE_MANAGER_SENTINEL = "@pm@"; // locking around the pending-backup management - private final Object mQueueLock = new Object(); + final Object mQueueLock = new Object(); // The thread performing the sequence of queued backups binds to each app's agent // in succession. Bind notifications are asynchronously delivered through the // Activity Manager; use this lock object to signal when a requested binding has // completed. - private final Object mAgentConnectLock = new Object(); - private IBackupAgent mConnectedAgent; - private volatile boolean mConnecting; + final Object mAgentConnectLock = new Object(); + IBackupAgent mConnectedAgent; + volatile boolean mConnecting; // A similar synchronicity mechanism around clearing apps' data for restore - private final Object mClearDataLock = new Object(); - private volatile boolean mClearingData; + final Object mClearDataLock = new Object(); + volatile boolean mClearingData; // Transport bookkeeping - private final HashMap<String,IBackupTransport> mTransports + final HashMap<String,IBackupTransport> mTransports = new HashMap<String,IBackupTransport>(); - private String mCurrentTransport; - private IBackupTransport mLocalTransport, mGoogleTransport; - private RestoreSession mActiveRestoreSession; + String mCurrentTransport; + IBackupTransport mLocalTransport, mGoogleTransport; + RestoreSession mActiveRestoreSession; - private class RestoreParams { + class RestoreParams { public IBackupTransport transport; public IRestoreObserver observer; public long token; @@ -165,7 +165,7 @@ class BackupManagerService extends IBackupManager.Stub { } } - private class ClearParams { + class ClearParams { public IBackupTransport transport; public PackageInfo packageInfo; @@ -176,11 +176,17 @@ class BackupManagerService extends IBackupManager.Stub { } // Where we keep our journal files and other bookkeeping - private File mBaseStateDir; - private File mDataDir; - private File mJournalDir; - private File mJournal; - private RandomAccessFile mJournalStream; + File mBaseStateDir; + File mDataDir; + File mJournalDir; + File mJournal; + RandomAccessFile mJournalStream; + + // Keep a log of all the apps we've ever backed up + private File mEverStored; + private RandomAccessFile mEverStoredStream; + HashSet<String> mEverStoredApps = new HashSet<String>(); + public BackupManagerService(Context context) { mContext = context; @@ -215,6 +221,9 @@ class BackupManagerService extends IBackupManager.Stub { mJournalDir.mkdirs(); // creates mBaseStateDir along the way makeJournalLocked(); // okay because no other threads are running yet + // Set up the various sorts of package tracking we do + initPackageTracking(); + // Build our mapping of uid to backup client services. This implicitly // schedules a backup pass on the Package Manager metadata the first // time anything needs to be backed up. @@ -249,14 +258,6 @@ class BackupManagerService extends IBackupManager.Stub { // leftover journal files into the pending backup set parseLeftoverJournals(); - // Register for broadcasts about package install, etc., so we can - // update the provider list. - IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_PACKAGE_ADDED); - filter.addAction(Intent.ACTION_PACKAGE_REMOVED); - filter.addDataScheme("package"); - mContext.registerReceiver(mBroadcastReceiver, filter); - // Power management mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "backup"); @@ -281,6 +282,39 @@ class BackupManagerService extends IBackupManager.Stub { } } + private void initPackageTracking() { + if (DEBUG) Log.v(TAG, "Initializing package tracking"); + + // Keep a log of what apps we've ever backed up + mEverStored = new File(mBaseStateDir, "processed"); + try { + mEverStoredStream = new RandomAccessFile(mEverStored, "rwd"); + + // parse its existing contents + mEverStoredStream.seek(0); + try { + while (true) { + String pkg = mEverStoredStream.readUTF(); + mEverStoredApps.add(pkg); + if (DEBUG) Log.v(TAG, " + " + pkg); + } + } catch (EOFException e) { + // now we're at EOF + } + } catch (IOException e) { + Log.e(TAG, "Unable to open known-stored file!"); + mEverStoredStream = null; + } + + // Register for broadcasts about package install, etc., so we can + // update the provider list. + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_PACKAGE_ADDED); + filter.addAction(Intent.ACTION_PACKAGE_REMOVED); + filter.addDataScheme("package"); + mContext.registerReceiver(mBroadcastReceiver, filter); + } + private void makeJournalLocked() { try { mJournal = File.createTempFile("journal", null, mJournalDir); @@ -485,6 +519,17 @@ class BackupManagerService extends IBackupManager.Stub { mBackupParticipants.put(uid, set); } set.add(pkg.applicationInfo); + + // If we've never seen this app before, schedule a backup for it + if (!mEverStoredApps.contains(pkg.packageName)) { + if (DEBUG) Log.i(TAG, "New app " + pkg.packageName + + " never backed up; scheduling"); + try { + dataChanged(pkg.packageName); + } catch (RemoteException e) { + // can't happen; it's a local method call + } + } } } } @@ -540,7 +585,7 @@ class BackupManagerService extends IBackupManager.Stub { } // Returns the set of all applications that define an android:backupAgent attribute - private List<PackageInfo> allAgentPackages() { + List<PackageInfo> allAgentPackages() { // !!! TODO: cache this and regenerate only when necessary int flags = PackageManager.GET_SIGNATURES; List<PackageInfo> packages = mPackageManager.getInstalledPackages(flags); @@ -570,6 +615,28 @@ class BackupManagerService extends IBackupManager.Stub { addPackageParticipantsLockedInner(packageName, allApps); } + // Called from the backup thread: record that the given app has been successfully + // backed up at least once + void logBackupComplete(String packageName) { + if (mEverStoredStream != null) { + synchronized (mEverStoredApps) { + if (mEverStoredApps.add(packageName)) { + try { + mEverStoredStream.writeUTF(packageName); + } catch (IOException e) { + Log.e(TAG, "Unable to log backup of " + packageName + ", ceasing log"); + try { + mEverStoredStream.close(); + } catch (IOException ioe) { + // we're dropping it; no need to handle an exception on close here + } + mEverStoredStream = null; + } + } + } + } + } + // Return the given transport private IBackupTransport getTransport(String transportName) { synchronized (mTransports) { @@ -799,6 +866,7 @@ class BackupManagerService extends IBackupManager.Stub { boolean success = false; try { agent.doBackup(savedState, backupData, newState); + logBackupComplete(packageName); success = true; } finally { if (savedState != null) { @@ -1235,7 +1303,8 @@ class BackupManagerService extends IBackupManager.Stub { } } } else { - Log.w(TAG, "dataChanged but no participant pkg='" + packageName + "'"); + Log.w(TAG, "dataChanged but no participant pkg='" + packageName + "'" + + " uid=" + Binder.getCallingUid()); } } @@ -1566,6 +1635,10 @@ class BackupManagerService extends IBackupManager.Stub { pw.println(" " + app.toString()); } } + pw.println("Ever backed up: " + mEverStoredApps.size()); + for (String pkg : mEverStoredApps) { + pw.println(" " + pkg); + } pw.println("Pending: " + mPendingBackups.size()); for (BackupRequest req : mPendingBackups.values()) { pw.println(" " + req); |