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

Commit cf7e1141 authored by Kuan Wang's avatar Kuan Wang
Browse files

Cancel data loading when hourly job happens in the first 40 minutes

after booting in AOSP.

Test: make RunSettingsRoboTests + manual
Bug: 257384343
Change-Id: I437b68719ff5ece73fa33b74cb144f4262528e8c
parent 269b14fb
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -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.
     */
+5 −0
Original line number Diff line number Diff line
@@ -156,6 +156,11 @@ public class PowerUsageFeatureProviderImpl implements PowerUsageFeatureProvider
        return false;
    }

    @Override
    public boolean delayHourlyJobWhenBooting() {
        return true;
    }

    @Override
    public Set<CharSequence> getHideBackgroundUsageTimeSet(Context context) {
        return new ArraySet<>();
+18 −6
Original line number Diff line number Diff line
@@ -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);
    }
}
+19 −4
Original line number Diff line number Diff line
@@ -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() {
+1 −1
Original line number Diff line number Diff line
@@ -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);
    }
}
Loading