summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/jobscheduler/service/aconfig/alarm.aconfig10
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java24
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java26
3 files changed, 55 insertions, 5 deletions
diff --git a/apex/jobscheduler/service/aconfig/alarm.aconfig b/apex/jobscheduler/service/aconfig/alarm.aconfig
index a6e980726a9a..9181ef0c532a 100644
--- a/apex/jobscheduler/service/aconfig/alarm.aconfig
+++ b/apex/jobscheduler/service/aconfig/alarm.aconfig
@@ -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
+ }
+}
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 829442aed6ac..f89b13dce307 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -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
@@ -5399,14 +5411,16 @@ 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 (mBroadcastRefCount == 0) {
- setWakelockWorkSource(alarm.workSource, alarm.creatorUid, alarm.statsTag, true);
- mWakeLock.acquire();
- mHandler.obtainMessage(AlarmHandler.REPORT_ALARMS_ACTIVE, 1, 0).sendToTarget();
+ 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);
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 8dc8c14f8948..cb52f1849b5b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java
@@ -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;
@@ -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;
@@ -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.
}
@@ -948,6 +952,28 @@ public final class AlarmManagerServiceTest {
}
@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);
assertEquals(10, mService.mConstants.MIN_FUTURITY);