blob: e184e66e6f8736cb7e22c42fdc98388f5fd81757 [file] [log] [blame]
Andreas Gampe73810102015-04-22 18:57:06 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17import java.io.BufferedReader;
18import java.io.FileReader;
19import java.io.InputStream;
20import java.io.OutputStream;
21import java.lang.reflect.InvocationTargetException;
22import java.lang.reflect.Method;
23
24public class Main {
25 // Whether to test local unwinding. Libunwind uses linker info to find executables. As we do
26 // not dlopen at the moment, this doesn't work, so keep it off for now.
27 public final static boolean TEST_LOCAL_UNWINDING = false;
28
29 // Unwinding another process, modelling debuggerd. This doesn't use the linker, so should work
30 // no matter whether we're using dlopen or not.
31 public final static boolean TEST_REMOTE_UNWINDING = true;
32
33 private boolean secondary;
34
35 public Main(boolean secondary) {
36 this.secondary = secondary;
37 }
38
39 public static void main(String[] args) throws Exception {
40 boolean secondary = false;
41 if (args.length > 0 && args[args.length - 1].equals("--secondary")) {
42 secondary = true;
43 }
44 new Main(secondary).run();
45 }
46
47 static {
48 System.loadLibrary("arttest");
49 }
50
51 private void run() {
52 if (secondary) {
53 if (!TEST_REMOTE_UNWINDING) {
54 throw new RuntimeException("Should not be running secondary!");
55 }
56 runSecondary();
57 } else {
58 runPrimary();
59 }
60 }
61
62 private void runSecondary() {
63 foo(true);
64 throw new RuntimeException("Didn't expect to get back...");
65 }
66
67 private void runPrimary() {
68 // First do the in-process unwinding.
69 if (TEST_LOCAL_UNWINDING && !foo(false)) {
70 System.out.println("Unwinding self failed.");
71 }
72
73 if (!TEST_REMOTE_UNWINDING) {
74 // Skip the remote step.
75 return;
76 }
77
78 // Fork the secondary.
79 String[] cmdline = getCmdLine();
80 String[] secCmdLine = new String[cmdline.length + 1];
81 System.arraycopy(cmdline, 0, secCmdLine, 0, cmdline.length);
82 secCmdLine[secCmdLine.length - 1] = "--secondary";
83 Process p = exec(secCmdLine);
84
85 try {
86 int pid = getPid(p);
87 if (pid <= 0) {
88 throw new RuntimeException("Couldn't parse process");
89 }
90
91 // Wait a bit, so the forked process has time to run until its sleep phase.
92 try {
93 Thread.sleep(5000);
94 } catch (Exception e) {
95 throw new RuntimeException(e);
96 }
97
98 if (!unwindOtherProcess(pid)) {
99 System.out.println("Unwinding other process failed.");
100 }
101 } finally {
102 // Kill the forked process.
103 p.destroy();
104 }
105 }
106
107 private static Process exec(String[] args) {
108 try {
109 return Runtime.getRuntime().exec(args);
110 } catch (Exception exc) {
111 throw new RuntimeException(exc);
112 }
113 }
114
115 private static int getPid(Process p) {
116 // Could do reflection for the private pid field, but String parsing is easier.
117 String s = p.toString();
118 if (s.startsWith("Process[pid=")) {
119 return Integer.parseInt(s.substring("Process[pid=".length(), s.length() - 1));
120 } else {
121 return -1;
122 }
123 }
124
125 // Read /proc/self/cmdline to find the invocation command line (so we can fork another runtime).
126 private static String[] getCmdLine() {
127 try {
128 BufferedReader in = new BufferedReader(new FileReader("/proc/self/cmdline"));
129 String s = in.readLine();
130 in.close();
131 return s.split("\0");
132 } catch (Exception exc) {
133 throw new RuntimeException(exc);
134 }
135 }
136
137 public boolean foo(boolean b) {
138 return bar(b);
139 }
140
141 public boolean bar(boolean b) {
142 if (b) {
143 return sleep(2, b, 1.0);
144 } else {
145 return unwindInProcess(1, b);
146 }
147 }
148
149 // Native functions. Note: to avoid deduping, they must all have different signatures.
150
151 public native boolean sleep(int i, boolean b, double dummy);
152
153 public native boolean unwindInProcess(int i, boolean b);
154 public native boolean unwindOtherProcess(int pid);
155}