Revamp backup scheduling policy
We now schedule a periodic check of pending backups; if any apps have requested a backup since the last check, we perform all of the pending backups. The periodic backup scheduling matches the enable/disable state of the backup manager; while backups are disabled entirely there are no periodic wakeups. The period is set here to one hour. If an external caller (transport, the 'bmgr' command line tool, etc) requests an immediate backup pass, that is performed and then the periodic backup check is rescheduled using that pass as the starting point of a new interval.
This commit is contained in:
@@ -78,8 +78,9 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
private static final String BACKUP_TRANSPORT_SETTING = "backup_transport";
|
private static final String BACKUP_TRANSPORT_SETTING = "backup_transport";
|
||||||
private static final String BACKUP_ENABLED_SETTING = "backup_enabled";
|
private static final String BACKUP_ENABLED_SETTING = "backup_enabled";
|
||||||
|
|
||||||
// Default time to wait after data changes before we back up the data
|
// How often we perform a backup pass. Privileged external callers can
|
||||||
private static final long COLLECTION_INTERVAL = 3 * 60 * 1000;
|
// trigger an immediate pass.
|
||||||
|
private static final long BACKUP_INTERVAL = 60 * 60 * 1000;
|
||||||
|
|
||||||
private static final int MSG_RUN_BACKUP = 1;
|
private static final int MSG_RUN_BACKUP = 1;
|
||||||
private static final int MSG_RUN_FULL_BACKUP = 2;
|
private static final int MSG_RUN_FULL_BACKUP = 2;
|
||||||
@@ -210,7 +211,7 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
context.bindService(intent, mGoogleConnection, Context.BIND_AUTO_CREATE);
|
context.bindService(intent, mGoogleConnection, Context.BIND_AUTO_CREATE);
|
||||||
|
|
||||||
// Now that we know about valid backup participants, parse any
|
// Now that we know about valid backup participants, parse any
|
||||||
// leftover journal files and schedule a new backup pass
|
// leftover journal files into the pending backup set
|
||||||
parseLeftoverJournals();
|
parseLeftoverJournals();
|
||||||
|
|
||||||
// Register for broadcasts about package install, etc., so we can
|
// Register for broadcasts about package install, etc., so we can
|
||||||
@@ -220,7 +221,13 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
|
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
|
||||||
filter.addDataScheme("package");
|
filter.addDataScheme("package");
|
||||||
mContext.registerReceiver(mBroadcastReceiver, filter);
|
mContext.registerReceiver(mBroadcastReceiver, filter);
|
||||||
}
|
|
||||||
|
// Schedule the first backup pass -- okay because no other threads are
|
||||||
|
// running yet
|
||||||
|
if (mEnabled) {
|
||||||
|
scheduleBackupPassLocked(BACKUP_INTERVAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void makeJournalLocked() {
|
private void makeJournalLocked() {
|
||||||
try {
|
try {
|
||||||
@@ -342,35 +349,39 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
ArrayList<BackupRequest> queue = new ArrayList<BackupRequest>();
|
ArrayList<BackupRequest> queue = new ArrayList<BackupRequest>();
|
||||||
File oldJournal = mJournal;
|
File oldJournal = mJournal;
|
||||||
synchronized (mQueueLock) {
|
synchronized (mQueueLock) {
|
||||||
if (mPendingBackups.size() == 0) {
|
// Do we have any work to do?
|
||||||
Log.v(TAG, "Backup requested but nothing pending");
|
if (mPendingBackups.size() > 0) {
|
||||||
break;
|
for (BackupRequest b: mPendingBackups.values()) {
|
||||||
}
|
queue.add(b);
|
||||||
|
|
||||||
for (BackupRequest b: mPendingBackups.values()) {
|
|
||||||
queue.add(b);
|
|
||||||
}
|
|
||||||
Log.v(TAG, "clearing pending backups");
|
|
||||||
mPendingBackups.clear();
|
|
||||||
|
|
||||||
// Start a new backup-queue journal file too
|
|
||||||
if (mJournalStream != null) {
|
|
||||||
try {
|
|
||||||
mJournalStream.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
// don't need to do anything
|
|
||||||
}
|
}
|
||||||
makeJournalLocked();
|
Log.v(TAG, "clearing pending backups");
|
||||||
}
|
mPendingBackups.clear();
|
||||||
|
|
||||||
// At this point, we have started a new journal file, and the old
|
// Start a new backup-queue journal file too
|
||||||
// file identity is being passed to the backup processing thread.
|
if (mJournalStream != null) {
|
||||||
// When it completes successfully, that old journal file will be
|
try {
|
||||||
// deleted. If we crash prior to that, the old journal is parsed
|
mJournalStream.close();
|
||||||
// at next boot and the journaled requests fulfilled.
|
} catch (IOException e) {
|
||||||
|
// don't need to do anything
|
||||||
|
}
|
||||||
|
makeJournalLocked();
|
||||||
|
}
|
||||||
|
|
||||||
|
// At this point, we have started a new journal file, and the old
|
||||||
|
// file identity is being passed to the backup processing thread.
|
||||||
|
// When it completes successfully, that old journal file will be
|
||||||
|
// deleted. If we crash prior to that, the old journal is parsed
|
||||||
|
// at next boot and the journaled requests fulfilled.
|
||||||
|
(new PerformBackupThread(transport, queue, oldJournal)).start();
|
||||||
|
} else {
|
||||||
|
Log.v(TAG, "Backup requested but nothing pending");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(new PerformBackupThread(transport, queue, oldJournal)).start();
|
// Schedule the next pass.
|
||||||
|
synchronized (mQueueLock) {
|
||||||
|
scheduleBackupPassLocked(BACKUP_INTERVAL);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1115,10 +1126,6 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
Log.d(TAG, " + " + b + " agent=" + b.appInfo.backupAgentName);
|
Log.d(TAG, " + " + b + " agent=" + b.appInfo.backupAgentName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Schedule a backup pass in a few minutes. As backup-eligible data
|
|
||||||
// keeps changing, continue to defer the backup pass until things
|
|
||||||
// settle down, to avoid extra overhead.
|
|
||||||
scheduleBackupPassLocked(COLLECTION_INTERVAL);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.w(TAG, "dataChanged but no participant pkg " + packageName);
|
Log.w(TAG, "dataChanged but no participant pkg " + packageName);
|
||||||
@@ -1159,16 +1166,16 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
mEnabled = enable;
|
mEnabled = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enable && !wasEnabled) {
|
synchronized (mQueueLock) {
|
||||||
synchronized (mQueueLock) {
|
if (enable && !wasEnabled) {
|
||||||
if (mPendingBackups.size() > 0) {
|
// if we've just been enabled, start scheduling backup passes
|
||||||
// !!! TODO: better policy around timing of the first backup pass
|
scheduleBackupPassLocked(BACKUP_INTERVAL);
|
||||||
if (DEBUG) Log.v(TAG, "Backup enabled with pending data changes, scheduling");
|
} else if (!enable) {
|
||||||
this.scheduleBackupPassLocked(COLLECTION_INTERVAL);
|
// No longer enabled, so stop running backups.
|
||||||
}
|
mBackupHandler.removeMessages(MSG_RUN_BACKUP);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Report whether the backup mechanism is currently enabled
|
// Report whether the backup mechanism is currently enabled
|
||||||
public boolean isBackupEnabled() {
|
public boolean isBackupEnabled() {
|
||||||
@@ -1343,6 +1350,14 @@ class BackupManagerService extends IBackupManager.Stub {
|
|||||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||||
synchronized (mQueueLock) {
|
synchronized (mQueueLock) {
|
||||||
pw.println("Backup Manager is " + (mEnabled ? "enabled" : "disabled"));
|
pw.println("Backup Manager is " + (mEnabled ? "enabled" : "disabled"));
|
||||||
|
boolean scheduled = mBackupHandler.hasMessages(MSG_RUN_BACKUP);
|
||||||
|
if (scheduled != mEnabled) {
|
||||||
|
if (mEnabled) {
|
||||||
|
pw.println("ERROR: backups enabled but none scheduled!");
|
||||||
|
} else {
|
||||||
|
pw.println("ERROR: backups are scheduled but not enabled!");
|
||||||
|
}
|
||||||
|
}
|
||||||
pw.println("Available transports:");
|
pw.println("Available transports:");
|
||||||
for (String t : listAllTransports()) {
|
for (String t : listAllTransports()) {
|
||||||
String pad = (t.equals(mCurrentTransport)) ? " * " : " ";
|
String pad = (t.equals(mCurrentTransport)) ? " * " : " ";
|
||||||
|
|||||||
Reference in New Issue
Block a user