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;
                 }
             }