diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java index 959820a9e5d..e51db0873c3 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java +++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProvider.java @@ -135,6 +135,11 @@ public interface PowerUsageFeatureProvider { */ boolean isExtraDefend(); + /** + * Returns {@code true} if delay the hourly job when device is booting. + */ + boolean delayHourlyJobWhenBooting(); + /** * Gets a intent for one time bypass charge limited to resume charging. */ diff --git a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java index 94e4872d303..ba8587cc37c 100644 --- a/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java +++ b/src/com/android/settings/fuelgauge/PowerUsageFeatureProviderImpl.java @@ -156,6 +156,11 @@ public class PowerUsageFeatureProviderImpl implements PowerUsageFeatureProvider return false; } + @Override + public boolean delayHourlyJobWhenBooting() { + return true; + } + @Override public Set getHideBackgroundUsageTimeSet(Context context) { return new ArraySet<>(); diff --git a/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java index c9d73cdbe70..8c9285edbc8 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java +++ b/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiver.java @@ -24,13 +24,17 @@ import android.os.Looper; import android.util.Log; import com.android.settings.core.instrumentation.ElapsedTimeUtils; +import com.android.settings.overlay.FeatureFactory; import java.time.Duration; /** Receives broadcasts to start or stop the periodic fetching job. */ public final class BootBroadcastReceiver extends BroadcastReceiver { private static final String TAG = "BootBroadcastReceiver"; - private static final long RESCHEDULE_FOR_BOOT_ACTION = Duration.ofSeconds(6).toMillis(); + private static final long RESCHEDULE_FOR_BOOT_ACTION_WITH_DELAY = + Duration.ofMinutes(40).toMillis(); + private static final long RESCHEDULE_FOR_BOOT_ACTION_WITHOUT_DELAY = + Duration.ofSeconds(6).toMillis(); private final Handler mHandler = new Handler(Looper.getMainLooper()); @@ -67,7 +71,7 @@ public final class BootBroadcastReceiver extends BroadcastReceiver { case Intent.ACTION_TIME_CHANGED: Log.d(TAG, "refresh job and clear all data from action=" + action); DatabaseUtils.clearAll(context); - PeriodicJobManager.getInstance(context).refreshJob(); + PeriodicJobManager.getInstance(context).refreshJob(/*fromBoot=*/ false); break; default: Log.w(TAG, "receive unsupported action=" + action); @@ -78,15 +82,23 @@ public final class BootBroadcastReceiver extends BroadcastReceiver { final Intent recheckIntent = new Intent(ACTION_PERIODIC_JOB_RECHECK); recheckIntent.setClass(context, BootBroadcastReceiver.class); mHandler.postDelayed(() -> context.sendBroadcast(recheckIntent), - RESCHEDULE_FOR_BOOT_ACTION); + getRescheduleTimeForBootAction(context)); } else if (ACTION_SETUP_WIZARD_FINISHED.equals(action)) { ElapsedTimeUtils.storeSuwFinishedTimestamp(context, System.currentTimeMillis()); } } + private long getRescheduleTimeForBootAction(Context context) { + final boolean delayHourlyJobWhenBooting = + FeatureFactory.getFactory(context) + .getPowerUsageFeatureProvider(context) + .delayHourlyJobWhenBooting(); + return delayHourlyJobWhenBooting + ? RESCHEDULE_FOR_BOOT_ACTION_WITH_DELAY + : RESCHEDULE_FOR_BOOT_ACTION_WITHOUT_DELAY; + } + private static void refreshJobs(Context context) { - // Clears useless data from battery usage database if needed. - DatabaseUtils.clearExpiredDataIfNeeded(context); - PeriodicJobManager.getInstance(context).refreshJob(); + PeriodicJobManager.getInstance(context).refreshJob(/*fromBoot=*/ true); } } diff --git a/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobManager.java b/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobManager.java index 39293dcc466..2b18e9237a5 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobManager.java +++ b/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobManager.java @@ -24,6 +24,8 @@ import android.util.Log; import androidx.annotation.VisibleForTesting; +import com.android.settings.overlay.FeatureFactory; + import java.text.SimpleDateFormat; import java.time.Clock; import java.time.Duration; @@ -45,6 +47,9 @@ public final class PeriodicJobManager { @VisibleForTesting static final int DATA_FETCH_INTERVAL_MINUTE = 60; + @VisibleForTesting + static long sBroadcastDelayFromBoot = Duration.ofMinutes(40).toMillis(); + @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) void reset() { sSingleton = null; // for testing only @@ -65,7 +70,7 @@ public final class PeriodicJobManager { /** Schedules the next alarm job if it is available. */ @SuppressWarnings("JavaUtilDate") - public void refreshJob() { + public void refreshJob(final boolean fromBoot) { if (mAlarmManager == null) { Log.e(TAG, "cannot schedule next alarm job"); return; @@ -74,7 +79,7 @@ public final class PeriodicJobManager { final PendingIntent pendingIntent = getPendingIntent(); cancelJob(pendingIntent); // Uses UTC time to avoid scheduler is impacted by different timezone. - final long triggerAtMillis = getTriggerAtMillis(Clock.systemUTC()); + final long triggerAtMillis = getTriggerAtMillis(mContext, Clock.systemUTC(), fromBoot); mAlarmManager.setExactAndAllowWhileIdle( AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent); Log.d(TAG, "schedule next alarm job at " @@ -90,11 +95,21 @@ public final class PeriodicJobManager { } /** Gets the next alarm trigger UTC time in milliseconds. */ - static long getTriggerAtMillis(Clock clock) { + static long getTriggerAtMillis(Context context, Clock clock, final boolean fromBoot) { long currentTimeMillis = clock.millis(); + final boolean delayHourlyJobWhenBooting = + FeatureFactory.getFactory(context) + .getPowerUsageFeatureProvider(context) + .delayHourlyJobWhenBooting(); // Rounds to the previous nearest time slot and shifts to the next one. long timeSlotUnit = Duration.ofMinutes(DATA_FETCH_INTERVAL_MINUTE).toMillis(); - return (currentTimeMillis / timeSlotUnit) * timeSlotUnit + timeSlotUnit; + long targetTime = (currentTimeMillis / timeSlotUnit) * timeSlotUnit + timeSlotUnit; + if (delayHourlyJobWhenBooting + && fromBoot + && (targetTime - currentTimeMillis) <= sBroadcastDelayFromBoot) { + targetTime += timeSlotUnit; + } + return targetTime; } private PendingIntent getPendingIntent() { diff --git a/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java b/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java index d6a2f625e81..3ca45322184 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java +++ b/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobReceiver.java @@ -42,7 +42,7 @@ public final class PeriodicJobReceiver extends BroadcastReceiver { BatteryUsageDataLoader.enqueueWork(context, /*isFullChargeStart=*/ false); AppUsageDataLoader.enqueueWork(context); Log.d(TAG, "refresh periodic job from action=" + action); - PeriodicJobManager.getInstance(context).refreshJob(); + PeriodicJobManager.getInstance(context).refreshJob(/*fromBoot=*/ false); DatabaseUtils.clearExpiredDataIfNeeded(context); } } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiverTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiverTest.java index 514ac63d0f3..ba51e293c90 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiverTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BootBroadcastReceiverTest.java @@ -124,28 +124,6 @@ public final class BootBroadcastReceiverTest { assertThat(mShadowAlarmManager.peekNextScheduledAlarm()).isNull(); } - @Test - public void onReceive_containsExpiredData_clearsExpiredDataFromDatabase() - throws InterruptedException { - insertExpiredData(/*shiftDay=*/ DatabaseUtils.DATA_RETENTION_INTERVAL_DAY); - - mReceiver.onReceive(mContext, new Intent(Intent.ACTION_BOOT_COMPLETED)); - - TimeUnit.MILLISECONDS.sleep(100); - assertThat(mDao.getAllAfter(0)).hasSize(1); - } - - @Test - public void onReceive_withoutExpiredData_notClearsExpiredDataFromDatabase() - throws InterruptedException { - insertExpiredData(/*shiftDay=*/ DatabaseUtils.DATA_RETENTION_INTERVAL_DAY - 1); - - mReceiver.onReceive(mContext, new Intent(Intent.ACTION_BOOT_COMPLETED)); - - TimeUnit.MILLISECONDS.sleep(100); - assertThat(mDao.getAllAfter(0)).hasSize(3); - } - @Test public void onReceive_withTimeChangedIntent_clearsAllDataAndRefreshesJob() throws InterruptedException { diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobManagerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobManagerTest.java index 9e27bb094d0..efbce12ea05 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobManagerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/PeriodicJobManagerTest.java @@ -57,7 +57,7 @@ public final class PeriodicJobManagerTest { @Test public void refreshJob_refreshesAlarmJob() { - mPeriodicJobManager.refreshJob(); + mPeriodicJobManager.refreshJob(/*fromBoot=*/ false); final ShadowAlarmManager.ScheduledAlarm alarm = mShadowAlarmManager.peekNextScheduledAlarm(); @@ -76,7 +76,7 @@ public final class PeriodicJobManagerTest { FakeClock fakeClock = new FakeClock(); fakeClock.setCurrentTime(currentTimeDuration); - assertThat(PeriodicJobManager.getTriggerAtMillis(fakeClock)) + assertThat(PeriodicJobManager.getTriggerAtMillis(mContext, fakeClock, /*fromBoot=*/ false)) .isEqualTo(currentTimeDuration.plusMinutes(timeSlotUnit).toMillis()); } @@ -89,7 +89,7 @@ public final class PeriodicJobManagerTest { fakeClock.setCurrentTime( currentTimeDuration.plusMinutes(1L).plusMillis(51L)); - assertThat(PeriodicJobManager.getTriggerAtMillis(fakeClock)) + assertThat(PeriodicJobManager.getTriggerAtMillis(mContext, fakeClock, /*fromBoot=*/ true)) .isEqualTo(currentTimeDuration.plusMinutes(timeSlotUnit).toMillis()); } }