Merge "Remove listener alarms when remote binder dies"
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 7be3d11..0f2fb92 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -208,6 +208,7 @@
AppWakeupHistory mAppWakeupHistory;
ClockReceiver mClockReceiver;
final DeliveryTracker mDeliveryTracker = new DeliveryTracker();
+ IBinder.DeathRecipient mListenerDeathRecipient;
Intent mTimeTickIntent;
IAlarmListener mTimeTickTrigger;
PendingIntent mDateChangeSender;
@@ -1447,6 +1448,18 @@
public void onStart() {
mInjector.init();
+ mListenerDeathRecipient = new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ }
+
+ @Override
+ public void binderDied(IBinder who) {
+ final IAlarmListener listener = IAlarmListener.Stub.asInterface(who);
+ removeImpl(null, listener);
+ }
+ };
+
synchronized (mLock) {
mHandler = new AlarmHandler();
mConstants = new Constants(mHandler);
@@ -1653,6 +1666,15 @@
return;
}
+ if (directReceiver != null) {
+ try {
+ directReceiver.asBinder().linkToDeath(mListenerDeathRecipient, 0);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Dropping unreachable alarm listener " + listenerTag);
+ return;
+ }
+ }
+
// 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) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
index 556f96a..6a5de84 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
@@ -345,8 +345,8 @@
}
/**
- * Lowers quotas to make testing feasible.
- * Careful while calling as this will replace any existing settings for the calling test.
+ * Lowers quotas to make testing feasible. Careful while calling as this will replace any
+ * existing settings for the calling test.
*/
private void setTestableQuotas() {
final StringBuilder constantsBuilder = new StringBuilder();
@@ -981,6 +981,25 @@
assertEquals(0, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
}
+ @Test
+ public void alarmCountOnListenerBinderDied() {
+ final int numAlarms = 10;
+ final IAlarmListener[] listeners = new IAlarmListener[numAlarms];
+ for (int i = 0; i < numAlarms; i++) {
+ listeners[i] = new IAlarmListener.Stub() {
+ @Override
+ public void doAlarm(IAlarmCompleteListener callback) throws RemoteException {
+ }
+ };
+ setTestAlarmWithListener(ELAPSED_REALTIME_WAKEUP, mNowElapsedTest + i, listeners[i]);
+ }
+ assertEquals(numAlarms, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
+ for (int i = 0; i < numAlarms; i++) {
+ mService.mListenerDeathRecipient.binderDied(listeners[i].asBinder());
+ assertEquals(numAlarms - i - 1, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
+ }
+ }
+
@After
public void tearDown() {
if (mMockingSession != null) {