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 61cca3234f564..3772960e8ac46 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(); } } @@ -3505,15 +3513,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]); + } + } }