From 980954b86cabc2cbf3fe68c9e7adc33290f7da48 Mon Sep 17 00:00:00 2001 From: Suprabh Shukla Date: Tue, 15 Jun 2021 16:23:37 -0700 Subject: [PATCH] Exempt some callers from min-window restrictions Callers that have power exemption should be allowed to set smaller windows for their alarms. Test: atest FrameworksMockingServicesTests:AlarmManagerServiceTest Bug: 185199076 Change-Id: I5f6515a917da7f87891f79fb637d48a3d7862a1b --- .../server/alarm/AlarmManagerService.java | 13 +++-- .../server/alarm/AlarmManagerServiceTest.java | 57 +++++++++++++++++-- 2 files changed, 59 insertions(+), 11 deletions(-) diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java index fe0c7f718bb05..fb5129f184170 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java @@ -2006,16 +2006,12 @@ public class AlarmManagerService extends SystemService { windowLength = INTERVAL_DAY; } else if ((flags & FLAG_PRIORITIZE) == 0 && windowLength < minAllowedWindow) { // Prioritized alarms are exempt from minimum window limits. - if (CompatChanges.isChangeEnabled( + if (!isExemptFromMinWindowRestrictions(callingUid) && CompatChanges.isChangeEnabled( AlarmManager.ENFORCE_MINIMUM_WINDOW_ON_INEXACT_ALARMS, callingPackage, UserHandle.getUserHandleForUid(callingUid))) { Slog.w(TAG, "Window length " + windowLength + "ms too short; expanding to " + minAllowedWindow + "ms."); windowLength = minAllowedWindow; - } else { - // TODO (b/185199076): Remove temporary log to catch breaking apps. - Slog.wtf(TAG, "Short window " + windowLength + "ms specified by " - + callingPackage); } } maxElapsed = triggerElapsed + windowLength; @@ -2408,6 +2404,13 @@ public class AlarmManagerService extends SystemService { return hasPermission; } + /** + * Returns true if the given uid can set window to be as small as it wants. + */ + boolean isExemptFromMinWindowRestrictions(int uid) { + return isExemptFromExactAlarmPermission(uid); + } + /** * Returns true if the given uid does not require SCHEDULE_EXACT_ALARM to set exact, * allow-while-idle alarms. diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java index 21de7916e23d5..280204dfd4811 100644 --- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java @@ -2309,12 +2309,14 @@ public class AlarmManagerServiceTest { public void minWindowChangeDisabled() { mockChangeEnabled(AlarmManager.ENFORCE_MINIMUM_WINDOW_ON_INEXACT_ALARMS, false); final long minWindow = 73; + final long futurity = 10_000; setDeviceConfigLong(KEY_MIN_WINDOW, minWindow); // 0 is WINDOW_EXACT and < 0 is WINDOW_HEURISTIC. for (int window = 1; window <= minWindow; window++) { final PendingIntent pi = getNewMockPendingIntent(); - setTestAlarm(ELAPSED_REALTIME, 0, window, pi, 0, 0, TEST_CALLING_UID, null); + setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + futurity, window, pi, 0, 0, + TEST_CALLING_UID, null); assertEquals(1, mService.mAlarmStore.size()); final Alarm a = mService.mAlarmStore.remove(unused -> true).get(0); @@ -2322,19 +2324,62 @@ public class AlarmManagerServiceTest { } } + @Test + public void minWindowExempted() { + mockChangeEnabled(AlarmManager.ENFORCE_MINIMUM_WINDOW_ON_INEXACT_ALARMS, true); + final long minWindow = 73; + final long futurity = 10_000; + + setDeviceConfigLong(KEY_MIN_WINDOW, minWindow); + + final int coreUid = 2312; + doReturn(true).when(() -> UserHandle.isCore(coreUid)); + + final int allowlisted = 54239; + when(mDeviceIdleInternal.isAppOnWhitelist(UserHandle.getAppId(allowlisted))).thenReturn( + true); + + for (final int callingUid : new int[]{SYSTEM_UI_UID, coreUid, coreUid}) { + // 0 is WINDOW_EXACT and < 0 is WINDOW_HEURISTIC. + for (int window = 1; window <= minWindow; window++) { + final PendingIntent pi = getNewMockPendingIntent(); + setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + futurity, window, pi, 0, 0, + callingUid, null); + + assertEquals(1, mService.mAlarmStore.size()); + final Alarm a = mService.mAlarmStore.remove(unused -> true).get(0); + assertEquals(window, a.windowLength); + } + } + + // 0 is WINDOW_EXACT and < 0 is WINDOW_HEURISTIC. + for (int window = 1; window <= minWindow; window++) { + final PendingIntent pi = getNewMockPendingIntent(); + setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + futurity, window, pi, 0, 0, + TEST_CALLING_UID, null); + + assertEquals(1, mService.mAlarmStore.size()); + final Alarm a = mService.mAlarmStore.remove(unused -> true).get(0); + assertEquals(minWindow, a.windowLength); + } + } + @Test public void minWindowPriorityAlarm() { mockChangeEnabled(AlarmManager.ENFORCE_MINIMUM_WINDOW_ON_INEXACT_ALARMS, true); final long minWindow = 73; + final long futurity = 10_000; setDeviceConfigLong(KEY_MIN_WINDOW, minWindow); // 0 is WINDOW_EXACT and < 0 is WINDOW_HEURISTIC. for (int window = 1; window <= minWindow; window++) { - setPrioritizedAlarm(ELAPSED_REALTIME, 0, window, new IAlarmListener.Stub() { - @Override - public void doAlarm(IAlarmCompleteListener callback) throws RemoteException { - } - }); + setPrioritizedAlarm(ELAPSED_REALTIME, mNowElapsedTest + futurity, window, + new IAlarmListener.Stub() { + @Override + public void doAlarm(IAlarmCompleteListener callback) + throws RemoteException { + } + }); assertEquals(1, mService.mAlarmStore.size()); final Alarm a = mService.mAlarmStore.remove(unused -> true).get(0); assertEquals(window, a.windowLength);