Loading apex/jobscheduler/service/aconfig/alarm.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -7,3 +7,13 @@ flag { description: "Persist list of users with alarms scheduled and wakeup stopped users before alarms are due" bug: "314907186" } flag { name: "acquire_wakelock_before_send" namespace: "backstage_power" description: "Acquire the userspace alarm wakelock before sending the alarm" bug: "391413964" metadata { purpose: PURPOSE_BUGFIX } } apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +19 −5 Original line number Diff line number Diff line Loading @@ -5334,6 +5334,18 @@ public class AlarmManagerService extends SystemService { public void deliverLocked(Alarm alarm, long nowELAPSED) { final long workSourceToken = ThreadLocalWorkSource.setUid( getAlarmAttributionUid(alarm)); if (Flags.acquireWakelockBeforeSend()) { // Acquire the wakelock before starting the app. This needs to be done to avoid // random stalls in the receiving app in case a suspend attempt is already in // progress. See b/391413964 for an incident where this was found to happen. if (mBroadcastRefCount == 0) { setWakelockWorkSource(alarm.workSource, alarm.creatorUid, alarm.statsTag, true); mWakeLock.acquire(); mHandler.obtainMessage(AlarmHandler.REPORT_ALARMS_ACTIVE, 1, 0).sendToTarget(); } } try { if (alarm.operation != null) { // PendingIntent alarm Loading Loading @@ -5399,15 +5411,17 @@ public class AlarmManagerService extends SystemService { ThreadLocalWorkSource.restore(workSourceToken); } // The alarm is now in flight; now arrange wakelock and stats tracking if (DEBUG_WAKELOCK) { Slog.d(TAG, "mBroadcastRefCount -> " + (mBroadcastRefCount + 1)); } if (!Flags.acquireWakelockBeforeSend()) { // The alarm is now in flight; now arrange wakelock and stats tracking if (mBroadcastRefCount == 0) { setWakelockWorkSource(alarm.workSource, alarm.creatorUid, alarm.statsTag, true); mWakeLock.acquire(); mHandler.obtainMessage(AlarmHandler.REPORT_ALARMS_ACTIVE, 1, 0).sendToTarget(); } } final InFlight inflight = new InFlight(AlarmManagerService.this, alarm, nowELAPSED); mInFlight.add(inflight); mBroadcastRefCount++; Loading services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java +26 −0 Original line number Diff line number Diff line Loading @@ -151,6 +151,7 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; import android.platform.test.flag.junit.SetFlagsRule; import android.platform.test.flag.util.FlagSetException; Loading Loading @@ -192,7 +193,9 @@ import org.junit.runner.RunWith; import org.mockito.Answers; import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatchers; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.quality.Strictness; import org.mockito.stubbing.Answer; Loading Loading @@ -435,6 +438,7 @@ public final class AlarmManagerServiceTest { private void disableFlagsNotSetByAnnotation() { try { mSetFlagsRule.disableFlags(Flags.FLAG_START_USER_BEFORE_SCHEDULED_ALARMS); mSetFlagsRule.disableFlags(Flags.FLAG_ACQUIRE_WAKELOCK_BEFORE_SEND); } catch (FlagSetException fse) { // Expected if the test about to be run requires this enabled. } Loading Loading @@ -947,6 +951,28 @@ public final class AlarmManagerServiceTest { assertEquals(expectedTriggerTime, mTestTimer.getElapsed()); } @Test @EnableFlags(Flags.FLAG_ACQUIRE_WAKELOCK_BEFORE_SEND) public void testWakelockOrdering() throws Exception { final long triggerTime = mNowElapsedTest + 5000; final PendingIntent alarmPi = getNewMockPendingIntent(); setTestAlarm(ELAPSED_REALTIME_WAKEUP, triggerTime, alarmPi); mNowElapsedTest = mTestTimer.getElapsed(); mTestTimer.expire(); final InOrder inOrder = Mockito.inOrder(alarmPi, mWakeLock); inOrder.verify(mWakeLock).acquire(); final ArgumentCaptor<PendingIntent.OnFinished> onFinishedCaptor = ArgumentCaptor.forClass(PendingIntent.OnFinished.class); inOrder.verify(alarmPi).send(eq(mMockContext), eq(0), any(Intent.class), onFinishedCaptor.capture(), any(Handler.class), isNull(), any()); onFinishedCaptor.getValue().onSendFinished(alarmPi, null, 0, null, null); inOrder.verify(mWakeLock).release(); } @Test public void testMinFuturityCoreUid() { setDeviceConfigLong(KEY_MIN_FUTURITY, 10L); Loading Loading
apex/jobscheduler/service/aconfig/alarm.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -7,3 +7,13 @@ flag { description: "Persist list of users with alarms scheduled and wakeup stopped users before alarms are due" bug: "314907186" } flag { name: "acquire_wakelock_before_send" namespace: "backstage_power" description: "Acquire the userspace alarm wakelock before sending the alarm" bug: "391413964" metadata { purpose: PURPOSE_BUGFIX } }
apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +19 −5 Original line number Diff line number Diff line Loading @@ -5334,6 +5334,18 @@ public class AlarmManagerService extends SystemService { public void deliverLocked(Alarm alarm, long nowELAPSED) { final long workSourceToken = ThreadLocalWorkSource.setUid( getAlarmAttributionUid(alarm)); if (Flags.acquireWakelockBeforeSend()) { // Acquire the wakelock before starting the app. This needs to be done to avoid // random stalls in the receiving app in case a suspend attempt is already in // progress. See b/391413964 for an incident where this was found to happen. if (mBroadcastRefCount == 0) { setWakelockWorkSource(alarm.workSource, alarm.creatorUid, alarm.statsTag, true); mWakeLock.acquire(); mHandler.obtainMessage(AlarmHandler.REPORT_ALARMS_ACTIVE, 1, 0).sendToTarget(); } } try { if (alarm.operation != null) { // PendingIntent alarm Loading Loading @@ -5399,15 +5411,17 @@ public class AlarmManagerService extends SystemService { ThreadLocalWorkSource.restore(workSourceToken); } // The alarm is now in flight; now arrange wakelock and stats tracking if (DEBUG_WAKELOCK) { Slog.d(TAG, "mBroadcastRefCount -> " + (mBroadcastRefCount + 1)); } if (!Flags.acquireWakelockBeforeSend()) { // The alarm is now in flight; now arrange wakelock and stats tracking if (mBroadcastRefCount == 0) { setWakelockWorkSource(alarm.workSource, alarm.creatorUid, alarm.statsTag, true); mWakeLock.acquire(); mHandler.obtainMessage(AlarmHandler.REPORT_ALARMS_ACTIVE, 1, 0).sendToTarget(); } } final InFlight inflight = new InFlight(AlarmManagerService.this, alarm, nowELAPSED); mInFlight.add(inflight); mBroadcastRefCount++; Loading
services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java +26 −0 Original line number Diff line number Diff line Loading @@ -151,6 +151,7 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; import android.platform.test.annotations.DisableFlags; import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; import android.platform.test.flag.junit.SetFlagsRule; import android.platform.test.flag.util.FlagSetException; Loading Loading @@ -192,7 +193,9 @@ import org.junit.runner.RunWith; import org.mockito.Answers; import org.mockito.ArgumentCaptor; import org.mockito.ArgumentMatchers; import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.quality.Strictness; import org.mockito.stubbing.Answer; Loading Loading @@ -435,6 +438,7 @@ public final class AlarmManagerServiceTest { private void disableFlagsNotSetByAnnotation() { try { mSetFlagsRule.disableFlags(Flags.FLAG_START_USER_BEFORE_SCHEDULED_ALARMS); mSetFlagsRule.disableFlags(Flags.FLAG_ACQUIRE_WAKELOCK_BEFORE_SEND); } catch (FlagSetException fse) { // Expected if the test about to be run requires this enabled. } Loading Loading @@ -947,6 +951,28 @@ public final class AlarmManagerServiceTest { assertEquals(expectedTriggerTime, mTestTimer.getElapsed()); } @Test @EnableFlags(Flags.FLAG_ACQUIRE_WAKELOCK_BEFORE_SEND) public void testWakelockOrdering() throws Exception { final long triggerTime = mNowElapsedTest + 5000; final PendingIntent alarmPi = getNewMockPendingIntent(); setTestAlarm(ELAPSED_REALTIME_WAKEUP, triggerTime, alarmPi); mNowElapsedTest = mTestTimer.getElapsed(); mTestTimer.expire(); final InOrder inOrder = Mockito.inOrder(alarmPi, mWakeLock); inOrder.verify(mWakeLock).acquire(); final ArgumentCaptor<PendingIntent.OnFinished> onFinishedCaptor = ArgumentCaptor.forClass(PendingIntent.OnFinished.class); inOrder.verify(alarmPi).send(eq(mMockContext), eq(0), any(Intent.class), onFinishedCaptor.capture(), any(Handler.class), isNull(), any()); onFinishedCaptor.getValue().onSendFinished(alarmPi, null, 0, null, null); inOrder.verify(mWakeLock).release(); } @Test public void testMinFuturityCoreUid() { setDeviceConfigLong(KEY_MIN_FUTURITY, 10L); Loading