From d65e58a90204a9758dee10f665aab1029f947f81 Mon Sep 17 00:00:00 2001 From: Suprabh Shukla Date: Mon, 5 Feb 2018 20:36:08 -0800 Subject: [PATCH] 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 --- .../android/server/AlarmManagerService.java | 57 ++++++++++--------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index 17c617c095d87..45b2118db1f3f 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -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,24 +1508,19 @@ 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 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 packageUser = Pair.create(alarm.sourcePackage, UserHandle.getUserId(alarm.creatorUid)); mLastAlarmDeliveredForPackage.put(packageUser, nowELAPSED);