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

Commit d65e58a9 authored by Suprabh Shukla's avatar Suprabh Shukla
Browse files

Allow-while-idle alarms throttling for app standby

Started throttling allow_while_idle alarms again. Throttled
allow_while_idle alarms behave as if the scheduling app scheduled it at
the next eligible time, so there is no conflict with app standby
rescheduling. Also exempting alarms by mSystemUiUid from app standby

Test: atest CtsAlarmManagerTestCases:AppStandbyTests

Bug: 72660630
Bug: 72916765
Change-Id: Ibb8ab449e1c148fc9689f1c2afb89b8d9630edfa
parent 45ae0fba
Loading
Loading
Loading
Loading
+31 −26
Original line number Diff line number Diff line
@@ -88,6 +88,7 @@ import java.util.TreeSet;
import java.util.function.Predicate;

import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE;
import static android.app.AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
import static android.app.AlarmManager.RTC_WAKEUP;
import static android.app.AlarmManager.RTC;
import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
@@ -1011,7 +1012,7 @@ class AlarmManagerService extends SystemService {
            // Recurring alarms may have passed several alarm intervals while the
            // alarm was kept pending. Send the appropriate trigger count.
            if (alarm.repeatInterval > 0) {
                alarm.count += (nowELAPSED - alarm.requestedWhenElapsed) / alarm.repeatInterval;
                alarm.count += (nowELAPSED - alarm.expectedWhenElapsed) / alarm.repeatInterval;
                // Also schedule its next recurrence
                final long delta = alarm.count * alarm.repeatInterval;
                final long nextElapsed = alarm.whenElapsed + delta;
@@ -1507,25 +1508,20 @@ class AlarmManagerService extends SystemService {
     * Adjusts the alarm delivery time based on the current app standby bucket.
     * @param alarm The alarm to adjust
     * @return true if the alarm delivery time was updated.
     * TODO: Reduce the number of calls to getAppStandbyBucket by batching the calls per
     * {package, user} pairs
     */
    private boolean adjustDeliveryTimeBasedOnStandbyBucketLocked(Alarm alarm) {
        if (alarm.alarmClock != null || UserHandle.isCore(alarm.creatorUid)) {
            return false;
        }
        // TODO: short term fix for b/72816079, remove after a proper fix is in place
        if ((alarm.flags & AlarmManager.FLAG_ALLOW_WHILE_IDLE) != 0) {
        if (isExemptFromAppStandby(alarm)) {
            return false;
        }
        if (mAppStandbyParole) {
            if (alarm.whenElapsed > alarm.requestedWhenElapsed) {
            if (alarm.whenElapsed > alarm.expectedWhenElapsed) {
                // We did defer this alarm earlier, restore original requirements
                alarm.whenElapsed = alarm.requestedWhenElapsed;
                alarm.maxWhenElapsed = alarm.requestedMaxWhenElapsed;
            }
                alarm.whenElapsed = alarm.expectedWhenElapsed;
                alarm.maxWhenElapsed = alarm.expectedMaxWhenElapsed;
                return true;
            }
            return false;
        }
        final long oldWhenElapsed = alarm.whenElapsed;
        final long oldMaxWhenElapsed = alarm.maxWhenElapsed;

@@ -1538,13 +1534,13 @@ class AlarmManagerService extends SystemService {
        final long lastElapsed = mLastAlarmDeliveredForPackage.getOrDefault(packageUser, 0L);
        if (lastElapsed > 0) {
            final long minElapsed = lastElapsed + getMinDelayForBucketLocked(standbyBucket);
            if (alarm.requestedWhenElapsed < minElapsed) {
            if (alarm.expectedWhenElapsed < minElapsed) {
                alarm.whenElapsed = alarm.maxWhenElapsed = minElapsed;
            } else {
                // app is now eligible to run alarms at the originally requested window.
                // Restore original requirements in case they were changed earlier.
                alarm.whenElapsed = alarm.requestedWhenElapsed;
                alarm.maxWhenElapsed = alarm.requestedMaxWhenElapsed;
                alarm.whenElapsed = alarm.expectedWhenElapsed;
                alarm.maxWhenElapsed = alarm.expectedMaxWhenElapsed;
            }
        }
        return (oldWhenElapsed != alarm.whenElapsed || oldMaxWhenElapsed != alarm.maxWhenElapsed);
@@ -1728,7 +1724,7 @@ class AlarmManagerService extends SystemService {
            // This means we will allow these alarms to go off as normal even while idle, with no
            // timing restrictions.
            } else if (workSource == null && (callingUid < Process.FIRST_APPLICATION_UID
                    || callingUid == mSystemUiUid
                    || UserHandle.isSameApp(callingUid, mSystemUiUid)
                    || mForceAppStandbyTracker.isUidPowerSaveWhitelisted(callingUid))) {
                flags |= AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
                flags &= ~AlarmManager.FLAG_ALLOW_WHILE_IDLE;
@@ -3000,10 +2996,11 @@ class AlarmManagerService extends SystemService {
                        // Whoops, it hasn't been long enough since the last ALLOW_WHILE_IDLE
                        // alarm went off for this app.  Reschedule the alarm to be in the
                        // correct time period.
                        alarm.whenElapsed = minTime;
                        alarm.expectedWhenElapsed = alarm.whenElapsed = minTime;
                        if (alarm.maxWhenElapsed < minTime) {
                            alarm.maxWhenElapsed = minTime;
                        }
                        alarm.expectedMaxWhenElapsed = alarm.maxWhenElapsed;
                        if (RECORD_DEVICE_IDLE_ALARMS) {
                            IdleDispatchEntry ent = new IdleDispatchEntry();
                            ent.uid = alarm.uid;
@@ -3053,7 +3050,7 @@ class AlarmManagerService extends SystemService {
                if (alarm.repeatInterval > 0) {
                    // this adjustment will be zero if we're late by
                    // less than one full repeat interval
                    alarm.count += (nowELAPSED - alarm.requestedWhenElapsed) / alarm.repeatInterval;
                    alarm.count += (nowELAPSED - alarm.expectedWhenElapsed) / alarm.repeatInterval;

                    // Also schedule its next recurrence
                    final long delta = alarm.count * alarm.repeatInterval;
@@ -3128,8 +3125,9 @@ class AlarmManagerService extends SystemService {
        public long windowLength;
        public long whenElapsed;    // 'when' in the elapsed time base
        public long maxWhenElapsed; // also in the elapsed time base
        public final long requestedWhenElapsed; // original expiry time requested by the app
        public final long requestedMaxWhenElapsed;
        // Expected alarm expiry time before app standby deferring is applied.
        public long expectedWhenElapsed;
        public long expectedMaxWhenElapsed;
        public long repeatInterval;
        public PriorityClass priorityClass;

@@ -3143,10 +3141,10 @@ class AlarmManagerService extends SystemService {
                    || _type == AlarmManager.RTC_WAKEUP;
            when = _when;
            whenElapsed = _whenElapsed;
            requestedWhenElapsed = _whenElapsed;
            expectedWhenElapsed = _whenElapsed;
            windowLength = _windowLength;
            maxWhenElapsed = _maxWhen;
            requestedMaxWhenElapsed = _maxWhen;
            expectedMaxWhenElapsed = _maxWhen;
            repeatInterval = _interval;
            operation = _op;
            listener = _rec;
@@ -3205,8 +3203,10 @@ class AlarmManagerService extends SystemService {
            final boolean isRtc = (type == RTC || type == RTC_WAKEUP);
            pw.print(prefix); pw.print("tag="); pw.println(statsTag);
            pw.print(prefix); pw.print("type="); pw.print(type);
                    pw.print(" requestedWhenElapsed="); TimeUtils.formatDuration(
                            requestedWhenElapsed, nowELAPSED, pw);
                    pw.print(" expectedWhenElapsed="); TimeUtils.formatDuration(
                    expectedWhenElapsed, nowELAPSED, pw);
                    pw.print(" expectedMaxWhenElapsed="); TimeUtils.formatDuration(
                    expectedMaxWhenElapsed, nowELAPSED, pw);
                    pw.print(" whenElapsed="); TimeUtils.formatDuration(whenElapsed,
                            nowELAPSED, pw);
                    pw.print(" when=");
@@ -3344,6 +3344,11 @@ class AlarmManagerService extends SystemService {
        }
    }

    private boolean isExemptFromAppStandby(Alarm a) {
        return a.alarmClock != null || UserHandle.isCore(a.creatorUid)
                || (a.flags & FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED) != 0;
    }

    private class AlarmThread extends Thread
    {
        public AlarmThread()
@@ -3462,7 +3467,7 @@ class AlarmManagerService extends SystemService {
                                    new ArraySet<>();
                            for (int i = 0; i < triggerList.size(); i++) {
                                final Alarm a = triggerList.get(i);
                                if (!UserHandle.isCore(a.creatorUid)) {
                                if (!isExemptFromAppStandby(a)) {
                                    triggerPackages.add(Pair.create(
                                            a.sourcePackage, UserHandle.getUserId(a.creatorUid)));
                                }
@@ -4148,7 +4153,7 @@ class AlarmManagerService extends SystemService {
                    mAllowWhileIdleDispatches.add(ent);
                }
            }
            if (!UserHandle.isCore(alarm.creatorUid)) {
            if (!isExemptFromAppStandby(alarm)) {
                final Pair<String, Integer> packageUser = Pair.create(alarm.sourcePackage,
                        UserHandle.getUserId(alarm.creatorUid));
                mLastAlarmDeliveredForPackage.put(packageUser, nowELAPSED);