Loading services/backup/java/com/android/server/backup/BackupManagerService.java +27 −22 Original line number Diff line number Diff line Loading @@ -293,14 +293,12 @@ public class BackupManagerService implements BackupManagerServiceInterface { // order to give them time to enter the backup password. static final long TIMEOUT_FULL_CONFIRMATION = 60 * 1000; // How long between attempts to perform a full-data backup of any given app static final long MIN_FULL_BACKUP_INTERVAL = 1000 * 60 * 60 * 24; // one day // If an app is busy when we want to do a full-data backup, how long to defer the retry. // This is fuzzed, so there are two parameters; backoff_min + Rand[0, backoff_fuzz) static final long BUSY_BACKOFF_MIN_MILLIS = 1000 * 60 * 60; // one hour static final int BUSY_BACKOFF_FUZZ = 1000 * 60 * 60 * 2; // two hours BackupManagerConstants mConstants; Context mContext; private PackageManager mPackageManager; IPackageManager mPackageManagerBinder; Loading Loading @@ -457,7 +455,7 @@ public class BackupManagerService implements BackupManagerServiceInterface { if (mProvisioned && !wasProvisioned && mEnabled) { // we're now good to go, so start the backup alarms if (MORE_DEBUG) Slog.d(TAG, "Now provisioned, so starting backups"); KeyValueBackupJob.schedule(mContext); KeyValueBackupJob.schedule(mContext, mConstants); scheduleNextFullBackupJob(0); } } Loading Loading @@ -1323,6 +1321,8 @@ public class BackupManagerService implements BackupManagerServiceInterface { mJournalDir.mkdirs(); // creates mBaseStateDir along the way mJournal = null; // will be created on first use mConstants = new BackupManagerConstants(mBackupHandler, mContext.getContentResolver()); // Set up the various sorts of package tracking we do mFullBackupScheduleFile = new File(mBaseStateDir, "fb-schedule"); initPackageTracking(); Loading Loading @@ -2478,8 +2478,8 @@ public class BackupManagerService implements BackupManagerServiceInterface { } // We don't want the backup jobs to kick in any time soon. // Reschedules them to run in the distant future. KeyValueBackupJob.schedule(mContext, BUSY_BACKOFF_MIN_MILLIS); FullBackupJob.schedule(mContext, 2 * BUSY_BACKOFF_MIN_MILLIS); KeyValueBackupJob.schedule(mContext, BUSY_BACKOFF_MIN_MILLIS, mConstants); FullBackupJob.schedule(mContext, 2 * BUSY_BACKOFF_MIN_MILLIS, mConstants); } finally { Binder.restoreCallingIdentity(oldToken); } Loading Loading @@ -3558,7 +3558,7 @@ public class BackupManagerService implements BackupManagerServiceInterface { Slog.w(TAG, "Unable to contact transport for recommended backoff: " + e.getMessage()); delay = 0; // use the scheduler's default } KeyValueBackupJob.schedule(mContext, delay); KeyValueBackupJob.schedule(mContext, delay, mConstants); for (BackupRequest request : mOriginalQueue) { dataChangedImpl(request.packageName); Loading Loading @@ -5370,12 +5370,12 @@ public class BackupManagerService implements BackupManagerServiceInterface { // due. final long upcomingLastBackup = mFullBackupQueue.get(0).lastBackup; final long timeSinceLast = System.currentTimeMillis() - upcomingLastBackup; final long appLatency = (timeSinceLast < MIN_FULL_BACKUP_INTERVAL) ? (MIN_FULL_BACKUP_INTERVAL - timeSinceLast) : 0; final long interval = mConstants.getFullBackupIntervalMilliseconds(); final long appLatency = (timeSinceLast < interval) ? (interval - timeSinceLast) : 0; final long latency = Math.max(transportMinLatency, appLatency); Runnable r = new Runnable() { @Override public void run() { FullBackupJob.schedule(mContext, latency); FullBackupJob.schedule(mContext, latency, mConstants); } }; mBackupHandler.postDelayed(r, 2500); Loading Loading @@ -5470,9 +5470,15 @@ public class BackupManagerService implements BackupManagerServiceInterface { */ @Override public boolean beginFullBackup(FullBackupJob scheduledJob) { long now = System.currentTimeMillis(); final long now = System.currentTimeMillis(); FullBackupEntry entry = null; long latency = MIN_FULL_BACKUP_INTERVAL; final long fullBackupInterval; final long keyValueBackupInterval; synchronized (mConstants) { fullBackupInterval = mConstants.getFullBackupIntervalMilliseconds(); keyValueBackupInterval = mConstants.getKeyValueBackupIntervalMilliseconds(); } long latency = fullBackupInterval; if (!mEnabled || !mProvisioned) { // Backups are globally disabled, so don't proceed. We also don't reschedule Loading @@ -5491,7 +5497,7 @@ public class BackupManagerService implements BackupManagerServiceInterface { mPowerManager.getPowerSaveState(ServiceType.FULL_BACKUP); if (result.batterySaverEnabled) { if (DEBUG) Slog.i(TAG, "Deferring scheduled full backups in battery saver mode"); FullBackupJob.schedule(mContext, KeyValueBackupJob.BATCH_INTERVAL); FullBackupJob.schedule(mContext, keyValueBackupInterval, mConstants); return false; } Loading Loading @@ -5534,20 +5540,20 @@ public class BackupManagerService implements BackupManagerServiceInterface { // Typically this means we haven't run a key/value backup yet. Back off // full-backup operations by the key/value job's run interval so that // next time we run, we are likely to be able to make progress. latency = KeyValueBackupJob.BATCH_INTERVAL; latency = keyValueBackupInterval; } if (runBackup) { entry = mFullBackupQueue.get(0); long timeSinceRun = now - entry.lastBackup; runBackup = (timeSinceRun >= MIN_FULL_BACKUP_INTERVAL); runBackup = (timeSinceRun >= fullBackupInterval); if (!runBackup) { // It's too early to back up the next thing in the queue, so bow out if (MORE_DEBUG) { Slog.i(TAG, "Device ready but too early to back up next app"); } // Wait until the next app in the queue falls due for a full data backup latency = MIN_FULL_BACKUP_INTERVAL - timeSinceRun; latency = fullBackupInterval - timeSinceRun; break; // we know we aren't doing work yet, so bail. } Loading Loading @@ -5583,8 +5589,7 @@ public class BackupManagerService implements BackupManagerServiceInterface { // This relocates the app's entry from the head of the queue to // its order-appropriate position further down, so upon looping // a new candidate will be considered at the head. enqueueFullBackup(entry.packageName, nextEligible - MIN_FULL_BACKUP_INTERVAL); enqueueFullBackup(entry.packageName, nextEligible - fullBackupInterval); } } catch (NameNotFoundException nnf) { // So, we think we want to back this up, but it turns out the package Loading @@ -5605,7 +5610,7 @@ public class BackupManagerService implements BackupManagerServiceInterface { final long deferTime = latency; // pin for the closure mBackupHandler.post(new Runnable() { @Override public void run() { FullBackupJob.schedule(mContext, deferTime); FullBackupJob.schedule(mContext, deferTime, mConstants); } }); return false; Loading Loading @@ -9851,7 +9856,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF } // ...and schedule a backup pass if necessary KeyValueBackupJob.schedule(mContext); KeyValueBackupJob.schedule(mContext, mConstants); } // Note: packageName is currently unused, but may be in the future Loading Loading @@ -10014,7 +10019,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF mPowerManager.getPowerSaveState(ServiceType.KEYVALUE_BACKUP); if (result.batterySaverEnabled) { if (DEBUG) Slog.v(TAG, "Not running backup while in battery save mode"); KeyValueBackupJob.schedule(mContext); // try again in several hours KeyValueBackupJob.schedule(mContext, mConstants); // try again in several hours } else { if (DEBUG) Slog.v(TAG, "Scheduling immediate backup pass"); synchronized (mQueueLock) { Loading Loading @@ -10387,7 +10392,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF synchronized (mQueueLock) { if (enable && !wasEnabled && mProvisioned) { // if we've just been enabled, start scheduling backup passes KeyValueBackupJob.schedule(mContext); KeyValueBackupJob.schedule(mContext, mConstants); scheduleNextFullBackupJob(0); } else if (!enable) { // No longer enabled, so stop running backups Loading services/backup/java/com/android/server/backup/FullBackupJob.java +7 −5 Original line number Diff line number Diff line Loading @@ -34,12 +34,14 @@ public class FullBackupJob extends JobService { JobParameters mParams; public static void schedule(Context ctx, long minDelay) { public static void schedule(Context ctx, long minDelay, BackupManagerConstants constants) { JobScheduler js = (JobScheduler) ctx.getSystemService(Context.JOB_SCHEDULER_SERVICE); JobInfo.Builder builder = new JobInfo.Builder(JOB_ID, sIdleService) .setRequiresDeviceIdle(true) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) .setRequiresCharging(true); JobInfo.Builder builder = new JobInfo.Builder(JOB_ID, sIdleService); synchronized (constants) { builder.setRequiresDeviceIdle(true) .setRequiredNetworkType(constants.getFullBackupRequiredNetworkType()) .setRequiresCharging(constants.getFullBackupRequireCharging()); } if (minDelay > 0) { builder.setMinimumLatency(minDelay); } Loading services/backup/java/com/android/server/backup/KeyValueBackupJob.java +33 −27 Original line number Diff line number Diff line Loading @@ -38,12 +38,6 @@ public class KeyValueBackupJob extends JobService { new ComponentName("android", KeyValueBackupJob.class.getName()); private static final int JOB_ID = 0x5039; // Minimum wait time between backups even while we're on charger static final long BATCH_INTERVAL = 4 * AlarmManager.INTERVAL_HOUR; // Random variation in next-backup scheduling time to avoid server load spikes private static final int FUZZ_MILLIS = 10 * 60 * 1000; // Once someone asks for a backup, this is how long we hold off until we find // an on-charging opportunity. If we hit this max latency we will run the operation // regardless. Privileged callers can always trigger an immediate pass via Loading @@ -53,33 +47,45 @@ public class KeyValueBackupJob extends JobService { private static boolean sScheduled = false; private static long sNextScheduled = 0; public static void schedule(Context ctx) { schedule(ctx, 0); public static void schedule(Context ctx, BackupManagerConstants constants) { schedule(ctx, 0, constants); } public static void schedule(Context ctx, long delay) { public static void schedule(Context ctx, long delay, BackupManagerConstants constants) { synchronized (KeyValueBackupJob.class) { if (!sScheduled) { if (sScheduled) { return; } final long interval; final long fuzz; final int networkType; final boolean needsCharging; synchronized (constants) { interval = constants.getKeyValueBackupIntervalMilliseconds(); fuzz = constants.getKeyValueBackupFuzzMilliseconds(); networkType = constants.getKeyValueBackupRequiredNetworkType(); needsCharging = constants.getKeyValueBackupRequireCharging(); } if (delay <= 0) { delay = BATCH_INTERVAL + new Random().nextInt(FUZZ_MILLIS); delay = interval + new Random().nextInt((int) fuzz); } if (BackupManagerService.DEBUG_SCHEDULING) { Slog.v(TAG, "Scheduling k/v pass in " + (delay / 1000 / 60) + " minutes"); Slog.v(TAG, "Scheduling k/v pass in " + (delay / 1000 / 60) + " minutes"); } JobScheduler js = (JobScheduler) ctx.getSystemService(Context.JOB_SCHEDULER_SERVICE); JobInfo.Builder builder = new JobInfo.Builder(JOB_ID, sKeyValueJobService) .setMinimumLatency(delay) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) .setRequiresCharging(true) .setRequiredNetworkType(networkType) .setRequiresCharging(needsCharging) .setOverrideDeadline(MAX_DEFERRAL); JobScheduler js = (JobScheduler) ctx.getSystemService(Context.JOB_SCHEDULER_SERVICE); js.schedule(builder.build()); sNextScheduled = System.currentTimeMillis() + delay; sScheduled = true; } } } public static void cancel(Context ctx) { synchronized (KeyValueBackupJob.class) { Loading services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java +69 −53 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.backup; import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND; import static com.android.server.backup.internal.BackupHandler.MSG_BACKUP_OPERATION_TIMEOUT; import static com.android.server.backup.internal.BackupHandler.MSG_FULL_CONFIRMATION_TIMEOUT; import static com.android.server.backup.internal.BackupHandler.MSG_OP_COMPLETE; Loading Loading @@ -212,14 +213,12 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter // order to give them time to enter the backup password. private static final long TIMEOUT_FULL_CONFIRMATION = 60 * 1000; // How long between attempts to perform a full-data backup of any given app private static final long MIN_FULL_BACKUP_INTERVAL = 1000 * 60 * 60 * 24; // one day // If an app is busy when we want to do a full-data backup, how long to defer the retry. // This is fuzzed, so there are two parameters; backoff_min + Rand[0, backoff_fuzz) private static final long BUSY_BACKOFF_MIN_MILLIS = 1000 * 60 * 60; // one hour private static final int BUSY_BACKOFF_FUZZ = 1000 * 60 * 60 * 2; // two hours private BackupManagerConstants mConstants; private Context mContext; private PackageManager mPackageManager; private IPackageManager mPackageManagerBinder; Loading Loading @@ -297,6 +296,10 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter return sInstance; } public BackupManagerConstants getConstants() { return mConstants; } public Context getContext() { return mContext; } Loading Loading @@ -623,7 +626,8 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter private File mBaseStateDir; private File mDataDir; private File mJournalDir; @Nullable private DataChangedJournal mJournal; @Nullable private DataChangedJournal mJournal; private final SecureRandom mRng = new SecureRandom(); Loading Loading @@ -753,6 +757,8 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter mJournalDir.mkdirs(); // creates mBaseStateDir along the way mJournal = null; // will be created on first use mConstants = new BackupManagerConstants(mBackupHandler, mContext.getContentResolver()); // Set up the various sorts of package tracking we do mFullBackupScheduleFile = new File(mBaseStateDir, "fb-schedule"); initPackageTracking(); Loading Loading @@ -1533,7 +1539,8 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter if (!mEnabled || !mProvisioned) { Slog.i(TAG, "Backup requested but e=" + mEnabled + " p=" + mProvisioned); BackupObserverUtils.sendBackupFinished(observer, BackupManager.ERROR_BACKUP_NOT_ALLOWED); BackupObserverUtils.sendBackupFinished(observer, BackupManager.ERROR_BACKUP_NOT_ALLOWED); final int logTag = mProvisioned ? BackupManagerMonitor.LOG_EVENT_ID_BACKUP_DISABLED : BackupManagerMonitor.LOG_EVENT_ID_DEVICE_NOT_PROVISIONED; Loading Loading @@ -1626,8 +1633,8 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter } // We don't want the backup jobs to kick in any time soon. // Reschedules them to run in the distant future. KeyValueBackupJob.schedule(mContext, BUSY_BACKOFF_MIN_MILLIS); FullBackupJob.schedule(mContext, 2 * BUSY_BACKOFF_MIN_MILLIS); KeyValueBackupJob.schedule(mContext, BUSY_BACKOFF_MIN_MILLIS, mConstants); FullBackupJob.schedule(mContext, 2 * BUSY_BACKOFF_MIN_MILLIS, mConstants); } finally { Binder.restoreCallingIdentity(oldToken); } Loading Loading @@ -1835,13 +1842,13 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter // due. final long upcomingLastBackup = mFullBackupQueue.get(0).lastBackup; final long timeSinceLast = System.currentTimeMillis() - upcomingLastBackup; final long appLatency = (timeSinceLast < MIN_FULL_BACKUP_INTERVAL) ? (MIN_FULL_BACKUP_INTERVAL - timeSinceLast) : 0; final long interval = mConstants.getFullBackupIntervalMilliseconds(); final long appLatency = (timeSinceLast < interval) ? (interval - timeSinceLast) : 0; final long latency = Math.max(transportMinLatency, appLatency); Runnable r = new Runnable() { @Override public void run() { FullBackupJob.schedule(mContext, latency); FullBackupJob.schedule(mContext, latency, mConstants); } }; mBackupHandler.postDelayed(r, 2500); Loading Loading @@ -1936,9 +1943,15 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter */ @Override public boolean beginFullBackup(FullBackupJob scheduledJob) { long now = System.currentTimeMillis(); final long now = System.currentTimeMillis(); final long fullBackupInterval; final long keyValueBackupInterval; synchronized (mConstants) { fullBackupInterval = mConstants.getFullBackupIntervalMilliseconds(); keyValueBackupInterval = mConstants.getKeyValueBackupIntervalMilliseconds(); } FullBackupEntry entry = null; long latency = MIN_FULL_BACKUP_INTERVAL; long latency = fullBackupInterval; if (!mEnabled || !mProvisioned) { // Backups are globally disabled, so don't proceed. We also don't reschedule Loading @@ -1957,7 +1970,7 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter mPowerManager.getPowerSaveState(ServiceType.FULL_BACKUP); if (result.batterySaverEnabled) { if (DEBUG) Slog.i(TAG, "Deferring scheduled full backups in battery saver mode"); FullBackupJob.schedule(mContext, KeyValueBackupJob.BATCH_INTERVAL); FullBackupJob.schedule(mContext, keyValueBackupInterval, mConstants); return false; } Loading Loading @@ -2000,20 +2013,20 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter // Typically this means we haven't run a key/value backup yet. Back off // full-backup operations by the key/value job's run interval so that // next time we run, we are likely to be able to make progress. latency = KeyValueBackupJob.BATCH_INTERVAL; latency = keyValueBackupInterval; } if (runBackup) { entry = mFullBackupQueue.get(0); long timeSinceRun = now - entry.lastBackup; runBackup = (timeSinceRun >= MIN_FULL_BACKUP_INTERVAL); runBackup = (timeSinceRun >= fullBackupInterval); if (!runBackup) { // It's too early to back up the next thing in the queue, so bow out if (MORE_DEBUG) { Slog.i(TAG, "Device ready but too early to back up next app"); } // Wait until the next app in the queue falls due for a full data backup latency = MIN_FULL_BACKUP_INTERVAL - timeSinceRun; latency = fullBackupInterval - timeSinceRun; break; // we know we aren't doing work yet, so bail. } Loading Loading @@ -2049,8 +2062,7 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter // This relocates the app's entry from the head of the queue to // its order-appropriate position further down, so upon looping // a new candidate will be considered at the head. enqueueFullBackup(entry.packageName, nextEligible - MIN_FULL_BACKUP_INTERVAL); enqueueFullBackup(entry.packageName, nextEligible - fullBackupInterval); } } catch (NameNotFoundException nnf) { // So, we think we want to back this up, but it turns out the package Loading @@ -2072,7 +2084,7 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter mBackupHandler.post(new Runnable() { @Override public void run() { FullBackupJob.schedule(mContext, deferTime); FullBackupJob.schedule(mContext, deferTime, mConstants); } }); return false; Loading Loading @@ -2153,7 +2165,7 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter } // ...and schedule a backup pass if necessary KeyValueBackupJob.schedule(mContext); KeyValueBackupJob.schedule(mContext, mConstants); } // Note: packageName is currently unused, but may be in the future Loading Loading @@ -2222,7 +2234,8 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter // Run an initialize operation for the given transport @Override public void initializeTransports(String[] transportNames, IBackupObserver observer) { mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "initializeTransport"); mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "initializeTransport"); if (MORE_DEBUG || true) { Slog.v(TAG, "initializeTransport(): " + Arrays.asList(transportNames)); } Loading Loading @@ -2296,7 +2309,7 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter mPowerManager.getPowerSaveState(ServiceType.KEYVALUE_BACKUP); if (result.batterySaverEnabled) { if (DEBUG) Slog.v(TAG, "Not running backup while in battery save mode"); KeyValueBackupJob.schedule(mContext); // try again in several hours KeyValueBackupJob.schedule(mContext, mConstants); // try again in several hours } else { if (DEBUG) Slog.v(TAG, "Scheduling immediate backup pass"); synchronized (mQueueLock) { Loading Loading @@ -2672,7 +2685,7 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter synchronized (mQueueLock) { if (enable && !wasEnabled && mProvisioned) { // if we've just been enabled, start scheduling backup passes KeyValueBackupJob.schedule(mContext); KeyValueBackupJob.schedule(mContext, mConstants); scheduleNextFullBackupJob(0); } else if (!enable) { // No longer enabled, so stop running backups Loading Loading @@ -2808,14 +2821,16 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter Slog.v(TAG, "selectBackupTransportAsync() called with transport " + transport.flattenToShortString()); mTransportManager.ensureTransportReady(transport, new TransportManager.TransportReadyCallback() { mTransportManager.ensureTransportReady(transport, new TransportManager.TransportReadyCallback() { @Override public void onSuccess(String transportName) { mTransportManager.selectTransport(transportName); Settings.Secure.putString(mContext.getContentResolver(), Settings.Secure.BACKUP_TRANSPORT, mTransportManager.getCurrentTransportName()); Slog.v(TAG, "Transport successfully selected: " + transport.flattenToShortString()); Slog.v(TAG, "Transport successfully selected: " + transport.flattenToShortString()); try { listener.onSuccess(transportName); } catch (RemoteException e) { Loading @@ -2825,7 +2840,8 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter @Override public void onFailure(int reason) { Slog.v(TAG, "Failed to select transport: " + transport.flattenToShortString()); Slog.v(TAG, "Failed to select transport: " + transport.flattenToShortString()); try { listener.onFailure(reason); } catch (RemoteException e) { Loading services/backup/java/com/android/server/backup/internal/PerformBackupTask.java +2 −1 Original line number Diff line number Diff line Loading @@ -1060,7 +1060,8 @@ public class PerformBackupTask implements BackupRestoreTask { Slog.w(TAG, "Unable to contact transport for recommended backoff: " + e.getMessage()); delay = 0; // use the scheduler's default } KeyValueBackupJob.schedule(backupManagerService.getContext(), delay); KeyValueBackupJob.schedule(backupManagerService.getContext(), delay, backupManagerService.getConstants()); for (BackupRequest request : mOriginalQueue) { backupManagerService.dataChangedImpl(request.packageName); Loading Loading
services/backup/java/com/android/server/backup/BackupManagerService.java +27 −22 Original line number Diff line number Diff line Loading @@ -293,14 +293,12 @@ public class BackupManagerService implements BackupManagerServiceInterface { // order to give them time to enter the backup password. static final long TIMEOUT_FULL_CONFIRMATION = 60 * 1000; // How long between attempts to perform a full-data backup of any given app static final long MIN_FULL_BACKUP_INTERVAL = 1000 * 60 * 60 * 24; // one day // If an app is busy when we want to do a full-data backup, how long to defer the retry. // This is fuzzed, so there are two parameters; backoff_min + Rand[0, backoff_fuzz) static final long BUSY_BACKOFF_MIN_MILLIS = 1000 * 60 * 60; // one hour static final int BUSY_BACKOFF_FUZZ = 1000 * 60 * 60 * 2; // two hours BackupManagerConstants mConstants; Context mContext; private PackageManager mPackageManager; IPackageManager mPackageManagerBinder; Loading Loading @@ -457,7 +455,7 @@ public class BackupManagerService implements BackupManagerServiceInterface { if (mProvisioned && !wasProvisioned && mEnabled) { // we're now good to go, so start the backup alarms if (MORE_DEBUG) Slog.d(TAG, "Now provisioned, so starting backups"); KeyValueBackupJob.schedule(mContext); KeyValueBackupJob.schedule(mContext, mConstants); scheduleNextFullBackupJob(0); } } Loading Loading @@ -1323,6 +1321,8 @@ public class BackupManagerService implements BackupManagerServiceInterface { mJournalDir.mkdirs(); // creates mBaseStateDir along the way mJournal = null; // will be created on first use mConstants = new BackupManagerConstants(mBackupHandler, mContext.getContentResolver()); // Set up the various sorts of package tracking we do mFullBackupScheduleFile = new File(mBaseStateDir, "fb-schedule"); initPackageTracking(); Loading Loading @@ -2478,8 +2478,8 @@ public class BackupManagerService implements BackupManagerServiceInterface { } // We don't want the backup jobs to kick in any time soon. // Reschedules them to run in the distant future. KeyValueBackupJob.schedule(mContext, BUSY_BACKOFF_MIN_MILLIS); FullBackupJob.schedule(mContext, 2 * BUSY_BACKOFF_MIN_MILLIS); KeyValueBackupJob.schedule(mContext, BUSY_BACKOFF_MIN_MILLIS, mConstants); FullBackupJob.schedule(mContext, 2 * BUSY_BACKOFF_MIN_MILLIS, mConstants); } finally { Binder.restoreCallingIdentity(oldToken); } Loading Loading @@ -3558,7 +3558,7 @@ public class BackupManagerService implements BackupManagerServiceInterface { Slog.w(TAG, "Unable to contact transport for recommended backoff: " + e.getMessage()); delay = 0; // use the scheduler's default } KeyValueBackupJob.schedule(mContext, delay); KeyValueBackupJob.schedule(mContext, delay, mConstants); for (BackupRequest request : mOriginalQueue) { dataChangedImpl(request.packageName); Loading Loading @@ -5370,12 +5370,12 @@ public class BackupManagerService implements BackupManagerServiceInterface { // due. final long upcomingLastBackup = mFullBackupQueue.get(0).lastBackup; final long timeSinceLast = System.currentTimeMillis() - upcomingLastBackup; final long appLatency = (timeSinceLast < MIN_FULL_BACKUP_INTERVAL) ? (MIN_FULL_BACKUP_INTERVAL - timeSinceLast) : 0; final long interval = mConstants.getFullBackupIntervalMilliseconds(); final long appLatency = (timeSinceLast < interval) ? (interval - timeSinceLast) : 0; final long latency = Math.max(transportMinLatency, appLatency); Runnable r = new Runnable() { @Override public void run() { FullBackupJob.schedule(mContext, latency); FullBackupJob.schedule(mContext, latency, mConstants); } }; mBackupHandler.postDelayed(r, 2500); Loading Loading @@ -5470,9 +5470,15 @@ public class BackupManagerService implements BackupManagerServiceInterface { */ @Override public boolean beginFullBackup(FullBackupJob scheduledJob) { long now = System.currentTimeMillis(); final long now = System.currentTimeMillis(); FullBackupEntry entry = null; long latency = MIN_FULL_BACKUP_INTERVAL; final long fullBackupInterval; final long keyValueBackupInterval; synchronized (mConstants) { fullBackupInterval = mConstants.getFullBackupIntervalMilliseconds(); keyValueBackupInterval = mConstants.getKeyValueBackupIntervalMilliseconds(); } long latency = fullBackupInterval; if (!mEnabled || !mProvisioned) { // Backups are globally disabled, so don't proceed. We also don't reschedule Loading @@ -5491,7 +5497,7 @@ public class BackupManagerService implements BackupManagerServiceInterface { mPowerManager.getPowerSaveState(ServiceType.FULL_BACKUP); if (result.batterySaverEnabled) { if (DEBUG) Slog.i(TAG, "Deferring scheduled full backups in battery saver mode"); FullBackupJob.schedule(mContext, KeyValueBackupJob.BATCH_INTERVAL); FullBackupJob.schedule(mContext, keyValueBackupInterval, mConstants); return false; } Loading Loading @@ -5534,20 +5540,20 @@ public class BackupManagerService implements BackupManagerServiceInterface { // Typically this means we haven't run a key/value backup yet. Back off // full-backup operations by the key/value job's run interval so that // next time we run, we are likely to be able to make progress. latency = KeyValueBackupJob.BATCH_INTERVAL; latency = keyValueBackupInterval; } if (runBackup) { entry = mFullBackupQueue.get(0); long timeSinceRun = now - entry.lastBackup; runBackup = (timeSinceRun >= MIN_FULL_BACKUP_INTERVAL); runBackup = (timeSinceRun >= fullBackupInterval); if (!runBackup) { // It's too early to back up the next thing in the queue, so bow out if (MORE_DEBUG) { Slog.i(TAG, "Device ready but too early to back up next app"); } // Wait until the next app in the queue falls due for a full data backup latency = MIN_FULL_BACKUP_INTERVAL - timeSinceRun; latency = fullBackupInterval - timeSinceRun; break; // we know we aren't doing work yet, so bail. } Loading Loading @@ -5583,8 +5589,7 @@ public class BackupManagerService implements BackupManagerServiceInterface { // This relocates the app's entry from the head of the queue to // its order-appropriate position further down, so upon looping // a new candidate will be considered at the head. enqueueFullBackup(entry.packageName, nextEligible - MIN_FULL_BACKUP_INTERVAL); enqueueFullBackup(entry.packageName, nextEligible - fullBackupInterval); } } catch (NameNotFoundException nnf) { // So, we think we want to back this up, but it turns out the package Loading @@ -5605,7 +5610,7 @@ public class BackupManagerService implements BackupManagerServiceInterface { final long deferTime = latency; // pin for the closure mBackupHandler.post(new Runnable() { @Override public void run() { FullBackupJob.schedule(mContext, deferTime); FullBackupJob.schedule(mContext, deferTime, mConstants); } }); return false; Loading Loading @@ -9851,7 +9856,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF } // ...and schedule a backup pass if necessary KeyValueBackupJob.schedule(mContext); KeyValueBackupJob.schedule(mContext, mConstants); } // Note: packageName is currently unused, but may be in the future Loading Loading @@ -10014,7 +10019,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF mPowerManager.getPowerSaveState(ServiceType.KEYVALUE_BACKUP); if (result.batterySaverEnabled) { if (DEBUG) Slog.v(TAG, "Not running backup while in battery save mode"); KeyValueBackupJob.schedule(mContext); // try again in several hours KeyValueBackupJob.schedule(mContext, mConstants); // try again in several hours } else { if (DEBUG) Slog.v(TAG, "Scheduling immediate backup pass"); synchronized (mQueueLock) { Loading Loading @@ -10387,7 +10392,7 @@ if (MORE_DEBUG) Slog.v(TAG, " + got " + nRead + "; now wanting " + (size - soF synchronized (mQueueLock) { if (enable && !wasEnabled && mProvisioned) { // if we've just been enabled, start scheduling backup passes KeyValueBackupJob.schedule(mContext); KeyValueBackupJob.schedule(mContext, mConstants); scheduleNextFullBackupJob(0); } else if (!enable) { // No longer enabled, so stop running backups Loading
services/backup/java/com/android/server/backup/FullBackupJob.java +7 −5 Original line number Diff line number Diff line Loading @@ -34,12 +34,14 @@ public class FullBackupJob extends JobService { JobParameters mParams; public static void schedule(Context ctx, long minDelay) { public static void schedule(Context ctx, long minDelay, BackupManagerConstants constants) { JobScheduler js = (JobScheduler) ctx.getSystemService(Context.JOB_SCHEDULER_SERVICE); JobInfo.Builder builder = new JobInfo.Builder(JOB_ID, sIdleService) .setRequiresDeviceIdle(true) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) .setRequiresCharging(true); JobInfo.Builder builder = new JobInfo.Builder(JOB_ID, sIdleService); synchronized (constants) { builder.setRequiresDeviceIdle(true) .setRequiredNetworkType(constants.getFullBackupRequiredNetworkType()) .setRequiresCharging(constants.getFullBackupRequireCharging()); } if (minDelay > 0) { builder.setMinimumLatency(minDelay); } Loading
services/backup/java/com/android/server/backup/KeyValueBackupJob.java +33 −27 Original line number Diff line number Diff line Loading @@ -38,12 +38,6 @@ public class KeyValueBackupJob extends JobService { new ComponentName("android", KeyValueBackupJob.class.getName()); private static final int JOB_ID = 0x5039; // Minimum wait time between backups even while we're on charger static final long BATCH_INTERVAL = 4 * AlarmManager.INTERVAL_HOUR; // Random variation in next-backup scheduling time to avoid server load spikes private static final int FUZZ_MILLIS = 10 * 60 * 1000; // Once someone asks for a backup, this is how long we hold off until we find // an on-charging opportunity. If we hit this max latency we will run the operation // regardless. Privileged callers can always trigger an immediate pass via Loading @@ -53,33 +47,45 @@ public class KeyValueBackupJob extends JobService { private static boolean sScheduled = false; private static long sNextScheduled = 0; public static void schedule(Context ctx) { schedule(ctx, 0); public static void schedule(Context ctx, BackupManagerConstants constants) { schedule(ctx, 0, constants); } public static void schedule(Context ctx, long delay) { public static void schedule(Context ctx, long delay, BackupManagerConstants constants) { synchronized (KeyValueBackupJob.class) { if (!sScheduled) { if (sScheduled) { return; } final long interval; final long fuzz; final int networkType; final boolean needsCharging; synchronized (constants) { interval = constants.getKeyValueBackupIntervalMilliseconds(); fuzz = constants.getKeyValueBackupFuzzMilliseconds(); networkType = constants.getKeyValueBackupRequiredNetworkType(); needsCharging = constants.getKeyValueBackupRequireCharging(); } if (delay <= 0) { delay = BATCH_INTERVAL + new Random().nextInt(FUZZ_MILLIS); delay = interval + new Random().nextInt((int) fuzz); } if (BackupManagerService.DEBUG_SCHEDULING) { Slog.v(TAG, "Scheduling k/v pass in " + (delay / 1000 / 60) + " minutes"); Slog.v(TAG, "Scheduling k/v pass in " + (delay / 1000 / 60) + " minutes"); } JobScheduler js = (JobScheduler) ctx.getSystemService(Context.JOB_SCHEDULER_SERVICE); JobInfo.Builder builder = new JobInfo.Builder(JOB_ID, sKeyValueJobService) .setMinimumLatency(delay) .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) .setRequiresCharging(true) .setRequiredNetworkType(networkType) .setRequiresCharging(needsCharging) .setOverrideDeadline(MAX_DEFERRAL); JobScheduler js = (JobScheduler) ctx.getSystemService(Context.JOB_SCHEDULER_SERVICE); js.schedule(builder.build()); sNextScheduled = System.currentTimeMillis() + delay; sScheduled = true; } } } public static void cancel(Context ctx) { synchronized (KeyValueBackupJob.class) { Loading
services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java +69 −53 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.backup; import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND; import static com.android.server.backup.internal.BackupHandler.MSG_BACKUP_OPERATION_TIMEOUT; import static com.android.server.backup.internal.BackupHandler.MSG_FULL_CONFIRMATION_TIMEOUT; import static com.android.server.backup.internal.BackupHandler.MSG_OP_COMPLETE; Loading Loading @@ -212,14 +213,12 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter // order to give them time to enter the backup password. private static final long TIMEOUT_FULL_CONFIRMATION = 60 * 1000; // How long between attempts to perform a full-data backup of any given app private static final long MIN_FULL_BACKUP_INTERVAL = 1000 * 60 * 60 * 24; // one day // If an app is busy when we want to do a full-data backup, how long to defer the retry. // This is fuzzed, so there are two parameters; backoff_min + Rand[0, backoff_fuzz) private static final long BUSY_BACKOFF_MIN_MILLIS = 1000 * 60 * 60; // one hour private static final int BUSY_BACKOFF_FUZZ = 1000 * 60 * 60 * 2; // two hours private BackupManagerConstants mConstants; private Context mContext; private PackageManager mPackageManager; private IPackageManager mPackageManagerBinder; Loading Loading @@ -297,6 +296,10 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter return sInstance; } public BackupManagerConstants getConstants() { return mConstants; } public Context getContext() { return mContext; } Loading Loading @@ -623,7 +626,8 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter private File mBaseStateDir; private File mDataDir; private File mJournalDir; @Nullable private DataChangedJournal mJournal; @Nullable private DataChangedJournal mJournal; private final SecureRandom mRng = new SecureRandom(); Loading Loading @@ -753,6 +757,8 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter mJournalDir.mkdirs(); // creates mBaseStateDir along the way mJournal = null; // will be created on first use mConstants = new BackupManagerConstants(mBackupHandler, mContext.getContentResolver()); // Set up the various sorts of package tracking we do mFullBackupScheduleFile = new File(mBaseStateDir, "fb-schedule"); initPackageTracking(); Loading Loading @@ -1533,7 +1539,8 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter if (!mEnabled || !mProvisioned) { Slog.i(TAG, "Backup requested but e=" + mEnabled + " p=" + mProvisioned); BackupObserverUtils.sendBackupFinished(observer, BackupManager.ERROR_BACKUP_NOT_ALLOWED); BackupObserverUtils.sendBackupFinished(observer, BackupManager.ERROR_BACKUP_NOT_ALLOWED); final int logTag = mProvisioned ? BackupManagerMonitor.LOG_EVENT_ID_BACKUP_DISABLED : BackupManagerMonitor.LOG_EVENT_ID_DEVICE_NOT_PROVISIONED; Loading Loading @@ -1626,8 +1633,8 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter } // We don't want the backup jobs to kick in any time soon. // Reschedules them to run in the distant future. KeyValueBackupJob.schedule(mContext, BUSY_BACKOFF_MIN_MILLIS); FullBackupJob.schedule(mContext, 2 * BUSY_BACKOFF_MIN_MILLIS); KeyValueBackupJob.schedule(mContext, BUSY_BACKOFF_MIN_MILLIS, mConstants); FullBackupJob.schedule(mContext, 2 * BUSY_BACKOFF_MIN_MILLIS, mConstants); } finally { Binder.restoreCallingIdentity(oldToken); } Loading Loading @@ -1835,13 +1842,13 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter // due. final long upcomingLastBackup = mFullBackupQueue.get(0).lastBackup; final long timeSinceLast = System.currentTimeMillis() - upcomingLastBackup; final long appLatency = (timeSinceLast < MIN_FULL_BACKUP_INTERVAL) ? (MIN_FULL_BACKUP_INTERVAL - timeSinceLast) : 0; final long interval = mConstants.getFullBackupIntervalMilliseconds(); final long appLatency = (timeSinceLast < interval) ? (interval - timeSinceLast) : 0; final long latency = Math.max(transportMinLatency, appLatency); Runnable r = new Runnable() { @Override public void run() { FullBackupJob.schedule(mContext, latency); FullBackupJob.schedule(mContext, latency, mConstants); } }; mBackupHandler.postDelayed(r, 2500); Loading Loading @@ -1936,9 +1943,15 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter */ @Override public boolean beginFullBackup(FullBackupJob scheduledJob) { long now = System.currentTimeMillis(); final long now = System.currentTimeMillis(); final long fullBackupInterval; final long keyValueBackupInterval; synchronized (mConstants) { fullBackupInterval = mConstants.getFullBackupIntervalMilliseconds(); keyValueBackupInterval = mConstants.getKeyValueBackupIntervalMilliseconds(); } FullBackupEntry entry = null; long latency = MIN_FULL_BACKUP_INTERVAL; long latency = fullBackupInterval; if (!mEnabled || !mProvisioned) { // Backups are globally disabled, so don't proceed. We also don't reschedule Loading @@ -1957,7 +1970,7 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter mPowerManager.getPowerSaveState(ServiceType.FULL_BACKUP); if (result.batterySaverEnabled) { if (DEBUG) Slog.i(TAG, "Deferring scheduled full backups in battery saver mode"); FullBackupJob.schedule(mContext, KeyValueBackupJob.BATCH_INTERVAL); FullBackupJob.schedule(mContext, keyValueBackupInterval, mConstants); return false; } Loading Loading @@ -2000,20 +2013,20 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter // Typically this means we haven't run a key/value backup yet. Back off // full-backup operations by the key/value job's run interval so that // next time we run, we are likely to be able to make progress. latency = KeyValueBackupJob.BATCH_INTERVAL; latency = keyValueBackupInterval; } if (runBackup) { entry = mFullBackupQueue.get(0); long timeSinceRun = now - entry.lastBackup; runBackup = (timeSinceRun >= MIN_FULL_BACKUP_INTERVAL); runBackup = (timeSinceRun >= fullBackupInterval); if (!runBackup) { // It's too early to back up the next thing in the queue, so bow out if (MORE_DEBUG) { Slog.i(TAG, "Device ready but too early to back up next app"); } // Wait until the next app in the queue falls due for a full data backup latency = MIN_FULL_BACKUP_INTERVAL - timeSinceRun; latency = fullBackupInterval - timeSinceRun; break; // we know we aren't doing work yet, so bail. } Loading Loading @@ -2049,8 +2062,7 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter // This relocates the app's entry from the head of the queue to // its order-appropriate position further down, so upon looping // a new candidate will be considered at the head. enqueueFullBackup(entry.packageName, nextEligible - MIN_FULL_BACKUP_INTERVAL); enqueueFullBackup(entry.packageName, nextEligible - fullBackupInterval); } } catch (NameNotFoundException nnf) { // So, we think we want to back this up, but it turns out the package Loading @@ -2072,7 +2084,7 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter mBackupHandler.post(new Runnable() { @Override public void run() { FullBackupJob.schedule(mContext, deferTime); FullBackupJob.schedule(mContext, deferTime, mConstants); } }); return false; Loading Loading @@ -2153,7 +2165,7 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter } // ...and schedule a backup pass if necessary KeyValueBackupJob.schedule(mContext); KeyValueBackupJob.schedule(mContext, mConstants); } // Note: packageName is currently unused, but may be in the future Loading Loading @@ -2222,7 +2234,8 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter // Run an initialize operation for the given transport @Override public void initializeTransports(String[] transportNames, IBackupObserver observer) { mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "initializeTransport"); mContext.enforceCallingPermission(android.Manifest.permission.BACKUP, "initializeTransport"); if (MORE_DEBUG || true) { Slog.v(TAG, "initializeTransport(): " + Arrays.asList(transportNames)); } Loading Loading @@ -2296,7 +2309,7 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter mPowerManager.getPowerSaveState(ServiceType.KEYVALUE_BACKUP); if (result.batterySaverEnabled) { if (DEBUG) Slog.v(TAG, "Not running backup while in battery save mode"); KeyValueBackupJob.schedule(mContext); // try again in several hours KeyValueBackupJob.schedule(mContext, mConstants); // try again in several hours } else { if (DEBUG) Slog.v(TAG, "Scheduling immediate backup pass"); synchronized (mQueueLock) { Loading Loading @@ -2672,7 +2685,7 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter synchronized (mQueueLock) { if (enable && !wasEnabled && mProvisioned) { // if we've just been enabled, start scheduling backup passes KeyValueBackupJob.schedule(mContext); KeyValueBackupJob.schedule(mContext, mConstants); scheduleNextFullBackupJob(0); } else if (!enable) { // No longer enabled, so stop running backups Loading Loading @@ -2808,14 +2821,16 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter Slog.v(TAG, "selectBackupTransportAsync() called with transport " + transport.flattenToShortString()); mTransportManager.ensureTransportReady(transport, new TransportManager.TransportReadyCallback() { mTransportManager.ensureTransportReady(transport, new TransportManager.TransportReadyCallback() { @Override public void onSuccess(String transportName) { mTransportManager.selectTransport(transportName); Settings.Secure.putString(mContext.getContentResolver(), Settings.Secure.BACKUP_TRANSPORT, mTransportManager.getCurrentTransportName()); Slog.v(TAG, "Transport successfully selected: " + transport.flattenToShortString()); Slog.v(TAG, "Transport successfully selected: " + transport.flattenToShortString()); try { listener.onSuccess(transportName); } catch (RemoteException e) { Loading @@ -2825,7 +2840,8 @@ public class RefactoredBackupManagerService implements BackupManagerServiceInter @Override public void onFailure(int reason) { Slog.v(TAG, "Failed to select transport: " + transport.flattenToShortString()); Slog.v(TAG, "Failed to select transport: " + transport.flattenToShortString()); try { listener.onFailure(reason); } catch (RemoteException e) { Loading
services/backup/java/com/android/server/backup/internal/PerformBackupTask.java +2 −1 Original line number Diff line number Diff line Loading @@ -1060,7 +1060,8 @@ public class PerformBackupTask implements BackupRestoreTask { Slog.w(TAG, "Unable to contact transport for recommended backoff: " + e.getMessage()); delay = 0; // use the scheduler's default } KeyValueBackupJob.schedule(backupManagerService.getContext(), delay); KeyValueBackupJob.schedule(backupManagerService.getContext(), delay, backupManagerService.getConstants()); for (BackupRequest request : mOriginalQueue) { backupManagerService.dataChangedImpl(request.packageName); Loading