From 544416e7027f9f5e491de56c135f046d88cc48f6 Mon Sep 17 00:00:00 2001 From: Andreas Gampe Date: Fri, 26 Jan 2018 11:39:46 -0800 Subject: [PATCH] Watchdog: Print annotated stack trace, if possible Use VMStack.getAnnotatedStackTrace() to print an annotated stack. Aids in diagnostics of watchdog aborts. Bug: 70538431 Test: m Test: art/test/testrunner/testrunner.py -b --host -t 168 Test: runtest -c com.android.server.WatchdogDiagnosticsTest frameworks-services Test: manual - insert a deadlock into ActivityManagerService Change-Id: I5bd43920edb8b569240432b6f299e56cabf5ef2a --- .../core/java/com/android/server/Watchdog.java | 9 +- .../com/android/server/WatchdogDiagnostics.java | 88 ++++++++++ .../android/server/WatchdogDiagnosticsTest.java | 189 +++++++++++++++++++++ 3 files changed, 278 insertions(+), 8 deletions(-) create mode 100644 services/core/java/com/android/server/WatchdogDiagnostics.java create mode 100644 services/tests/servicestests/src/com/android/server/WatchdogDiagnosticsTest.java diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java index 18b00ac21222..53285e6a07d7 100644 --- a/services/core/java/com/android/server/Watchdog.java +++ b/services/core/java/com/android/server/Watchdog.java @@ -566,14 +566,7 @@ public class Watchdog extends Thread { Slog.w(TAG, "Restart not allowed: Watchdog is *not* killing the system process"); } else { Slog.w(TAG, "*** WATCHDOG KILLING SYSTEM PROCESS: " + subject); - for (int i=0; i (a %s)", + System.identityHashCode(blockedOn), blockedOn.getClass().getName()); + } + + private static String getLockedString(Object heldLock) { + return String.format("- locked <0x%08x> (a %s)", System.identityHashCode(heldLock), + heldLock.getClass().getName()); + } + + /** + * Print the annotated stack for the given thread. If the annotated stack cannot be retrieved, + * returns false. + */ + @VisibleForTesting + public static boolean printAnnotatedStack(Thread thread, PrintWriter out) { + AnnotatedStackTraceElement stack[] = VMStack.getAnnotatedThreadStackTrace(thread); + if (stack == null) { + return false; + } + out.println(thread.getName() + " annotated stack trace:"); + for (AnnotatedStackTraceElement element : stack) { + out.println(" at " + element.getStackTraceElement()); + if (element.getBlockedOn() != null) { + out.println(" " + getBlockedOnString(element.getBlockedOn())); + } + if (element.getHeldLocks() != null) { + for (Object held : element.getHeldLocks()) { + out.println(" " + getLockedString(held)); + } + } + } + return true; + } + + public static void diagnoseCheckers(final List blockedCheckers) { + PrintWriter out = new PrintWriter(new LogWriter(Log.WARN, Watchdog.TAG, Log.LOG_ID_SYSTEM), + true); + for (int i=0; i (a java.lang.Integer)\n" + + " at com.android.server.WatchdogDiagnosticsTest$TestThread1.a(" + + "WatchdogDiagnosticsTest.java:53)\n" + + " - locked (a java.lang.Object)\n" + + " at com.android.server.WatchdogDiagnosticsTest$TestThread1.run(" + + "WatchdogDiagnosticsTest.java:48)\n"; + assertEquals(expected, filterHashes(output)); + } + + stringBuffer.getBuffer().setLength(0); + + { + WatchdogDiagnostics.printAnnotatedStack(thread2, print); + + String output = stringBuffer.toString(); + String expected = + "TestThread2 annotated stack trace:\n" + + " at java.lang.Object.wait(Native Method)\n" + + " at com.android.server.WatchdogDiagnosticsTest$TestThread2.y(" + + "WatchdogDiagnosticsTest.java:91)\n" + + " - locked (a java.lang.String)\n" + + " at com.android.server.WatchdogDiagnosticsTest$TestThread2.x(" + + "WatchdogDiagnosticsTest.java:83)\n" + + " - locked (a java.lang.Integer)\n" + + " at com.android.server.WatchdogDiagnosticsTest$TestThread2.run(" + + "WatchdogDiagnosticsTest.java:78)\n"; + assertEquals(expected, filterHashes(output)); + } + + // Let the threads finish. + synchronized (waitLock) { + waitLock.notifyAll(); + } + + thread1.join(); + thread2.join(); + } + + /** + * A filter function that removes hash codes (which will change between tests and cannot be + * controlled.) + *

+ * Note: leaves "" to indicate that something was replaced. + */ + private static String filterHashes(String t) { + return t.replaceAll("<0x[0-9a-f]{8}>", ""); + } +} -- 2.11.0