1 /*
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 
17 import java.io.BufferedReader;
18 import java.io.FileReader;
19 import java.io.InputStreamReader;
20 import java.util.Arrays;
21 import java.util.Comparator;
22 
23 public class Main extends Base implements Comparator<Main> {
24   // Whether to test local unwinding.
25   private static boolean testLocal;
26 
27   // Unwinding another process, modelling debuggerd.
28   private static boolean testRemote;
29 
30   // We fork ourself to create the secondary process for remote unwinding.
31   private static boolean secondary;
32 
main(String[] args)33   public static void main(String[] args) throws Exception {
34       System.out.println("args: " + String.join(" ", Arrays.copyOfRange(args, 1, args.length)));
35 
36       System.loadLibrary(args[0]);
37       for (int i = 1; i < args.length; i++) {
38           if (args[i].equals("--test-local")) {
39               testLocal = true;
40           } else if (args[i].equals("--test-remote")) {
41               testRemote = true;
42           } else if (args[i].equals("--secondary")) {
43               secondary = true;
44           } else {
45               System.out.println("Unknown argument: " + args[i]);
46               System.exit(1);
47           }
48       }
49 
50       // Call test() via base class to test unwinding through multidex.
51       new Main().$noinline$runTest();
52   }
53 
test()54   public void test() {
55       // Call unwind() via Arrays.binarySearch to test unwinding through framework.
56       Main[] array = { this, this, this };
57       Arrays.binarySearch(array, 0, 3, this /* value */, this /* comparator */);
58   }
59 
compare(Main lhs, Main rhs)60   public int compare(Main lhs, Main rhs) {
61       unwind();
62       // Returning "equal" ensures that we terminate search
63       // after first item and thus call unwind() only once.
64       return 0;
65   }
66 
unwind()67   public void unwind() {
68       if (secondary) {
69           sigstop();  // This is helper child process. Stop and wait for unwinding.
70           return;     // Don't run the tests again in the secondary helper process.
71       }
72 
73       if (testLocal) {
74           System.out.println(unwindInProcess() ? "PASS" : "FAIL");
75       }
76 
77       if (testRemote) {
78           // Start a secondary helper process. It will stop itself when it is ready.
79           int pid = startSecondaryProcess();
80           // Wait for the secondary process to stop and then unwind it remotely.
81           System.out.println(unwindOtherProcess(pid) ? "PASS" : "FAIL");
82       }
83   }
84 
startSecondaryProcess()85   public static native int startSecondaryProcess();
sigstop()86   public static native boolean sigstop();
unwindInProcess()87   public static native boolean unwindInProcess();
unwindOtherProcess(int pid)88   public static native boolean unwindOtherProcess(int pid);
89 }
90