Don't leak alarm wakelock when delivery fails
If an app sets an alarm and then cancels the underlying PendingIntent,
delivery will fail in such a way that the OnFinished callback is not
invoked. The Alarm Manager relies on that callback for managing
wakelock lifetime, however; this meant that the wakelock acquisition
would leak, burning down the battery.
We now detect these sorts of delivery failures and manage the
wakelock appropriately.
Bug 25864361
Change-Id: I74af48e81002b29b129c41a76c0a8329c647390d
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index f6af942..960fb4b 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -1363,7 +1363,7 @@
pw.print(" nowRTC="); pw.print(nowRTC);
pw.print("="); pw.print(sdf.format(new Date(nowRTC)));
- pw.print(" nowELAPSED="); TimeUtils.formatDuration(nowELAPSED, pw);
+ pw.print(" nowELAPSED="); pw.print(nowELAPSED);
pw.println();
pw.print(" mLastTimeChangeClockTime="); pw.print(mLastTimeChangeClockTime);
pw.print("="); pw.println(sdf.format(new Date(mLastTimeChangeClockTime)));
@@ -1464,6 +1464,15 @@
pw.print(" Broadcast ref count: "); pw.println(mBroadcastRefCount);
pw.println();
+ if (mInFlight.size() > 0) {
+ pw.println("Outstanding deliveries:");
+ for (int i = 0; i < mInFlight.size(); i++) {
+ pw.print(" #"); pw.print(i); pw.print(": ");
+ pw.println(mInFlight.get(i));
+ }
+ pw.println();
+ }
+
pw.print(" mAllowWhileIdleMinTime=");
TimeUtils.formatDuration(mAllowWhileIdleMinTime, pw);
pw.println();
@@ -2956,6 +2965,11 @@
// is a repeating alarm, so toss it
removeImpl(alarm.operation);
}
+ // No actual delivery was possible, so the delivery tracker's
+ // 'finished' callback won't be invoked. We also don't need
+ // to do any wakelock or stats tracking, so we have nothing
+ // left to do here but go on to the next thing.
+ return;
}
} else {
// Direct listener callback alarm
@@ -2974,6 +2988,11 @@
Slog.i(TAG, "Alarm undeliverable to listener "
+ alarm.listener.asBinder(), e);
}
+ // As in the PendingIntent.CanceledException case, delivery of the
+ // alarm was not possible, so we have no wakelock or timeout or
+ // stats management to do. It threw before we posted the delayed
+ // timeout message, so we're done here.
+ return;
}
}