Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 49401ddb authored by Christopher Tate's avatar Christopher Tate
Browse files

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.
parent ce0bf069
Loading
Loading
Loading
Loading
+56 −41
Original line number Diff line number Diff line
@@ -78,8 +78,9 @@ class BackupManagerService extends IBackupManager.Stub {
    private static final String BACKUP_TRANSPORT_SETTING = "backup_transport";
    private static final String BACKUP_ENABLED_SETTING = "backup_enabled";

    // Default time to wait after data changes before we back up the data
    private static final long COLLECTION_INTERVAL = 3 * 60 * 1000;
    // How often we perform a backup pass.  Privileged external callers can
    // 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_FULL_BACKUP = 2;
@@ -210,7 +211,7 @@ class BackupManagerService extends IBackupManager.Stub {
        context.bindService(intent, mGoogleConnection, Context.BIND_AUTO_CREATE);

        // 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();

        // Register for broadcasts about package install, etc., so we can
@@ -220,6 +221,12 @@ class BackupManagerService extends IBackupManager.Stub {
        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
        filter.addDataScheme("package");
        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() {
@@ -342,11 +349,8 @@ class BackupManagerService extends IBackupManager.Stub {
                ArrayList<BackupRequest> queue = new ArrayList<BackupRequest>();
                File oldJournal = mJournal;
                synchronized (mQueueLock) {
                    if (mPendingBackups.size() == 0) {
                        Log.v(TAG, "Backup requested but nothing pending");
                        break;
                    }

                    // Do we have any work to do?
                    if (mPendingBackups.size() > 0) {
                        for (BackupRequest b: mPendingBackups.values()) {
                            queue.add(b);
                        }
@@ -368,9 +372,16 @@ class BackupManagerService extends IBackupManager.Stub {
                        // 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;
            }

@@ -1115,10 +1126,6 @@ class BackupManagerService extends IBackupManager.Stub {
                        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 {
            Log.w(TAG, "dataChanged but no participant pkg " + packageName);
@@ -1159,13 +1166,13 @@ class BackupManagerService extends IBackupManager.Stub {
            mEnabled = enable;
        }

        if (enable && !wasEnabled) {
        synchronized (mQueueLock) {
                if (mPendingBackups.size() > 0) {
                    // !!! TODO: better policy around timing of the first backup pass
                    if (DEBUG) Log.v(TAG, "Backup enabled with pending data changes, scheduling");
                    this.scheduleBackupPassLocked(COLLECTION_INTERVAL);
                }
            if (enable && !wasEnabled) {
                // if we've just been enabled, start scheduling backup passes
                scheduleBackupPassLocked(BACKUP_INTERVAL);
            } else if (!enable) {
                // No longer enabled, so stop running backups.
                mBackupHandler.removeMessages(MSG_RUN_BACKUP);
            }
        }
    }
@@ -1343,6 +1350,14 @@ class BackupManagerService extends IBackupManager.Stub {
    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        synchronized (mQueueLock) {
            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:");
            for (String t : listAllTransports()) {
                String pad = (t.equals(mCurrentTransport)) ? "  * " : "    ";