From 5dde7fffb190e10975c323930067f3fc3fdf0d09 Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Tue, 28 Feb 2023 17:23:05 -0800 Subject: [PATCH] Include more broadcasts related data in the activity service dump. Bug: 268639079 Bug: 267503178 Test: manual Change-Id: I80bdfea987099fa86e01bb457295e0271a8065e9 --- .../server/activitymanagerservice.proto | 1 + .../android/server/am/BroadcastHistory.java | 41 ++++++++++++++-- .../server/am/BroadcastProcessQueue.java | 48 ++++++++++++++++++- .../server/am/BroadcastQueueModernImpl.java | 17 ++++--- .../android/server/am/BroadcastRecord.java | 17 +++++-- .../am/BroadcastQueueModernImplTest.java | 2 +- 6 files changed, 110 insertions(+), 16 deletions(-) diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto index ab7b0ab8d1fc7..483debdab57fd 100644 --- a/core/proto/android/server/activitymanagerservice.proto +++ b/core/proto/android/server/activitymanagerservice.proto @@ -142,6 +142,7 @@ message BroadcastQueueProto { optional int64 finish_clock_time_ms = 4; } repeated BroadcastSummary historical_broadcasts_summary = 6; + repeated BroadcastRecordProto pending_broadcasts = 7; } message MemInfoDumpProto { diff --git a/services/core/java/com/android/server/am/BroadcastHistory.java b/services/core/java/com/android/server/am/BroadcastHistory.java index 6ac0e8bee58b8..34658ca41356c 100644 --- a/services/core/java/com/android/server/am/BroadcastHistory.java +++ b/services/core/java/com/android/server/am/BroadcastHistory.java @@ -17,6 +17,7 @@ package com.android.server.am; import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Intent; import android.os.Bundle; import android.util.TimeUtils; @@ -26,6 +27,7 @@ import dalvik.annotation.optimization.NeverCompile; import java.io.PrintWriter; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Date; /** @@ -47,6 +49,11 @@ public class BroadcastHistory { mSummaryHistoryFinishTime = new long[MAX_BROADCAST_SUMMARY_HISTORY]; } + /** + * List of broadcasts which are being delivered or yet to be delivered. + */ + private final ArrayList mPendingBroadcasts = new ArrayList<>(); + /** * Historical data of past broadcasts, for debugging. This is a ring buffer * whose last element is at mHistoryNext. @@ -70,7 +77,16 @@ public class BroadcastHistory { final long[] mSummaryHistoryDispatchTime; final long[] mSummaryHistoryFinishTime; - public void addBroadcastToHistoryLocked(BroadcastRecord original) { + void onBroadcastEnqueuedLocked(@NonNull BroadcastRecord r) { + mPendingBroadcasts.add(r); + } + + void onBroadcastFinishedLocked(@NonNull BroadcastRecord r) { + mPendingBroadcasts.remove(r); + addBroadcastToHistoryLocked(r); + } + + public void addBroadcastToHistoryLocked(@NonNull BroadcastRecord original) { // Note sometimes (only for sticky broadcasts?) we reuse BroadcastRecords, // So don't change the incoming record directly. final BroadcastRecord historyRecord = original.maybeStripForHistory(); @@ -93,7 +109,12 @@ public class BroadcastHistory { } @NeverCompile - public void dumpDebug(ProtoOutputStream proto) { + public void dumpDebug(@NonNull ProtoOutputStream proto) { + for (int i = 0; i < mPendingBroadcasts.size(); ++i) { + final BroadcastRecord r = mPendingBroadcasts.get(i); + r.dumpDebug(proto, BroadcastQueueProto.PENDING_BROADCASTS); + } + int lastIndex = mHistoryNext; int ringIndex = lastIndex; do { @@ -127,8 +148,20 @@ public class BroadcastHistory { } @NeverCompile - public boolean dumpLocked(PrintWriter pw, String dumpPackage, String queueName, - SimpleDateFormat sdf, boolean dumpAll, boolean needSep) { + public boolean dumpLocked(@NonNull PrintWriter pw, @Nullable String dumpPackage, + @NonNull String queueName, @NonNull SimpleDateFormat sdf, + boolean dumpAll, boolean needSep) { + pw.println(" Pending broadcasts:"); + if (mPendingBroadcasts.isEmpty()) { + pw.println(" "); + } else { + for (int idx = mPendingBroadcasts.size() - 1; idx >= 0; --idx) { + final BroadcastRecord r = mPendingBroadcasts.get(idx); + pw.print(" Broadcast #"); pw.print(idx); pw.println(":"); + r.dump(pw, " ", sdf); + } + } + int i; boolean printed = false; diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java index 84c03e59c658b..32e5fd1ef3fd2 100644 --- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java +++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java @@ -1145,8 +1145,11 @@ class BroadcastProcessQueue { pw.print(" because "); pw.print(reasonToString(mRunnableAtReason)); pw.println(); - pw.print("mProcessCached="); pw.println(mProcessCached); + pw.increaseIndent(); + dumpProcessState(pw); + dumpBroadcastCounts(pw); + if (mActive != null) { dumpRecord("ACTIVE", now, pw, mActive, mActiveIndex); } @@ -1166,6 +1169,49 @@ class BroadcastProcessQueue { pw.println(); } + @NeverCompile + private void dumpProcessState(@NonNull IndentingPrintWriter pw) { + final StringBuilder sb = new StringBuilder(); + if (mProcessCached) { + sb.append("CACHED"); + } + if (mProcessInstrumented) { + if (sb.length() > 0) sb.append("|"); + sb.append("INSTR"); + } + if (mProcessPersistent) { + if (sb.length() > 0) sb.append("|"); + sb.append("PER"); + } + if (sb.length() > 0) { + pw.print("state:"); pw.println(sb); + } + if (runningOomAdjusted) { + pw.print("runningOomAdjusted:"); pw.println(runningOomAdjusted); + } + } + + @NeverCompile + private void dumpBroadcastCounts(@NonNull IndentingPrintWriter pw) { + pw.print("e:"); pw.print(mCountEnqueued); + pw.print(" d:"); pw.print(mCountDeferred); + pw.print(" f:"); pw.print(mCountForeground); + pw.print(" fd:"); pw.print(mCountForegroundDeferred); + pw.print(" o:"); pw.print(mCountOrdered); + pw.print(" a:"); pw.print(mCountAlarm); + pw.print(" p:"); pw.print(mCountPrioritized); + pw.print(" pd:"); pw.print(mCountPrioritizedDeferred); + pw.print(" int:"); pw.print(mCountInteractive); + pw.print(" rt:"); pw.print(mCountResultTo); + pw.print(" ins:"); pw.print(mCountInstrumented); + pw.print(" m:"); pw.print(mCountManifest); + + pw.print(" csi:"); pw.print(mActiveCountSinceIdle); + pw.print(" ccu:"); pw.print(mActiveCountConsecutiveUrgent); + pw.print(" ccn:"); pw.print(mActiveCountConsecutiveNormal); + pw.println(); + } + @NeverCompile private void dumpRecord(@Nullable String flavor, @UptimeMillisLong long now, @NonNull IndentingPrintWriter pw, @NonNull BroadcastRecord record, int recordIndex) { diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java index b942f4b96b219..bfe8c2c4d24eb 100644 --- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java +++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java @@ -90,7 +90,6 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Arrays; import java.util.Objects; import java.util.Set; import java.util.concurrent.CountDownLatch; @@ -614,6 +613,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { r.enqueueTime = SystemClock.uptimeMillis(); r.enqueueRealTime = SystemClock.elapsedRealtime(); r.enqueueClockTime = System.currentTimeMillis(); + mHistory.onBroadcastEnqueuedLocked(r); ArraySet replacedBroadcasts = mReplacedBroadcastsCache.getAndSet(null); if (replacedBroadcasts == null) { @@ -837,8 +837,9 @@ class BroadcastQueueModernImpl extends BroadcastQueue { if (app != null && app.isInFullBackup()) { return "isInFullBackup"; } - if (mSkipPolicy.shouldSkip(r, receiver)) { - return "mSkipPolicy"; + final String skipReason = mSkipPolicy.shouldSkipMessage(r, receiver); + if (skipReason != null) { + return skipReason; } final Intent receiverIntent = r.getReceiverIntent(receiver); if (receiverIntent == null) { @@ -1108,7 +1109,8 @@ class BroadcastQueueModernImpl extends BroadcastQueue { */ private void setDeliveryState(@Nullable BroadcastProcessQueue queue, @Nullable ProcessRecord app, @NonNull BroadcastRecord r, int index, - @NonNull Object receiver, @DeliveryState int newDeliveryState, String reason) { + @NonNull Object receiver, @DeliveryState int newDeliveryState, + @NonNull String reason) { final int cookie = traceBegin("setDeliveryState"); final int oldDeliveryState = getDeliveryState(r, index); boolean checkFinished = false; @@ -1116,7 +1118,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { // Only apply state when we haven't already reached a terminal state; // this is how we ignore racing timeout messages if (!isDeliveryStateTerminal(oldDeliveryState)) { - r.setDeliveryState(index, newDeliveryState); + r.setDeliveryState(index, newDeliveryState, reason); if (oldDeliveryState == BroadcastRecord.DELIVERY_DEFERRED) { r.deferredCount--; } else if (newDeliveryState == BroadcastRecord.DELIVERY_DEFERRED) { @@ -1667,7 +1669,7 @@ class BroadcastQueueModernImpl extends BroadcastQueue { mService.notifyBroadcastFinishedLocked(r); r.finishTime = SystemClock.uptimeMillis(); r.nextReceiver = r.receivers.size(); - mHistory.addBroadcastToHistoryLocked(r); + mHistory.onBroadcastFinishedLocked(r); BroadcastQueueImpl.logBootCompletedBroadcastCompletionLatencyIfPossible(r); @@ -1841,8 +1843,9 @@ class BroadcastQueueModernImpl extends BroadcastQueue { if (dumpConstants) { mConstants.dump(ipw); } + if (dumpHistory) { - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); + final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); needSep = mHistory.dumpLocked(ipw, dumpPackage, mQueueName, sdf, dumpAll, needSep); } return needSep; diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java index f793c5078b5e8..59f33ddb795df 100644 --- a/services/core/java/com/android/server/am/BroadcastRecord.java +++ b/services/core/java/com/android/server/am/BroadcastRecord.java @@ -99,6 +99,7 @@ final class BroadcastRecord extends Binder { final @Nullable BroadcastOptions options; // BroadcastOptions supplied by caller final @NonNull List receivers; // contains BroadcastFilter and ResolveInfo final @DeliveryState int[] delivery; // delivery state of each receiver + final @NonNull String[] deliveryReasons; // reasons for delivery state of each receiver final boolean[] deferredUntilActive; // whether each receiver is infinitely deferred final int[] blockedUntilTerminalCount; // blocked until count of each receiver @Nullable ProcessRecord resultToApp; // who receives final result if non-null @@ -298,7 +299,7 @@ final class BroadcastRecord extends Binder { pw.print(" initialSticky="); pw.println(initialSticky); } if (nextReceiver != 0) { - pw.print(prefix); pw.print("nextReceiver="); pw.print(nextReceiver); + pw.print(prefix); pw.print("nextReceiver="); pw.println(nextReceiver); } if (curFilter != null) { pw.print(prefix); pw.print("curFilter="); pw.println(curFilter); @@ -328,6 +329,7 @@ final class BroadcastRecord extends Binder { } pw.print(prefix); pw.print("state="); pw.print(state); pw.println(stateStr); } + pw.print(prefix); pw.print("terminalCount="); pw.println(terminalCount); final int N = receivers != null ? receivers.size() : 0; String p2 = prefix + " "; PrintWriterPrinter printer = new PrintWriterPrinter(pw); @@ -346,6 +348,7 @@ final class BroadcastRecord extends Binder { TimeUtils.formatDuration(terminalTime[i] - scheduledTime[i], pw); pw.print(' '); } + pw.print("("); pw.print(blockedUntilTerminalCount[i]); pw.print(") "); pw.print("#"); pw.print(i); pw.print(": "); if (o instanceof BroadcastFilter) { pw.println(o); @@ -356,6 +359,9 @@ final class BroadcastRecord extends Binder { } else { pw.println(o); } + if (deliveryReasons[i] != null) { + pw.print(p2); pw.print("reason: "); pw.println(deliveryReasons[i]); + } } } @@ -393,6 +399,7 @@ final class BroadcastRecord extends Binder { options = _options; receivers = (_receivers != null) ? _receivers : EMPTY_RECEIVERS; delivery = new int[_receivers != null ? _receivers.size() : 0]; + deliveryReasons = new String[delivery.length]; deferUntilActive = options != null ? options.isDeferUntilActive() : false; deferredUntilActive = new boolean[deferUntilActive ? delivery.length : 0]; blockedUntilTerminalCount = calculateBlockedUntilTerminalCount(receivers, _serialized); @@ -448,6 +455,7 @@ final class BroadcastRecord extends Binder { options = from.options; receivers = from.receivers; delivery = from.delivery; + deliveryReasons = from.deliveryReasons; deferUntilActive = from.deferUntilActive; deferredUntilActive = from.deferredUntilActive; blockedUntilTerminalCount = from.blockedUntilTerminalCount; @@ -609,8 +617,10 @@ final class BroadcastRecord extends Binder { * Update the delivery state of the given {@link #receivers} index. * Automatically updates any time measurements related to state changes. */ - void setDeliveryState(int index, @DeliveryState int deliveryState) { + void setDeliveryState(int index, @DeliveryState int deliveryState, + @NonNull String reason) { delivery[index] = deliveryState; + deliveryReasons[index] = reason; if (deferUntilActive) deferredUntilActive[index] = false; switch (deliveryState) { case DELIVERY_DELIVERED: @@ -977,7 +987,8 @@ final class BroadcastRecord extends Binder { if (label == null) { label = intent.toString(); } - mCachedToShortString = label + "/u" + userId; + mCachedToShortString = Integer.toHexString(System.identityHashCode(this)) + + ":" + label + "/u" + userId; } return mCachedToShortString; } diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java index 95c2ed2f841fa..50010e18394d8 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java @@ -558,7 +558,7 @@ public final class BroadcastQueueModernImplTest { // To maximize test coverage, dump current state; we're not worried // about the actual output, just that we don't crash - queue.getActive().setDeliveryState(0, BroadcastRecord.DELIVERY_SCHEDULED); + queue.getActive().setDeliveryState(0, BroadcastRecord.DELIVERY_SCHEDULED, "Test-driven"); queue.dumpLocked(SystemClock.uptimeMillis(), new IndentingPrintWriter(new PrintWriter(new ByteArrayOutputStream())));