diff options
author | Alex Light <allight@google.com> | 2018-02-09 07:23:21 +0000 |
---|---|---|
committer | android-build-merger <android-build-merger@google.com> | 2018-02-09 07:23:21 +0000 |
commit | eb5d20ab7a2079625aa1b20aa8ef517cd9cc1613 (patch) | |
tree | ad6cc63b06c9e6569065001fe83fa8f428b4b1b0 | |
parent | e626a01e06fbd4a1e8a24ffdf68c5db34f0efd3c (diff) | |
parent | fb40f85d6da8c8bf43320a8b1c2f30745621d8f5 (diff) | |
download | apache-harmony-eb5d20ab7a2079625aa1b20aa8ef517cd9cc1613.tar.gz |
Merge "Allow jdwp tests to dump native traces on timeout." am: 0ea7d2a564
am: fb40f85d6d
Change-Id: I102ecff95fadd78be1fc239f3119969db9bb95b2
-rw-r--r-- | jdwp/src/test/java/org/apache/harmony/jpda/tests/framework/TestOptions.java | 10 | ||||
-rw-r--r-- | jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/share/JDWPUnitDebuggeeProcessWrapper.java | 121 |
2 files changed, 130 insertions, 1 deletions
diff --git a/jdwp/src/test/java/org/apache/harmony/jpda/tests/framework/TestOptions.java b/jdwp/src/test/java/org/apache/harmony/jpda/tests/framework/TestOptions.java index bc909d1..fa9882d 100644 --- a/jdwp/src/test/java/org/apache/harmony/jpda/tests/framework/TestOptions.java +++ b/jdwp/src/test/java/org/apache/harmony/jpda/tests/framework/TestOptions.java @@ -70,6 +70,9 @@ import java.util.HashMap; * <li><code>jpda.settings.waitingTime</code> * - timeout for waiting events * </ul> + * <li><code>jpda.settings.dumpProcess</code> + * - Command to dump a process' data + * </ul> * <li><code>jpda.settings.verbose</code> * - flag that disables (default) or enables writing messages to the log * </ul> @@ -118,6 +121,13 @@ public class TestOptions { } /** + * Gets the command line needed to get backtraces/status of a given pid + */ + public String getDumpProcessCommand() { + return getProperty("jpda.settings.dumpProcess", "true"); + } + + /** * Returns path to Java bundle to run debuggee on. * * @return option "jpda.settings.debuggeeJavaHome" or system property diff --git a/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/share/JDWPUnitDebuggeeProcessWrapper.java b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/share/JDWPUnitDebuggeeProcessWrapper.java index 6910319..409ac02 100644 --- a/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/share/JDWPUnitDebuggeeProcessWrapper.java +++ b/jdwp/src/test/java/org/apache/harmony/jpda/tests/jdwp/share/JDWPUnitDebuggeeProcessWrapper.java @@ -22,7 +22,15 @@ package org.apache.harmony.jpda.tests.jdwp.share; +import java.lang.reflect.Field; + +import java.io.*; +import java.nio.file.*; + import java.io.IOException; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.List; import java.util.Vector; import org.apache.harmony.jpda.tests.framework.LogWriter; @@ -296,7 +304,8 @@ public class JDWPUnitDebuggeeProcessWrapper extends JDWPDebuggeeWrapper { " but we expected code " + expectedExitCode); } } catch (IllegalThreadStateException e) { - logWriter.printError("Terminate debuggee process"); + logWriter.println("Terminate debuggee process with " + e); + GetRemoteStackTrace(process); throw new TestErrorException("Debuggee process did not finish during timeout", e); } finally { // dispose any resources of the process @@ -304,6 +313,116 @@ public class JDWPUnitDebuggeeProcessWrapper extends JDWPDebuggeeWrapper { } } + private int GetRealPid(Process process) { + int initial_pid = GetInitialPid(process); + logWriter.println("initial pid: " + initial_pid); + String[] names = new String[] { "java", "dalvikvm", "dalvikvm32", "dalvikvm64" }; + return FindPidFor(Paths.get("/proc").resolve(Integer.toString(initial_pid)), names); + } + + private int getPid(Path proc) throws IOException { + try { + // See man 5 proc for information on stat file. All we really care about is that it is a + // list of various pieces of information about the process separated by ' '. The first of + // these is the PID. + return Integer.valueOf(new String(Files.readAllBytes(proc.resolve("stat"))).split(" ")[0]); + } catch (IOException e) { + return -1; + } + } + + private int FindPidFor(Path cur, String[] names) { + try { + if (!cur.toFile().exists()) { + return -1; + } + int pid = getPid(cur); + if (Arrays.stream(names).anyMatch( + (x) -> { + try { + return cur.resolve("exe").toRealPath().endsWith(x); + } catch (Exception e) { + return false; + } + })) { + return pid; + } else { + Path children = cur.resolve("task").resolve(Integer.toString(pid)).resolve("children"); + if (!children.toFile().exists()) { + return -1; + } else { + for (String child_pid : ReadChildPids(children.toFile())) { + logWriter.println("Examining pid: " + child_pid); + int res = FindPidFor(Paths.get("/proc").resolve(child_pid), names); + if (res != -1) { + return res; + } + } + return -1; + } + } + } catch (Exception e) { + return -1; + } + } + + private String[] ReadChildPids(File children) throws Exception { + if (!children.exists()) { + return new String[0]; + } else { + return new String(Files.readAllBytes(children.toPath())).split(" "); + } + } + + private int GetInitialPid(Process process) { + try { + Class<?> unix_process_class = Class.forName("java.lang.UNIXProcess"); + if (!process.getClass().equals(unix_process_class)) { + throw new TestErrorException("Process is of unexpected type. Timeout happened."); + } + Field pid = unix_process_class.getDeclaredField("pid"); + pid.setAccessible(true); + return (int)pid.get(process); + } catch (ReflectiveOperationException e) { + throw new TestErrorException("Unable to get pid from process to debug timeout!", e); + } + } + + private void GetRemoteStackTrace(Process process) throws IOException { + String pid = Integer.toString(GetRealPid(process)); + logWriter.println("trying to dump " + pid); + List<String> cmd = new ArrayList<>(Arrays.asList(splitCommandLine(settings.getDumpProcessCommand()))); + cmd.add(pid); + logWriter.println("command: " + cmd); + + ProcessBuilder b = new ProcessBuilder(cmd).redirectErrorStream(true); + Process p = null; + StreamRedirector out = null; + try { + p = b.start(); + out = new StreamRedirector(p.getInputStream(), logWriter, "dump-" + pid); + out.setDaemon(true); + out.start(); + p.waitFor(); + // Wait 5 seconds for the streams to catch up. + Thread.sleep(5000); + } catch (Exception e) { + throw new TestErrorException("Unable to get process dump!", e); + } finally { + if (p != null) { + p.destroy(); + } + if (out != null) { + try { + out.exit(); + out.join(); + } catch (Exception e) { + logWriter.println("Suppressing error: " + e); + } + } + } + } + /** * Separate thread for waiting for process exit for specified timeout. */ |