Simplify the 137-cfi test.

Test: ./test.py --host -b -t 137
Change-Id: I4307ab28d942b2baa110ab26035ef0f095d1b3c7
diff --git a/test/137-cfi/cfi.cc b/test/137-cfi/cfi.cc
index a91d348..985d273 100644
--- a/test/137-cfi/cfi.cc
+++ b/test/137-cfi/cfi.cc
@@ -54,15 +54,38 @@
 #endif
 }
 
-extern "C" JNIEXPORT jboolean JNICALL Java_Main_sleep(JNIEnv*, jobject, jint, jboolean, jdouble) {
-  // Keep pausing.
-  struct timespec ts = { .tv_sec = 100, .tv_nsec = 0 };
-  printf("Going to sleep\n");
-  for (;;) {
-    // Use nanosleep since it gets to the system call quickly and doesn't
-    // have any points at which an unwind will fail.
-    nanosleep(&ts, nullptr);
+extern "C" JNIEXPORT jint JNICALL Java_Main_startSecondaryProcess(JNIEnv*, jclass) {
+#if __linux__
+  // Get our command line so that we can use it to start identical process.
+  std::string cmdline;  // null-separated and null-terminated arguments.
+  ReadFileToString("/proc/self/cmdline", &cmdline);
+  cmdline = cmdline + "--secondary" + '\0';  // Let the child know it is a helper.
+
+  // Split the string into individual arguments suitable for execv.
+  std::vector<char*> argv;
+  for (size_t i = 0; i < cmdline.size(); i += strlen(&cmdline[i]) + 1) {
+    argv.push_back(&cmdline[i]);
   }
+  argv.push_back(nullptr);  // Terminate the list.
+
+  pid_t pid = fork();
+  if (pid < 0) {
+    LOG(FATAL) << "Fork failed";
+  } else if (pid == 0) {
+    execv(argv[0], argv.data());
+    exit(1);
+  }
+  return pid;
+#else
+  return 0;
+#endif
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_sigstop(JNIEnv*, jclass) {
+#if __linux__
+  raise(SIGSTOP);
+#endif
+  return true;  // Prevent the compiler from tail-call optimizing this method away.
 }
 
 // Helper to look for a sequence in the stack trace.
@@ -107,12 +130,7 @@
 }
 #endif
 
-extern "C" JNIEXPORT jboolean JNICALL Java_Main_unwindInProcess(
-    JNIEnv*,
-    jobject,
-    jboolean,
-    jint,
-    jboolean) {
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_unwindInProcess(JNIEnv*, jclass) {
 #if __linux__
   std::unique_ptr<Backtrace> bt(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, GetTid()));
   if (!bt->Unwind(0, nullptr)) {
@@ -128,10 +146,10 @@
   // only unique functions are being expected.
   // "mini-debug-info" does not include parameters to save space.
   std::vector<std::string> seq = {
-      "Java_Main_unwindInProcess",                   // This function.
-      "java.util.Arrays.binarySearch0",              // Framework method.
-      "Base.runBase",                                // Method in other dex file.
-      "Main.main"                                    // The Java entry method.
+      "Java_Main_unwindInProcess",       // This function.
+      "java.util.Arrays.binarySearch0",  // Framework method.
+      "Base.runTest",                    // Method in other dex file.
+      "Main.main"                        // The Java entry method.
   };
 
   bool result = CheckStack(bt.get(), seq);
@@ -150,8 +168,8 @@
 }
 
 #if __linux__
-static constexpr int kSleepTimeMicroseconds = 50000;            // 0.05 seconds
-static constexpr int kMaxTotalSleepTimeMicroseconds = 1000000;  // 1 second
+static constexpr int kSleepTimeMicroseconds = 50000;             // 0.05 seconds
+static constexpr int kMaxTotalSleepTimeMicroseconds = 10000000;  // 10 seconds
 
 // Wait for a sigstop. This code is copied from libbacktrace.
 int wait_for_sigstop(pid_t tid, int* total_sleep_time_usec, bool* detach_failed ATTRIBUTE_UNUSED) {
@@ -183,17 +201,12 @@
 }
 #endif
 
-extern "C" JNIEXPORT jboolean JNICALL Java_Main_unwindOtherProcess(
-    JNIEnv*,
-    jobject,
-    jboolean,
-    jint pid_int) {
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_unwindOtherProcess(JNIEnv*, jclass, jint pid_int) {
 #if __linux__
   pid_t pid = static_cast<pid_t>(pid_int);
 
-  // OK, this is painful. debuggerd uses ptrace to unwind other processes.
-
-  if (ptrace(PTRACE_ATTACH, pid, 0, 0)) {
+  // SEIZE is like ATTACH, but it does not stop the process (we let it stop itself).
+  if (ptrace(PTRACE_SEIZE, pid, 0, 0)) {
     // Were not able to attach, bad.
     printf("Failed to attach to other process.\n");
     PLOG(ERROR) << "Failed to attach.";
@@ -201,13 +214,12 @@
     return JNI_FALSE;
   }
 
-  kill(pid, SIGSTOP);
-
   bool detach_failed = false;
   int total_sleep_time_usec = 0;
   int signal = wait_for_sigstop(pid, &total_sleep_time_usec, &detach_failed);
-  if (signal == -1) {
+  if (signal != SIGSTOP) {
     LOG(WARNING) << "wait_for_sigstop failed.";
+    return JNI_FALSE;
   }
 
   std::unique_ptr<Backtrace> bt(Backtrace::Create(pid, BACKTRACE_CURRENT_THREAD));
@@ -224,10 +236,10 @@
     // See comment in unwindInProcess for non-exact stack matching.
     // "mini-debug-info" does not include parameters to save space.
     std::vector<std::string> seq = {
-        "Java_Main_sleep",                           // The sleep function in the other process.
-        "java.util.Arrays.binarySearch0",            // Framework method.
-        "Base.runBase",                              // Method in other dex file.
-        "Main.main"                                  // The Java entry method.
+        "Java_Main_sigstop",                // The stop function in the other process.
+        "java.util.Arrays.binarySearch0",   // Framework method.
+        "Base.runTest",                     // Method in other dex file.
+        "Main.main"                         // The Java entry method.
     };
 
     result = CheckStack(bt.get(), seq);
diff --git a/test/137-cfi/expected.txt b/test/137-cfi/expected.txt
index 8db7853..eedae8f 100644
--- a/test/137-cfi/expected.txt
+++ b/test/137-cfi/expected.txt
@@ -1,2 +1,7 @@
 JNI_OnLoad called
+Unwind in process: PASS
 JNI_OnLoad called
+Unwind other process: PASS
+JNI_OnLoad called
+JNI_OnLoad called
+Unwind other process: PASS
diff --git a/test/137-cfi/run b/test/137-cfi/run
index 9190b1c..4096b89 100755
--- a/test/137-cfi/run
+++ b/test/137-cfi/run
@@ -20,7 +20,7 @@
 # there will be JITed frames on the callstack (it synchronously JITs on first use).
 ${RUN} "$@" -Xcompiler-option --generate-debug-info \
   --runtime-option -Xjitthreshold:0 \
-  --args --full-signatures --args --test-local --args --test-remote
+  --args --test-local --args --test-remote
 return_status1=$?
 
 # Test with minimal compressed debugging information.
diff --git a/test/137-cfi/src-multidex/Base.java b/test/137-cfi/src-multidex/Base.java
index d3f8a56..986a3c2 100644
--- a/test/137-cfi/src-multidex/Base.java
+++ b/test/137-cfi/src-multidex/Base.java
@@ -15,8 +15,12 @@
  */
 
 public abstract class Base {
-  abstract public void runImpl();
-  public void runBase() {
-    runImpl();
+  public void runTest() throws Exception {
+    // Conditionally throw exception to prevent the compiler from inlining the code.
+    if (!this.getClass().getName().equals("Main")) {
+      throw new Exception("Who is calling?");
+    }
+    test();
   }
+  abstract public void test();
 }
diff --git a/test/137-cfi/src/Main.java b/test/137-cfi/src/Main.java
index 9a2e352..5b32d8e 100644
--- a/test/137-cfi/src/Main.java
+++ b/test/137-cfi/src/Main.java
@@ -22,181 +22,68 @@
 
 public class Main extends Base implements Comparator<Main> {
   // Whether to test local unwinding.
-  private boolean testLocal;
+  private static boolean testLocal;
 
   // Unwinding another process, modelling debuggerd.
-  private boolean testRemote;
+  private static boolean testRemote;
 
   // We fork ourself to create the secondary process for remote unwinding.
-  private boolean secondary;
-
-  // Expect the symbols to contain full method signatures including parameters.
-  private boolean fullSignatures;
-
-  private boolean passed;
-
-  public Main(String[] args) throws Exception {
-      System.loadLibrary(args[0]);
-      for (String arg : args) {
-          if (arg.equals("--test-local")) {
-              testLocal = true;
-          }
-          if (arg.equals("--test-remote")) {
-              testRemote = true;
-          }
-          if (arg.equals("--secondary")) {
-              secondary = true;
-          }
-          if (arg.equals("--full-signatures")) {
-              fullSignatures = true;
-          }
-      }
-      if (!testLocal && !testRemote) {
-          System.out.println("No test selected.");
-      }
-  }
+  private static boolean secondary;
 
   public static void main(String[] args) throws Exception {
-      new Main(args).runBase();
-  }
-
-  public void runImpl() {
-      if (secondary) {
-          if (!testRemote) {
-              throw new RuntimeException("Should not be running secondary!");
+      System.loadLibrary(args[0]);
+      for (int i = 1; i < args.length; i++) {
+          if (args[i].equals("--test-local")) {
+              testLocal = true;
+          } else if (args[i].equals("--test-remote")) {
+              testRemote = true;
+          } else if (args[i].equals("--secondary")) {
+              secondary = true;
+          } else {
+              System.out.println("Unknown argument: " + args[i]);
+              System.exit(1);
           }
-          runSecondary();
-      } else {
-          runPrimary();
       }
+
+      // Call test() via base class to test unwinding through multidex.
+      new Main().runTest();
   }
 
-  private void runSecondary() {
-      foo();
-      throw new RuntimeException("Didn't expect to get back...");
-  }
-
-  private void runPrimary() {
-      // First do the in-process unwinding.
-      if (testLocal && !foo()) {
-          System.out.println("Unwinding self failed.");
-      }
-
-      if (!testRemote) {
-          // Skip the remote step.
-          return;
-      }
-
-      // Fork the secondary.
-      String[] cmdline = getCmdLine();
-      String[] secCmdLine = new String[cmdline.length + 1];
-      System.arraycopy(cmdline, 0, secCmdLine, 0, cmdline.length);
-      secCmdLine[secCmdLine.length - 1] = "--secondary";
-      Process p = exec(secCmdLine);
-
-      try {
-          int pid = getPid(p);
-          if (pid <= 0) {
-              throw new RuntimeException("Couldn't parse process");
-          }
-
-          // Wait until the forked process had time to run until its sleep phase.
-          BufferedReader lineReader;
-          try {
-              InputStreamReader stdout = new InputStreamReader(p.getInputStream(), "UTF-8");
-              lineReader = new BufferedReader(stdout);
-              while (!lineReader.readLine().contains("Going to sleep")) {
-              }
-          } catch (Exception e) {
-              throw new RuntimeException(e);
-          }
-
-          if (!unwindOtherProcess(fullSignatures, pid)) {
-              System.out.println("Unwinding other process failed.");
-
-              // In this case, log all the output.
-              // Note: this is potentially non-terminating code, if the secondary is totally stuck.
-              //       We rely on the run-test timeout infrastructure to terminate the primary in
-              //       such a case.
-              try {
-                  String tmp;
-                  System.out.println("Output from the secondary:");
-                  while ((tmp = lineReader.readLine()) != null) {
-                      System.out.println("Secondary: " + tmp);
-                  }
-              } catch (Exception e) {
-                  e.printStackTrace(System.out);
-              }
-          }
-
-          try {
-              lineReader.close();
-          } catch (Exception e) {
-              e.printStackTrace(System.out);
-          }
-      } finally {
-          // Kill the forked process if it is not already dead.
-          p.destroy();
-      }
-  }
-
-  private static Process exec(String[] args) {
-      try {
-          return Runtime.getRuntime().exec(args);
-      } catch (Exception exc) {
-          throw new RuntimeException(exc);
-      }
-  }
-
-  private static int getPid(Process p) {
-      // Could do reflection for the private pid field, but String parsing is easier.
-      String s = p.toString();
-      if (s.startsWith("Process[pid=")) {
-          return Integer.parseInt(s.substring("Process[pid=".length(), s.indexOf(",")));
-      } else {
-          return -1;
-      }
-  }
-
-  // Read /proc/self/cmdline to find the invocation command line (so we can fork another runtime).
-  private static String[] getCmdLine() {
-      try {
-          BufferedReader in = new BufferedReader(new FileReader("/proc/self/cmdline"));
-          String s = in.readLine();
-          in.close();
-          return s.split("\0");
-      } catch (Exception exc) {
-          throw new RuntimeException(exc);
-      }
-  }
-
-  public boolean foo() {
-      // Call bar via Arrays.binarySearch.
-      // This tests that we can unwind from framework code.
+  public void test() {
+      // Call unwind() via Arrays.binarySearch to test unwinding through framework.
       Main[] array = { this, this, this };
       Arrays.binarySearch(array, 0, 3, this /* value */, this /* comparator */);
-      return passed;
   }
 
   public int compare(Main lhs, Main rhs) {
-      passed = bar(secondary);
+      unwind();
       // Returning "equal" ensures that we terminate search
-      // after first item and thus call bar() only once.
+      // after first item and thus call unwind() only once.
       return 0;
   }
 
-  public boolean bar(boolean b) {
-      if (b) {
-          return sleep(2, b, 1.0);
-      } else {
-          return unwindInProcess(fullSignatures, 1, b);
+  public void unwind() {
+      if (secondary) {
+          sigstop();  // This is helper child process. Stop and wait for unwinding.
+          return;     // Don't run the tests again in the secondary helper process.
+      }
+
+      if (testLocal) {
+          String result = unwindInProcess() ? "PASS" : "FAIL";
+          System.out.println("Unwind in process: " + result);
+      }
+
+      if (testRemote) {
+          // Start a secondary helper process. It will stop itself when it is ready.
+          int pid = startSecondaryProcess();
+          // Wait for the secondary process to stop and then unwind it remotely.
+          String result = unwindOtherProcess(pid) ? "PASS" : "FAIL";
+          System.out.println("Unwind other process: " + result);
       }
   }
 
-  // Native functions. Note: to avoid deduping, they must all have different signatures.
-
-  public native boolean sleep(int i, boolean b, double dummy);
-
-  public native boolean unwindInProcess(boolean fullSignatures, int i, boolean b);
-  public native boolean unwindOtherProcess(boolean fullSignatures, int pid);
+  public static native int startSecondaryProcess();
+  public static native boolean sigstop();
+  public static native boolean unwindInProcess();
+  public static native boolean unwindOtherProcess(int pid);
 }