From 61011ab3bea1c49acd4d61620ccdf3afe9583067 Mon Sep 17 00:00:00 2001 From: Suprabh Shukla Date: Tue, 21 Mar 2023 15:13:27 -0700 Subject: [PATCH] Add more data to removal history in alarm dump Expanding the history to include more information about the alarm which was removed. Specifically, the calculations for when the alarm is due is extremely useful in debugging issues by looking at the dump. Creating a mechanism to snapshot an alarm object for logging. More fields can be added to this as needed. Reversing the order of printing the removal history so it prints the most recent removal first. Test: Manually inspect the output of `dumpsys alarm` Test: atest FrameworksMockingServicesTests:AlarmTest Bug: 193063877 Change-Id: Id1baaa5c985a201ccd3d5f325c0781edec783fba --- .../java/com/android/server/alarm/Alarm.java | 31 ++++++++++++++++++- .../server/alarm/AlarmManagerService.java | 25 ++++++++++----- .../com/android/server/alarm/AlarmTest.java | 22 +++++++++++++ 3 files changed, 69 insertions(+), 9 deletions(-) diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java b/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java index 69fe85e37b4bf..430a1e25e123b 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/Alarm.java @@ -35,6 +35,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; import java.text.SimpleDateFormat; +import java.util.Arrays; import java.util.Date; /** @@ -264,7 +265,7 @@ class Alarm { return sb.toString(); } - private static String policyIndexToString(int index) { + static String policyIndexToString(int index) { switch (index) { case REQUESTER_POLICY_INDEX: return "requester"; @@ -400,4 +401,32 @@ class Alarm { proto.end(token); } + + /** + * Stores a snapshot of an alarm at any given time to be used for logging and diagnostics. + * This should intentionally avoid holding pointers to objects like {@link Alarm#operation}. + */ + static class Snapshot { + final int mType; + final String mTag; + final long[] mPolicyWhenElapsed; + + Snapshot(Alarm a) { + mType = a.type; + mTag = a.statsTag; + mPolicyWhenElapsed = Arrays.copyOf(a.mPolicyWhenElapsed, NUM_POLICIES); + } + + void dump(IndentingPrintWriter pw, long nowElapsed) { + pw.print("type", typeToString(mType)); + pw.print("tag", mTag); + pw.println(); + pw.print("policyWhenElapsed:"); + for (int i = 0; i < NUM_POLICIES; i++) { + pw.print(" " + policyIndexToString(i) + "="); + TimeUtils.formatDuration(mPolicyWhenElapsed[i], nowElapsed, pw); + } + pw.println(); + } + } } 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 af995367a1e44..4e795ee190062 100644 --- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java +++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java @@ -618,13 +618,13 @@ public class AlarmManagerService extends SystemService { static final int REMOVE_REASON_LISTENER_BINDER_DIED = 5; static final int REMOVE_REASON_LISTENER_CACHED = 6; - final String mTag; + final Alarm.Snapshot mAlarmSnapshot; final long mWhenRemovedElapsed; final long mWhenRemovedRtc; final int mRemoveReason; RemovedAlarm(Alarm a, int removeReason, long nowRtc, long nowElapsed) { - mTag = a.statsTag; + mAlarmSnapshot = new Alarm.Snapshot(a); mRemoveReason = removeReason; mWhenRemovedRtc = nowRtc; mWhenRemovedElapsed = nowElapsed; @@ -656,13 +656,21 @@ public class AlarmManagerService extends SystemService { } void dump(IndentingPrintWriter pw, long nowElapsed, SimpleDateFormat sdf) { - pw.print("[tag", mTag); - pw.print("reason", removeReasonToString(mRemoveReason)); + pw.increaseIndent(); + + pw.print("Reason", removeReasonToString(mRemoveReason)); pw.print("elapsed="); TimeUtils.formatDuration(mWhenRemovedElapsed, nowElapsed, pw); pw.print(" rtc="); pw.print(sdf.format(new Date(mWhenRemovedRtc))); - pw.println("]"); + pw.println(); + + pw.println("Snapshot:"); + pw.increaseIndent(); + mAlarmSnapshot.dump(pw, nowElapsed); + pw.decreaseIndent(); + + pw.decreaseIndent(); } } @@ -3503,15 +3511,16 @@ public class AlarmManagerService extends SystemService { } if (mRemovalHistory.size() > 0) { - pw.println("Removal history: "); + pw.println("Removal history:"); pw.increaseIndent(); for (int i = 0; i < mRemovalHistory.size(); i++) { UserHandle.formatUid(pw, mRemovalHistory.keyAt(i)); pw.println(":"); pw.increaseIndent(); final RemovedAlarm[] historyForUid = mRemovalHistory.valueAt(i).toArray(); - for (final RemovedAlarm removedAlarm : historyForUid) { - removedAlarm.dump(pw, nowELAPSED, sdf); + for (int index = historyForUid.length - 1; index >= 0; index--) { + pw.print("#" + (historyForUid.length - index) + ": "); + historyForUid[index].dump(pw, nowELAPSED, sdf); } pw.decreaseIndent(); } diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java index a129f39106cd2..246b0f04171ec 100644 --- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmTest.java @@ -210,4 +210,26 @@ public class AlarmTest { createDefaultAlarm(anything, anything, FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED))); assertTrue("Alarm clock not exempt", isExemptFromTare(createAlarmClock(anything))); } + + @Test + public void snapshotImmutable() { + final Alarm a = createDefaultAlarm(0, 0, 0); + + final Random random = new Random(234); + final long[] policyElapsed = new long[NUM_POLICIES]; + for (int i = 0; i < NUM_POLICIES; i++) { + a.setPolicyElapsed(i, policyElapsed[i] = random.nextInt(1 << 10)); + } + + final Alarm.Snapshot snapshot = new Alarm.Snapshot(a); + + for (int i = 0; i < NUM_POLICIES; i++) { + assertEquals(policyElapsed[i], snapshot.mPolicyWhenElapsed[i]); + } + + for (int i = 0; i < NUM_POLICIES; i++) { + a.setPolicyElapsed(i, policyElapsed[i] + 5 + i); + assertEquals(policyElapsed[i], snapshot.mPolicyWhenElapsed[i]); + } + } }