summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/AlarmManagerService.java50
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java39
2 files changed, 67 insertions, 22 deletions
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 1fa62cec6e30..1220e82485e7 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -760,7 +760,7 @@ class AlarmManagerService extends SystemService {
if (predicate.test(alarm)) {
alarms.remove(i);
if (!reOrdering) {
- decrementAlarmCount(alarm.uid);
+ decrementAlarmCount(alarm.uid, 1);
}
didRemove = true;
if (alarm.alarmClock != null) {
@@ -1764,7 +1764,7 @@ class AlarmManagerService extends SystemService {
+ ", callingPackage: " + callingPackage;
// STOPSHIP (b/128866264): Just to catch breakages. Remove before final release.
Slog.wtf(TAG, errorMsg);
- // TODO b/129995049: Resume throwing once issue is resolved.
+ // TODO b/129995049: Resume throwing after some soak time without errors
// throw new UnsupportedOperationException(errorMsg);
}
setImplLocked(type, triggerAtTime, triggerElapsed, windowLength, maxElapsed,
@@ -3113,17 +3113,21 @@ class AlarmManagerService extends SystemService {
}
}
for (int i = mPendingWhileIdleAlarms.size() - 1; i >= 0; i--) {
- if (mPendingWhileIdleAlarms.get(i).matches(operation, directReceiver)) {
+ final Alarm alarm = mPendingWhileIdleAlarms.get(i);
+ if (alarm.matches(operation, directReceiver)) {
// Don't set didRemove, since this doesn't impact the scheduled alarms.
mPendingWhileIdleAlarms.remove(i);
+ decrementAlarmCount(alarm.uid, 1);
}
}
for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i--) {
final ArrayList<Alarm> alarmsForUid = mPendingBackgroundAlarms.valueAt(i);
for (int j = alarmsForUid.size() - 1; j >= 0; j--) {
- if (alarmsForUid.get(j).matches(operation, directReceiver)) {
+ final Alarm alarm = alarmsForUid.get(j);
+ if (alarm.matches(operation, directReceiver)) {
// Don't set didRemove, since this doesn't impact the scheduled alarms.
alarmsForUid.remove(j);
+ decrementAlarmCount(alarm.uid, 1);
}
}
if (alarmsForUid.size() == 0) {
@@ -3169,6 +3173,7 @@ class AlarmManagerService extends SystemService {
if (a.uid == uid) {
// Don't set didRemove, since this doesn't impact the scheduled alarms.
mPendingWhileIdleAlarms.remove(i);
+ decrementAlarmCount(uid, 1);
}
}
for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i --) {
@@ -3176,6 +3181,7 @@ class AlarmManagerService extends SystemService {
for (int j = alarmsForUid.size() - 1; j >= 0; j--) {
if (alarmsForUid.get(j).uid == uid) {
alarmsForUid.remove(j);
+ decrementAlarmCount(uid, 1);
}
}
if (alarmsForUid.size() == 0) {
@@ -3221,13 +3227,16 @@ class AlarmManagerService extends SystemService {
if (a.matches(packageName)) {
// Don't set didRemove, since this doesn't impact the scheduled alarms.
mPendingWhileIdleAlarms.remove(i);
+ decrementAlarmCount(a.uid, 1);
}
}
for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i --) {
final ArrayList<Alarm> alarmsForUid = mPendingBackgroundAlarms.valueAt(i);
for (int j = alarmsForUid.size() - 1; j >= 0; j--) {
- if (alarmsForUid.get(j).matches(packageName)) {
+ final Alarm alarm = alarmsForUid.get(j);
+ if (alarm.matches(packageName)) {
alarmsForUid.remove(j);
+ decrementAlarmCount(alarm.uid, 1);
}
}
if (alarmsForUid.size() == 0) {
@@ -3272,10 +3281,15 @@ class AlarmManagerService extends SystemService {
if (a.uid == uid) {
// Don't set didRemove, since this doesn't impact the scheduled alarms.
mPendingWhileIdleAlarms.remove(i);
+ decrementAlarmCount(uid, 1);
}
}
for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i--) {
if (mPendingBackgroundAlarms.keyAt(i) == uid) {
+ final ArrayList<Alarm> toRemove = mPendingBackgroundAlarms.valueAt(i);
+ if (toRemove != null) {
+ decrementAlarmCount(uid, toRemove.size());
+ }
mPendingBackgroundAlarms.removeAt(i);
}
}
@@ -3308,11 +3322,18 @@ class AlarmManagerService extends SystemService {
if (UserHandle.getUserId(mPendingWhileIdleAlarms.get(i).creatorUid)
== userHandle) {
// Don't set didRemove, since this doesn't impact the scheduled alarms.
- mPendingWhileIdleAlarms.remove(i);
+ final Alarm removed = mPendingWhileIdleAlarms.remove(i);
+ decrementAlarmCount(removed.uid, 1);
}
}
for (int i = mPendingBackgroundAlarms.size() - 1; i >= 0; i--) {
if (UserHandle.getUserId(mPendingBackgroundAlarms.keyAt(i)) == userHandle) {
+ final ArrayList<Alarm> toRemove = mPendingBackgroundAlarms.valueAt(i);
+ if (toRemove != null) {
+ for (int j = 0; j < toRemove.size(); j++) {
+ decrementAlarmCount(toRemove.get(j).uid, 1);
+ }
+ }
mPendingBackgroundAlarms.removeAt(i);
}
}
@@ -3844,7 +3865,7 @@ class AlarmManagerService extends SystemService {
Slog.w(TAG, "Failure sending alarm.", e);
}
Trace.traceEnd(Trace.TRACE_TAG_POWER);
- decrementAlarmCount(alarm.uid);
+ decrementAlarmCount(alarm.uid, 1);
}
}
@@ -4198,7 +4219,7 @@ class AlarmManagerService extends SystemService {
removeImpl(alarm.operation, null);
}
}
- decrementAlarmCount(alarm.uid);
+ decrementAlarmCount(alarm.uid, 1);
}
break;
}
@@ -4828,16 +4849,21 @@ class AlarmManagerService extends SystemService {
}
}
- private void decrementAlarmCount(int uid) {
+ private void decrementAlarmCount(int uid, int decrement) {
+ int oldCount = 0;
final int uidIndex = mAlarmsPerUid.indexOfKey(uid);
if (uidIndex >= 0) {
- final int newCount = mAlarmsPerUid.valueAt(uidIndex) - 1;
- if (newCount > 0) {
- mAlarmsPerUid.setValueAt(uidIndex, newCount);
+ oldCount = mAlarmsPerUid.valueAt(uidIndex);
+ if (oldCount > decrement) {
+ mAlarmsPerUid.setValueAt(uidIndex, oldCount - decrement);
} else {
mAlarmsPerUid.removeAt(uidIndex);
}
}
+ if (oldCount < decrement) {
+ Slog.wtf(TAG, "Attempt to decrement existing alarm count " + oldCount + " by "
+ + decrement + " for uid " + uid);
+ }
}
private class ShellCmd extends ShellCommand {
diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
index c0a11b27c65c..6517303842ed 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
@@ -263,6 +263,9 @@ public class AlarmManagerServiceTest {
mService.onStart();
spyOn(mService.mHandler);
+ // Stubbing the handler. Test should simulate any handling of messages synchronously.
+ doReturn(true).when(mService.mHandler).sendMessageAtTime(any(Message.class), anyLong());
+
assertEquals(mService.mSystemUiUid, SYSTEM_UI_UID);
assertEquals(mService.mClockReceiver, mClockReceiver);
assertEquals(mService.mWakeLock, mWakeLock);
@@ -617,11 +620,9 @@ public class AlarmManagerServiceTest {
testQuotasNoDeferral(STANDBY_BUCKET_RARE);
}
- private void sendAndHandleBucketChanged(int bucket) {
+ private void assertAndHandleBucketChanged(int bucket) {
when(mUsageStatsManagerInternal.getAppStandbyBucket(eq(TEST_CALLING_PACKAGE), anyInt(),
anyLong())).thenReturn(bucket);
- // Stubbing the handler call to simulate it synchronously here.
- doReturn(true).when(mService.mHandler).sendMessage(any(Message.class));
mAppStandbyListener.onAppIdleStateChanged(TEST_CALLING_PACKAGE,
UserHandle.getUserId(TEST_CALLING_UID), false, bucket, 0);
final ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
@@ -652,7 +653,7 @@ public class AlarmManagerServiceTest {
// The next upcoming alarm in queue should also be set as expected.
assertEquals(firstTrigger + workingQuota - 1, mTestTimer.getElapsed());
// Downgrading the bucket now
- sendAndHandleBucketChanged(STANDBY_BUCKET_RARE);
+ assertAndHandleBucketChanged(STANDBY_BUCKET_RARE);
final int rareQuota = mService.getQuotaForBucketLocked(STANDBY_BUCKET_RARE);
// The last alarm should now be deferred.
final long expectedNextTrigger = (firstTrigger + workingQuota - 1 - rareQuota)
@@ -680,15 +681,13 @@ public class AlarmManagerServiceTest {
assertEquals(deferredTrigger, mTestTimer.getElapsed());
// Upgrading the bucket now
- sendAndHandleBucketChanged(STANDBY_BUCKET_ACTIVE);
+ assertAndHandleBucketChanged(STANDBY_BUCKET_ACTIVE);
// The last alarm should now be rescheduled to go as per original expectations
final long originalTrigger = firstTrigger + frequentQuota;
assertEquals("Incorrect next alarm trigger", originalTrigger, mTestTimer.getElapsed());
}
- private void sendAndHandleParoleChanged(boolean parole) {
- // Stubbing the handler call to simulate it synchronously here.
- doReturn(true).when(mService.mHandler).sendMessage(any(Message.class));
+ private void assertAndHandleParoleChanged(boolean parole) {
mAppStandbyListener.onParoleStateChanged(parole);
final ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
verify(mService.mHandler, atLeastOnce()).sendMessage(messageCaptor.capture());
@@ -719,7 +718,7 @@ public class AlarmManagerServiceTest {
// Any subsequent alarms in queue should all be deferred
assertEquals(firstTrigger + mAppStandbyWindow + 1, mTestTimer.getElapsed());
// Paroling now
- sendAndHandleParoleChanged(true);
+ assertAndHandleParoleChanged(true);
// Subsequent alarms should now go off as per original expectations.
for (int i = 0; i < 5; i++) {
@@ -728,7 +727,7 @@ public class AlarmManagerServiceTest {
mTestTimer.expire();
}
// Come out of parole
- sendAndHandleParoleChanged(false);
+ assertAndHandleParoleChanged(false);
// Subsequent alarms should again get deferred
final long expectedNextTrigger = (firstTrigger + 5) + 1 + mAppStandbyWindow;
@@ -938,6 +937,26 @@ public class AlarmManagerServiceTest {
}
@Test
+ public void alarmCountOnRemoveFromPendingWhileIdle() {
+ mService.mPendingIdleUntil = mock(AlarmManagerService.Alarm.class);
+ final int numAlarms = 15;
+ final PendingIntent[] pis = new PendingIntent[numAlarms];
+ for (int i = 0; i < numAlarms; i++) {
+ pis[i] = getNewMockPendingIntent();
+ setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 5, pis[i]);
+ }
+ assertEquals(numAlarms, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
+ assertEquals(numAlarms, mService.mPendingWhileIdleAlarms.size());
+ final int toRemove = 8;
+ for (int i = 0; i < toRemove; i++) {
+ mService.removeLocked(pis[i], null);
+ assertEquals(numAlarms - i - 1, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0));
+ }
+ mService.removeLocked(TEST_CALLING_UID);
+ assertEquals(0, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0));
+ }
+
+ @Test
public void alarmCountOnAlarmRemoved() {
final int numAlarms = 10;
final PendingIntent[] pis = new PendingIntent[numAlarms];