Loading services/core/java/com/android/server/AlarmManagerService.java +25 −0 Original line number Diff line number Diff line Loading @@ -1697,6 +1697,8 @@ class AlarmManagerService extends SystemService { return; } type = fixTypeIfAuto(type); // Sanity check the window length. This will catch people mistakenly // trying to pass an end-of-window timestamp rather than a duration. if (windowLength > AlarmManager.INTERVAL_HALF_DAY) { Loading Loading @@ -1811,6 +1813,21 @@ class AlarmManagerService extends SystemService { return mConstants.APP_STANDBY_QUOTAS[index]; } /** * In case of cars, we need to avoid scheduling wakeup alarms, since we don't want the system * to wake up from suspend arbitrarily to perform app work. */ private int fixTypeIfAuto(int type) { if (mInjector.isAutomotive()) { if (type == AlarmManager.ELAPSED_REALTIME_WAKEUP) { type = AlarmManager.ELAPSED_REALTIME; } else if (type == AlarmManager.RTC_WAKEUP) { type = AlarmManager.RTC; } } return type; } /** * Return the minimum time that should elapse before an app in the specified bucket * can receive alarms again Loading Loading @@ -2214,6 +2231,7 @@ class AlarmManagerService extends SystemService { pw.print(" mLastTickSet="); pw.println(sdf.format(new Date(mLastTickSet))); pw.print(" mLastTickAdded="); pw.println(sdf.format(new Date(mLastTickAdded))); pw.print(" mLastTickRemoved="); pw.println(sdf.format(new Date(mLastTickRemoved))); pw.print(" mIsAutomotive="); pw.println(mInjector.isAutomotive()); if (RECORD_ALARMS_IN_HISTORY) { pw.println(); Loading Loading @@ -3838,9 +3856,12 @@ class AlarmManagerService extends SystemService { static class Injector { private long mNativeData; private Context mContext; private final boolean mIsAutomotive; Injector(Context context) { mContext = context; mIsAutomotive = context.getPackageManager().hasSystemFeature( PackageManager.FEATURE_AUTOMOTIVE); } void init() { Loading Loading @@ -3929,6 +3950,10 @@ class AlarmManagerService extends SystemService { ClockReceiver getClockReceiver(AlarmManagerService service) { return service.new ClockReceiver(); } boolean isAutomotive() { return mIsAutomotive; } } private class AlarmThread extends Thread Loading services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java +51 −2 Original line number Diff line number Diff line Loading @@ -66,6 +66,7 @@ import android.app.usage.UsageStatsManagerInternal; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Handler; import android.os.Looper; import android.os.Message; Loading Loading @@ -118,6 +119,8 @@ public class AlarmManagerServiceTest { private AlarmManagerService.ClockReceiver mClockReceiver; @Mock private PowerManager.WakeLock mWakeLock; @Mock private PackageManager mMockPackageManager; private MockitoSession mMockingSession; private Injector mInjector; Loading @@ -128,15 +131,21 @@ public class AlarmManagerServiceTest { static class TestTimer { private long mElapsed; boolean mExpired; int mType; synchronized long getElapsed() { return mElapsed; } synchronized void set(long millisElapsed) { synchronized void set(int type, long millisElapsed) { mType = type; mElapsed = millisElapsed; } synchronized int getType() { return mType; } synchronized void expire() throws InterruptedException { mExpired = true; notifyAll(); Loading @@ -146,6 +155,8 @@ public class AlarmManagerServiceTest { } public class Injector extends AlarmManagerService.Injector { boolean mIsAutomotiveOverride; Injector(Context context) { super(context); } Loading Loading @@ -179,7 +190,7 @@ public class AlarmManagerServiceTest { @Override void setAlarm(int type, long millis) { mTestTimer.set(millis); mTestTimer.set(type, millis); } @Override Loading Loading @@ -211,6 +222,11 @@ public class AlarmManagerServiceTest { PowerManager.WakeLock getAlarmWakeLock() { return mWakeLock; } @Override boolean isAutomotive() { return mIsAutomotiveOverride; } } @Before Loading @@ -237,6 +253,8 @@ public class AlarmManagerServiceTest { when(mMockContext.getContentResolver()).thenReturn(mMockResolver); doReturn("min_futurity=0,min_interval=0").when(() -> Settings.Global.getString(mMockResolver, Settings.Global.ALARM_MANAGER_CONSTANTS)); when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager); mInjector = new Injector(mMockContext); mService = new AlarmManagerService(mMockContext, mInjector); spyOn(mService); Loading Loading @@ -932,6 +950,37 @@ public class AlarmManagerServiceTest { } } @Test public void alarmTypes() throws Exception { final int[] typesToSet = {ELAPSED_REALTIME_WAKEUP, ELAPSED_REALTIME, RTC_WAKEUP, RTC}; final int[] typesExpected = {ELAPSED_REALTIME_WAKEUP, ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, ELAPSED_REALTIME}; assertAlarmTypeConversion(typesToSet, typesExpected); } /** * Confirm that wakeup alarms are never set for automotive. */ @Test public void alarmTypesForAuto() throws Exception { mInjector.mIsAutomotiveOverride = true; final int[] typesToSet = {ELAPSED_REALTIME_WAKEUP, ELAPSED_REALTIME, RTC_WAKEUP, RTC}; final int[] typesExpected = {ELAPSED_REALTIME, ELAPSED_REALTIME, ELAPSED_REALTIME, ELAPSED_REALTIME}; assertAlarmTypeConversion(typesToSet, typesExpected); } private void assertAlarmTypeConversion(int[] typesToSet, int[] typesExpected) throws Exception { for (int i = 0; i < typesToSet.length; i++) { setTestAlarm(typesToSet[i], 1234, getNewMockPendingIntent()); final int typeSet = mTestTimer.getType(); assertEquals("Alarm of type " + typesToSet[i] + " was set to type " + typeSet, typesExpected[i], typeSet); mNowElapsedTest = mTestTimer.getElapsed(); mTestTimer.expire(); } } @Test public void alarmCountOnInvalidSet() { setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + 12345, null); Loading Loading
services/core/java/com/android/server/AlarmManagerService.java +25 −0 Original line number Diff line number Diff line Loading @@ -1697,6 +1697,8 @@ class AlarmManagerService extends SystemService { return; } type = fixTypeIfAuto(type); // Sanity check the window length. This will catch people mistakenly // trying to pass an end-of-window timestamp rather than a duration. if (windowLength > AlarmManager.INTERVAL_HALF_DAY) { Loading Loading @@ -1811,6 +1813,21 @@ class AlarmManagerService extends SystemService { return mConstants.APP_STANDBY_QUOTAS[index]; } /** * In case of cars, we need to avoid scheduling wakeup alarms, since we don't want the system * to wake up from suspend arbitrarily to perform app work. */ private int fixTypeIfAuto(int type) { if (mInjector.isAutomotive()) { if (type == AlarmManager.ELAPSED_REALTIME_WAKEUP) { type = AlarmManager.ELAPSED_REALTIME; } else if (type == AlarmManager.RTC_WAKEUP) { type = AlarmManager.RTC; } } return type; } /** * Return the minimum time that should elapse before an app in the specified bucket * can receive alarms again Loading Loading @@ -2214,6 +2231,7 @@ class AlarmManagerService extends SystemService { pw.print(" mLastTickSet="); pw.println(sdf.format(new Date(mLastTickSet))); pw.print(" mLastTickAdded="); pw.println(sdf.format(new Date(mLastTickAdded))); pw.print(" mLastTickRemoved="); pw.println(sdf.format(new Date(mLastTickRemoved))); pw.print(" mIsAutomotive="); pw.println(mInjector.isAutomotive()); if (RECORD_ALARMS_IN_HISTORY) { pw.println(); Loading Loading @@ -3838,9 +3856,12 @@ class AlarmManagerService extends SystemService { static class Injector { private long mNativeData; private Context mContext; private final boolean mIsAutomotive; Injector(Context context) { mContext = context; mIsAutomotive = context.getPackageManager().hasSystemFeature( PackageManager.FEATURE_AUTOMOTIVE); } void init() { Loading Loading @@ -3929,6 +3950,10 @@ class AlarmManagerService extends SystemService { ClockReceiver getClockReceiver(AlarmManagerService service) { return service.new ClockReceiver(); } boolean isAutomotive() { return mIsAutomotive; } } private class AlarmThread extends Thread Loading
services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java +51 −2 Original line number Diff line number Diff line Loading @@ -66,6 +66,7 @@ import android.app.usage.UsageStatsManagerInternal; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Handler; import android.os.Looper; import android.os.Message; Loading Loading @@ -118,6 +119,8 @@ public class AlarmManagerServiceTest { private AlarmManagerService.ClockReceiver mClockReceiver; @Mock private PowerManager.WakeLock mWakeLock; @Mock private PackageManager mMockPackageManager; private MockitoSession mMockingSession; private Injector mInjector; Loading @@ -128,15 +131,21 @@ public class AlarmManagerServiceTest { static class TestTimer { private long mElapsed; boolean mExpired; int mType; synchronized long getElapsed() { return mElapsed; } synchronized void set(long millisElapsed) { synchronized void set(int type, long millisElapsed) { mType = type; mElapsed = millisElapsed; } synchronized int getType() { return mType; } synchronized void expire() throws InterruptedException { mExpired = true; notifyAll(); Loading @@ -146,6 +155,8 @@ public class AlarmManagerServiceTest { } public class Injector extends AlarmManagerService.Injector { boolean mIsAutomotiveOverride; Injector(Context context) { super(context); } Loading Loading @@ -179,7 +190,7 @@ public class AlarmManagerServiceTest { @Override void setAlarm(int type, long millis) { mTestTimer.set(millis); mTestTimer.set(type, millis); } @Override Loading Loading @@ -211,6 +222,11 @@ public class AlarmManagerServiceTest { PowerManager.WakeLock getAlarmWakeLock() { return mWakeLock; } @Override boolean isAutomotive() { return mIsAutomotiveOverride; } } @Before Loading @@ -237,6 +253,8 @@ public class AlarmManagerServiceTest { when(mMockContext.getContentResolver()).thenReturn(mMockResolver); doReturn("min_futurity=0,min_interval=0").when(() -> Settings.Global.getString(mMockResolver, Settings.Global.ALARM_MANAGER_CONSTANTS)); when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager); mInjector = new Injector(mMockContext); mService = new AlarmManagerService(mMockContext, mInjector); spyOn(mService); Loading Loading @@ -932,6 +950,37 @@ public class AlarmManagerServiceTest { } } @Test public void alarmTypes() throws Exception { final int[] typesToSet = {ELAPSED_REALTIME_WAKEUP, ELAPSED_REALTIME, RTC_WAKEUP, RTC}; final int[] typesExpected = {ELAPSED_REALTIME_WAKEUP, ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, ELAPSED_REALTIME}; assertAlarmTypeConversion(typesToSet, typesExpected); } /** * Confirm that wakeup alarms are never set for automotive. */ @Test public void alarmTypesForAuto() throws Exception { mInjector.mIsAutomotiveOverride = true; final int[] typesToSet = {ELAPSED_REALTIME_WAKEUP, ELAPSED_REALTIME, RTC_WAKEUP, RTC}; final int[] typesExpected = {ELAPSED_REALTIME, ELAPSED_REALTIME, ELAPSED_REALTIME, ELAPSED_REALTIME}; assertAlarmTypeConversion(typesToSet, typesExpected); } private void assertAlarmTypeConversion(int[] typesToSet, int[] typesExpected) throws Exception { for (int i = 0; i < typesToSet.length; i++) { setTestAlarm(typesToSet[i], 1234, getNewMockPendingIntent()); final int typeSet = mTestTimer.getType(); assertEquals("Alarm of type " + typesToSet[i] + " was set to type " + typeSet, typesExpected[i], typeSet); mNowElapsedTest = mTestTimer.getElapsed(); mTestTimer.expire(); } } @Test public void alarmCountOnInvalidSet() { setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + 12345, null); Loading