xref: /aosp_15_r20/art/test/141-class-unload/src/Main.java (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker import java.io.BufferedReader;
18*795d594fSAndroid Build Coastguard Worker import java.io.File;
19*795d594fSAndroid Build Coastguard Worker import java.io.FileReader;
20*795d594fSAndroid Build Coastguard Worker import java.lang.ref.WeakReference;
21*795d594fSAndroid Build Coastguard Worker import java.lang.reflect.Constructor;
22*795d594fSAndroid Build Coastguard Worker import java.lang.reflect.Method;
23*795d594fSAndroid Build Coastguard Worker import java.nio.ByteBuffer;
24*795d594fSAndroid Build Coastguard Worker import java.util.Arrays;
25*795d594fSAndroid Build Coastguard Worker import java.util.function.Consumer;
26*795d594fSAndroid Build Coastguard Worker import java.util.Base64;
27*795d594fSAndroid Build Coastguard Worker 
28*795d594fSAndroid Build Coastguard Worker public class Main {
29*795d594fSAndroid Build Coastguard Worker     static final String DEX_FILE = System.getenv("DEX_LOCATION") + "/141-class-unload-ex.jar";
30*795d594fSAndroid Build Coastguard Worker     static final String LIBRARY_SEARCH_PATH = System.getProperty("java.library.path");
31*795d594fSAndroid Build Coastguard Worker     static String nativeLibraryName;
32*795d594fSAndroid Build Coastguard Worker 
main(String[] args)33*795d594fSAndroid Build Coastguard Worker     public static void main(String[] args) throws Exception {
34*795d594fSAndroid Build Coastguard Worker         nativeLibraryName = args[0];
35*795d594fSAndroid Build Coastguard Worker         Class<?> pathClassLoader = Class.forName("dalvik.system.PathClassLoader");
36*795d594fSAndroid Build Coastguard Worker         if (pathClassLoader == null) {
37*795d594fSAndroid Build Coastguard Worker             throw new AssertionError("Couldn't find path class loader class");
38*795d594fSAndroid Build Coastguard Worker         }
39*795d594fSAndroid Build Coastguard Worker         Constructor<?> constructor =
40*795d594fSAndroid Build Coastguard Worker             pathClassLoader.getDeclaredConstructor(String.class, String.class, ClassLoader.class);
41*795d594fSAndroid Build Coastguard Worker         try {
42*795d594fSAndroid Build Coastguard Worker             testUnloadClass(constructor);
43*795d594fSAndroid Build Coastguard Worker             testUnloadLoader(constructor);
44*795d594fSAndroid Build Coastguard Worker             // Test that we don't unload if we have an instance.
45*795d594fSAndroid Build Coastguard Worker             testNoUnloadInstance(constructor);
46*795d594fSAndroid Build Coastguard Worker             // Test JNI_OnLoad and JNI_OnUnload.
47*795d594fSAndroid Build Coastguard Worker             testLoadAndUnloadLibrary(constructor);
48*795d594fSAndroid Build Coastguard Worker             // Test that stack traces keep the classes live.
49*795d594fSAndroid Build Coastguard Worker             testStackTrace(constructor);
50*795d594fSAndroid Build Coastguard Worker             // Stress test to make sure we dont leak memory.
51*795d594fSAndroid Build Coastguard Worker             stressTest(constructor);
52*795d594fSAndroid Build Coastguard Worker             // Test that the oat files are unloaded.
53*795d594fSAndroid Build Coastguard Worker             testOatFilesUnloaded(getPid());
54*795d594fSAndroid Build Coastguard Worker             // Test that objects keep class loader live for sticky GC.
55*795d594fSAndroid Build Coastguard Worker             testStickyUnload(constructor);
56*795d594fSAndroid Build Coastguard Worker             // Test that copied methods recorded in a stack trace prevents unloading.
57*795d594fSAndroid Build Coastguard Worker             testCopiedMethodInStackTrace(constructor);
58*795d594fSAndroid Build Coastguard Worker             // Test that code preventing unloading holder classes of copied methods recorded in
59*795d594fSAndroid Build Coastguard Worker             // a stack trace does not crash when processing a copied method in the boot class path.
60*795d594fSAndroid Build Coastguard Worker             testCopiedBcpMethodInStackTrace();
61*795d594fSAndroid Build Coastguard Worker             // Test that code preventing unloading holder classes of copied methods recorded in
62*795d594fSAndroid Build Coastguard Worker             // a stack trace does not crash when processing a copied method in an app image.
63*795d594fSAndroid Build Coastguard Worker             testCopiedAppImageMethodInStackTrace();
64*795d594fSAndroid Build Coastguard Worker             // Test that the runtime uses the right allocator when creating conflict methods.
65*795d594fSAndroid Build Coastguard Worker             testConflictMethod(constructor);
66*795d594fSAndroid Build Coastguard Worker             testConflictMethod2(constructor);
67*795d594fSAndroid Build Coastguard Worker         } catch (Exception e) {
68*795d594fSAndroid Build Coastguard Worker             e.printStackTrace(System.out);
69*795d594fSAndroid Build Coastguard Worker         }
70*795d594fSAndroid Build Coastguard Worker     }
71*795d594fSAndroid Build Coastguard Worker 
testOatFilesUnloaded(int pid)72*795d594fSAndroid Build Coastguard Worker     private static void testOatFilesUnloaded(int pid) throws Exception {
73*795d594fSAndroid Build Coastguard Worker         System.loadLibrary(nativeLibraryName);
74*795d594fSAndroid Build Coastguard Worker         // Stop the JIT to ensure its threads and work queue are not keeping classes
75*795d594fSAndroid Build Coastguard Worker         // artifically alive.
76*795d594fSAndroid Build Coastguard Worker         stopJit();
77*795d594fSAndroid Build Coastguard Worker         doUnloading();
78*795d594fSAndroid Build Coastguard Worker         System.runFinalization();
79*795d594fSAndroid Build Coastguard Worker         BufferedReader reader = new BufferedReader(new FileReader ("/proc/" + pid + "/maps"));
80*795d594fSAndroid Build Coastguard Worker         String line;
81*795d594fSAndroid Build Coastguard Worker         int count = 0;
82*795d594fSAndroid Build Coastguard Worker         while ((line = reader.readLine()) != null) {
83*795d594fSAndroid Build Coastguard Worker             if (line.contains("141-class-unload-ex.odex") ||
84*795d594fSAndroid Build Coastguard Worker                 line.contains("141-class-unload-ex.vdex")) {
85*795d594fSAndroid Build Coastguard Worker                 System.out.println(line);
86*795d594fSAndroid Build Coastguard Worker                 ++count;
87*795d594fSAndroid Build Coastguard Worker             }
88*795d594fSAndroid Build Coastguard Worker         }
89*795d594fSAndroid Build Coastguard Worker         System.out.println("Number of loaded unload-ex maps " + count);
90*795d594fSAndroid Build Coastguard Worker         startJit();
91*795d594fSAndroid Build Coastguard Worker     }
92*795d594fSAndroid Build Coastguard Worker 
stressTest(Constructor<?> constructor)93*795d594fSAndroid Build Coastguard Worker     private static void stressTest(Constructor<?> constructor) throws Exception {
94*795d594fSAndroid Build Coastguard Worker         for (int i = 0; i <= 100; ++i) {
95*795d594fSAndroid Build Coastguard Worker             setUpUnloadLoader(constructor, false);
96*795d594fSAndroid Build Coastguard Worker             if (i % 10 == 0) {
97*795d594fSAndroid Build Coastguard Worker                 Runtime.getRuntime().gc();
98*795d594fSAndroid Build Coastguard Worker             }
99*795d594fSAndroid Build Coastguard Worker         }
100*795d594fSAndroid Build Coastguard Worker     }
101*795d594fSAndroid Build Coastguard Worker 
doUnloading()102*795d594fSAndroid Build Coastguard Worker     private static void doUnloading() {
103*795d594fSAndroid Build Coastguard Worker       // Do multiple GCs to prevent rare flakiness if some other thread is keeping the
104*795d594fSAndroid Build Coastguard Worker       // classloader live.
105*795d594fSAndroid Build Coastguard Worker       for (int i = 0; i < 5; ++i) {
106*795d594fSAndroid Build Coastguard Worker          Runtime.getRuntime().gc();
107*795d594fSAndroid Build Coastguard Worker       }
108*795d594fSAndroid Build Coastguard Worker     }
109*795d594fSAndroid Build Coastguard Worker 
testUnloadClass(Constructor<?> constructor)110*795d594fSAndroid Build Coastguard Worker     private static void testUnloadClass(Constructor<?> constructor) throws Exception {
111*795d594fSAndroid Build Coastguard Worker         WeakReference<Class> klass = setUpUnloadClassWeak(constructor);
112*795d594fSAndroid Build Coastguard Worker         // No strong references to class loader, should get unloaded.
113*795d594fSAndroid Build Coastguard Worker         doUnloading();
114*795d594fSAndroid Build Coastguard Worker         WeakReference<Class> klass2 = setUpUnloadClassWeak(constructor);
115*795d594fSAndroid Build Coastguard Worker         doUnloading();
116*795d594fSAndroid Build Coastguard Worker         // If the weak reference is cleared, then it was unloaded.
117*795d594fSAndroid Build Coastguard Worker         System.out.println(klass.get());
118*795d594fSAndroid Build Coastguard Worker         System.out.println(klass2.get());
119*795d594fSAndroid Build Coastguard Worker     }
120*795d594fSAndroid Build Coastguard Worker 
testUnloadLoader(Constructor<?> constructor)121*795d594fSAndroid Build Coastguard Worker     private static void testUnloadLoader(Constructor<?> constructor) throws Exception {
122*795d594fSAndroid Build Coastguard Worker         WeakReference<ClassLoader> loader = setUpUnloadLoader(constructor, true);
123*795d594fSAndroid Build Coastguard Worker         // No strong references to class loader, should get unloaded.
124*795d594fSAndroid Build Coastguard Worker         doUnloading();
125*795d594fSAndroid Build Coastguard Worker         // If the weak reference is cleared, then it was unloaded.
126*795d594fSAndroid Build Coastguard Worker         System.out.println(loader.get());
127*795d594fSAndroid Build Coastguard Worker     }
128*795d594fSAndroid Build Coastguard Worker 
testStackTrace(Constructor<?> constructor)129*795d594fSAndroid Build Coastguard Worker     private static void testStackTrace(Constructor<?> constructor) throws Exception {
130*795d594fSAndroid Build Coastguard Worker         Class<?> klass = setUpUnloadClass(constructor);
131*795d594fSAndroid Build Coastguard Worker         WeakReference<Class> weak_klass = new WeakReference(klass);
132*795d594fSAndroid Build Coastguard Worker         Method stackTraceMethod = klass.getDeclaredMethod("generateStackTrace");
133*795d594fSAndroid Build Coastguard Worker         Throwable throwable = (Throwable) stackTraceMethod.invoke(klass);
134*795d594fSAndroid Build Coastguard Worker         stackTraceMethod = null;
135*795d594fSAndroid Build Coastguard Worker         klass = null;
136*795d594fSAndroid Build Coastguard Worker         doUnloading();
137*795d594fSAndroid Build Coastguard Worker         boolean isNull = weak_klass.get() == null;
138*795d594fSAndroid Build Coastguard Worker         System.out.println("class null " + isNull + " " + throwable.getMessage());
139*795d594fSAndroid Build Coastguard Worker     }
140*795d594fSAndroid Build Coastguard Worker 
testLoadAndUnloadLibrary(Constructor<?> constructor)141*795d594fSAndroid Build Coastguard Worker     private static void testLoadAndUnloadLibrary(Constructor<?> constructor) throws Exception {
142*795d594fSAndroid Build Coastguard Worker         WeakReference<ClassLoader> loader = setUpLoadLibrary(constructor);
143*795d594fSAndroid Build Coastguard Worker         // No strong references to class loader, should get unloaded.
144*795d594fSAndroid Build Coastguard Worker         doUnloading();
145*795d594fSAndroid Build Coastguard Worker         // If the weak reference is cleared, then it was unloaded.
146*795d594fSAndroid Build Coastguard Worker         System.out.println(loader.get());
147*795d594fSAndroid Build Coastguard Worker     }
148*795d594fSAndroid Build Coastguard Worker 
testNoUnloadHelper(ClassLoader loader)149*795d594fSAndroid Build Coastguard Worker     private static Object testNoUnloadHelper(ClassLoader loader) throws Exception {
150*795d594fSAndroid Build Coastguard Worker         Class<?> intHolder = loader.loadClass("IntHolder");
151*795d594fSAndroid Build Coastguard Worker         return intHolder.newInstance();
152*795d594fSAndroid Build Coastguard Worker     }
153*795d594fSAndroid Build Coastguard Worker 
154*795d594fSAndroid Build Coastguard Worker     static class Pair {
Pair(Object o, ClassLoader l)155*795d594fSAndroid Build Coastguard Worker         public Pair(Object o, ClassLoader l) {
156*795d594fSAndroid Build Coastguard Worker             object = o;
157*795d594fSAndroid Build Coastguard Worker             classLoader = new WeakReference<ClassLoader>(l);
158*795d594fSAndroid Build Coastguard Worker         }
159*795d594fSAndroid Build Coastguard Worker 
160*795d594fSAndroid Build Coastguard Worker         public Object object;
161*795d594fSAndroid Build Coastguard Worker         public WeakReference<ClassLoader> classLoader;
162*795d594fSAndroid Build Coastguard Worker     }
163*795d594fSAndroid Build Coastguard Worker 
164*795d594fSAndroid Build Coastguard Worker     // Make the method not inline-able to prevent the compiler optimizing away the allocation.
$noinline$testNoUnloadInstanceHelper(Constructor<?> constructor)165*795d594fSAndroid Build Coastguard Worker     private static Pair $noinline$testNoUnloadInstanceHelper(Constructor<?> constructor)
166*795d594fSAndroid Build Coastguard Worker             throws Exception {
167*795d594fSAndroid Build Coastguard Worker         ClassLoader loader = (ClassLoader) constructor.newInstance(
168*795d594fSAndroid Build Coastguard Worker                 DEX_FILE, LIBRARY_SEARCH_PATH, ClassLoader.getSystemClassLoader());
169*795d594fSAndroid Build Coastguard Worker         Object o = testNoUnloadHelper(loader);
170*795d594fSAndroid Build Coastguard Worker         return new Pair(o, loader);
171*795d594fSAndroid Build Coastguard Worker     }
172*795d594fSAndroid Build Coastguard Worker 
testNoUnloadInstance(Constructor<?> constructor)173*795d594fSAndroid Build Coastguard Worker     private static void testNoUnloadInstance(Constructor<?> constructor) throws Exception {
174*795d594fSAndroid Build Coastguard Worker         Pair p = $noinline$testNoUnloadInstanceHelper(constructor);
175*795d594fSAndroid Build Coastguard Worker         doUnloading();
176*795d594fSAndroid Build Coastguard Worker         boolean isNull = p.classLoader.get() == null;
177*795d594fSAndroid Build Coastguard Worker         System.out.println("loader null " + isNull);
178*795d594fSAndroid Build Coastguard Worker     }
179*795d594fSAndroid Build Coastguard Worker 
setUpUnloadClass(Constructor<?> constructor)180*795d594fSAndroid Build Coastguard Worker     private static Class<?> setUpUnloadClass(Constructor<?> constructor) throws Exception {
181*795d594fSAndroid Build Coastguard Worker         ClassLoader loader = (ClassLoader) constructor.newInstance(
182*795d594fSAndroid Build Coastguard Worker                 DEX_FILE, LIBRARY_SEARCH_PATH, ClassLoader.getSystemClassLoader());
183*795d594fSAndroid Build Coastguard Worker         Class<?> intHolder = loader.loadClass("IntHolder");
184*795d594fSAndroid Build Coastguard Worker         Method getValue = intHolder.getDeclaredMethod("getValue");
185*795d594fSAndroid Build Coastguard Worker         Method setValue = intHolder.getDeclaredMethod("setValue", Integer.TYPE);
186*795d594fSAndroid Build Coastguard Worker         // Make sure we don't accidentally preserve the value in the int holder, the class
187*795d594fSAndroid Build Coastguard Worker         // initializer should be re-run.
188*795d594fSAndroid Build Coastguard Worker         System.out.println((int) getValue.invoke(intHolder));
189*795d594fSAndroid Build Coastguard Worker         setValue.invoke(intHolder, 2);
190*795d594fSAndroid Build Coastguard Worker         System.out.println((int) getValue.invoke(intHolder));
191*795d594fSAndroid Build Coastguard Worker         waitForCompilation(intHolder);
192*795d594fSAndroid Build Coastguard Worker         return intHolder;
193*795d594fSAndroid Build Coastguard Worker     }
194*795d594fSAndroid Build Coastguard Worker 
allocObjectInOtherClassLoader(Constructor<?> constructor)195*795d594fSAndroid Build Coastguard Worker     private static Object allocObjectInOtherClassLoader(Constructor<?> constructor)
196*795d594fSAndroid Build Coastguard Worker             throws Exception {
197*795d594fSAndroid Build Coastguard Worker       ClassLoader loader = (ClassLoader) constructor.newInstance(
198*795d594fSAndroid Build Coastguard Worker               DEX_FILE, LIBRARY_SEARCH_PATH, ClassLoader.getSystemClassLoader());
199*795d594fSAndroid Build Coastguard Worker       return loader.loadClass("IntHolder").newInstance();
200*795d594fSAndroid Build Coastguard Worker     }
201*795d594fSAndroid Build Coastguard Worker 
202*795d594fSAndroid Build Coastguard Worker     // Regression test for public issue 227182.
testStickyUnload(Constructor<?> constructor)203*795d594fSAndroid Build Coastguard Worker     private static void testStickyUnload(Constructor<?> constructor) throws Exception {
204*795d594fSAndroid Build Coastguard Worker         String s = "";
205*795d594fSAndroid Build Coastguard Worker         for (int i = 0; i < 10; ++i) {
206*795d594fSAndroid Build Coastguard Worker             s = "";
207*795d594fSAndroid Build Coastguard Worker             // The object is the only thing preventing the class loader from being unloaded.
208*795d594fSAndroid Build Coastguard Worker             Object o = allocObjectInOtherClassLoader(constructor);
209*795d594fSAndroid Build Coastguard Worker             for (int j = 0; j < 1000; ++j) {
210*795d594fSAndroid Build Coastguard Worker                 s += j + " ";
211*795d594fSAndroid Build Coastguard Worker             }
212*795d594fSAndroid Build Coastguard Worker             // Make sure the object still has a valid class (hasn't been incorrectly unloaded).
213*795d594fSAndroid Build Coastguard Worker             s += o.getClass().getName();
214*795d594fSAndroid Build Coastguard Worker             o = null;
215*795d594fSAndroid Build Coastguard Worker         }
216*795d594fSAndroid Build Coastguard Worker         System.out.println("Too small " + (s.length() < 1000));
217*795d594fSAndroid Build Coastguard Worker     }
218*795d594fSAndroid Build Coastguard Worker 
assertStackTraceContains(Throwable t, String className, String methodName)219*795d594fSAndroid Build Coastguard Worker     private static void assertStackTraceContains(Throwable t, String className, String methodName) {
220*795d594fSAndroid Build Coastguard Worker         boolean found = false;
221*795d594fSAndroid Build Coastguard Worker         for (StackTraceElement e : t.getStackTrace()) {
222*795d594fSAndroid Build Coastguard Worker             if (className.equals(e.getClassName()) && methodName.equals(e.getMethodName())) {
223*795d594fSAndroid Build Coastguard Worker                 found = true;
224*795d594fSAndroid Build Coastguard Worker                 break;
225*795d594fSAndroid Build Coastguard Worker             }
226*795d594fSAndroid Build Coastguard Worker         }
227*795d594fSAndroid Build Coastguard Worker         if (!found) {
228*795d594fSAndroid Build Coastguard Worker             throw new Error("Did not find " + className + "." + methodName);
229*795d594fSAndroid Build Coastguard Worker         }
230*795d594fSAndroid Build Coastguard Worker     }
231*795d594fSAndroid Build Coastguard Worker 
$noinline$callAllMethods(ConflictIface iface)232*795d594fSAndroid Build Coastguard Worker     private static void $noinline$callAllMethods(ConflictIface iface) {
233*795d594fSAndroid Build Coastguard Worker         // Call all methods in the interface to make sure we hit conflicts in the IMT.
234*795d594fSAndroid Build Coastguard Worker         iface.method1();
235*795d594fSAndroid Build Coastguard Worker         iface.method2();
236*795d594fSAndroid Build Coastguard Worker         iface.method3();
237*795d594fSAndroid Build Coastguard Worker         iface.method4();
238*795d594fSAndroid Build Coastguard Worker         iface.method5();
239*795d594fSAndroid Build Coastguard Worker         iface.method6();
240*795d594fSAndroid Build Coastguard Worker         iface.method7();
241*795d594fSAndroid Build Coastguard Worker         iface.method8();
242*795d594fSAndroid Build Coastguard Worker         iface.method9();
243*795d594fSAndroid Build Coastguard Worker         iface.method10();
244*795d594fSAndroid Build Coastguard Worker         iface.method11();
245*795d594fSAndroid Build Coastguard Worker         iface.method12();
246*795d594fSAndroid Build Coastguard Worker         iface.method13();
247*795d594fSAndroid Build Coastguard Worker         iface.method14();
248*795d594fSAndroid Build Coastguard Worker         iface.method15();
249*795d594fSAndroid Build Coastguard Worker         iface.method16();
250*795d594fSAndroid Build Coastguard Worker         iface.method17();
251*795d594fSAndroid Build Coastguard Worker         iface.method18();
252*795d594fSAndroid Build Coastguard Worker         iface.method19();
253*795d594fSAndroid Build Coastguard Worker         iface.method20();
254*795d594fSAndroid Build Coastguard Worker         iface.method21();
255*795d594fSAndroid Build Coastguard Worker         iface.method22();
256*795d594fSAndroid Build Coastguard Worker         iface.method23();
257*795d594fSAndroid Build Coastguard Worker         iface.method24();
258*795d594fSAndroid Build Coastguard Worker         iface.method25();
259*795d594fSAndroid Build Coastguard Worker         iface.method26();
260*795d594fSAndroid Build Coastguard Worker         iface.method27();
261*795d594fSAndroid Build Coastguard Worker         iface.method28();
262*795d594fSAndroid Build Coastguard Worker         iface.method29();
263*795d594fSAndroid Build Coastguard Worker         iface.method30();
264*795d594fSAndroid Build Coastguard Worker         iface.method31();
265*795d594fSAndroid Build Coastguard Worker         iface.method32();
266*795d594fSAndroid Build Coastguard Worker         iface.method33();
267*795d594fSAndroid Build Coastguard Worker         iface.method34();
268*795d594fSAndroid Build Coastguard Worker         iface.method35();
269*795d594fSAndroid Build Coastguard Worker         iface.method36();
270*795d594fSAndroid Build Coastguard Worker         iface.method37();
271*795d594fSAndroid Build Coastguard Worker         iface.method38();
272*795d594fSAndroid Build Coastguard Worker         iface.method39();
273*795d594fSAndroid Build Coastguard Worker         iface.method40();
274*795d594fSAndroid Build Coastguard Worker         iface.method41();
275*795d594fSAndroid Build Coastguard Worker         iface.method42();
276*795d594fSAndroid Build Coastguard Worker         iface.method43();
277*795d594fSAndroid Build Coastguard Worker         iface.method44();
278*795d594fSAndroid Build Coastguard Worker         iface.method45();
279*795d594fSAndroid Build Coastguard Worker         iface.method46();
280*795d594fSAndroid Build Coastguard Worker         iface.method47();
281*795d594fSAndroid Build Coastguard Worker         iface.method48();
282*795d594fSAndroid Build Coastguard Worker         iface.method49();
283*795d594fSAndroid Build Coastguard Worker         iface.method50();
284*795d594fSAndroid Build Coastguard Worker         iface.method51();
285*795d594fSAndroid Build Coastguard Worker         iface.method52();
286*795d594fSAndroid Build Coastguard Worker         iface.method53();
287*795d594fSAndroid Build Coastguard Worker         iface.method54();
288*795d594fSAndroid Build Coastguard Worker         iface.method55();
289*795d594fSAndroid Build Coastguard Worker         iface.method56();
290*795d594fSAndroid Build Coastguard Worker         iface.method57();
291*795d594fSAndroid Build Coastguard Worker         iface.method58();
292*795d594fSAndroid Build Coastguard Worker         iface.method59();
293*795d594fSAndroid Build Coastguard Worker         iface.method60();
294*795d594fSAndroid Build Coastguard Worker         iface.method61();
295*795d594fSAndroid Build Coastguard Worker         iface.method62();
296*795d594fSAndroid Build Coastguard Worker         iface.method63();
297*795d594fSAndroid Build Coastguard Worker         iface.method64();
298*795d594fSAndroid Build Coastguard Worker         iface.method65();
299*795d594fSAndroid Build Coastguard Worker         iface.method66();
300*795d594fSAndroid Build Coastguard Worker         iface.method67();
301*795d594fSAndroid Build Coastguard Worker         iface.method68();
302*795d594fSAndroid Build Coastguard Worker         iface.method69();
303*795d594fSAndroid Build Coastguard Worker         iface.method70();
304*795d594fSAndroid Build Coastguard Worker         iface.method71();
305*795d594fSAndroid Build Coastguard Worker         iface.method72();
306*795d594fSAndroid Build Coastguard Worker         iface.method73();
307*795d594fSAndroid Build Coastguard Worker         iface.method74();
308*795d594fSAndroid Build Coastguard Worker         iface.method75();
309*795d594fSAndroid Build Coastguard Worker         iface.method76();
310*795d594fSAndroid Build Coastguard Worker         iface.method77();
311*795d594fSAndroid Build Coastguard Worker         iface.method78();
312*795d594fSAndroid Build Coastguard Worker         iface.method79();
313*795d594fSAndroid Build Coastguard Worker     }
314*795d594fSAndroid Build Coastguard Worker 
$noinline$invokeConflictMethod(Constructor<?> constructor)315*795d594fSAndroid Build Coastguard Worker     private static void $noinline$invokeConflictMethod(Constructor<?> constructor)
316*795d594fSAndroid Build Coastguard Worker             throws Exception {
317*795d594fSAndroid Build Coastguard Worker         ClassLoader loader = (ClassLoader) constructor.newInstance(
318*795d594fSAndroid Build Coastguard Worker                 DEX_FILE, LIBRARY_SEARCH_PATH, ClassLoader.getSystemClassLoader());
319*795d594fSAndroid Build Coastguard Worker         Class<?> impl = loader.loadClass("ConflictImpl");
320*795d594fSAndroid Build Coastguard Worker         ConflictIface iface = (ConflictIface) impl.newInstance();
321*795d594fSAndroid Build Coastguard Worker         $noinline$callAllMethods(iface);
322*795d594fSAndroid Build Coastguard Worker     }
323*795d594fSAndroid Build Coastguard Worker 
testConflictMethod(Constructor<?> constructor)324*795d594fSAndroid Build Coastguard Worker     private static void testConflictMethod(Constructor<?> constructor) throws Exception {
325*795d594fSAndroid Build Coastguard Worker         // Load and unload a few class loaders to force re-use of the native memory where we
326*795d594fSAndroid Build Coastguard Worker         // used to allocate the conflict table.
327*795d594fSAndroid Build Coastguard Worker         for (int i = 0; i < 2; i++) {
328*795d594fSAndroid Build Coastguard Worker             $noinline$invokeConflictMethod(constructor);
329*795d594fSAndroid Build Coastguard Worker             doUnloading();
330*795d594fSAndroid Build Coastguard Worker         }
331*795d594fSAndroid Build Coastguard Worker         Class<?> impl = Class.forName("ConflictSuper");
332*795d594fSAndroid Build Coastguard Worker         ConflictIface iface = (ConflictIface) impl.newInstance();
333*795d594fSAndroid Build Coastguard Worker         $noinline$callAllMethods(iface);
334*795d594fSAndroid Build Coastguard Worker     }
335*795d594fSAndroid Build Coastguard Worker 
$noinline$invokeConflictMethod2(Constructor<?> constructor)336*795d594fSAndroid Build Coastguard Worker     private static void $noinline$invokeConflictMethod2(Constructor<?> constructor)
337*795d594fSAndroid Build Coastguard Worker             throws Exception {
338*795d594fSAndroid Build Coastguard Worker         // We need three class loaders to expose the issue: the main one with the top super class,
339*795d594fSAndroid Build Coastguard Worker         // then a second one with the abstract class which we used to wrongly return as an IMT
340*795d594fSAndroid Build Coastguard Worker         // owner, and the concrete class in a different class loader.
341*795d594fSAndroid Build Coastguard Worker         Class<?> cls = Class.forName("dalvik.system.InMemoryDexClassLoader");
342*795d594fSAndroid Build Coastguard Worker         Constructor<?> inMemoryConstructor =
343*795d594fSAndroid Build Coastguard Worker                 cls.getDeclaredConstructor(ByteBuffer.class, ClassLoader.class);
344*795d594fSAndroid Build Coastguard Worker         ClassLoader inMemoryLoader = (ClassLoader) inMemoryConstructor.newInstance(
345*795d594fSAndroid Build Coastguard Worker                 ByteBuffer.wrap(DEX_BYTES), ClassLoader.getSystemClassLoader());
346*795d594fSAndroid Build Coastguard Worker         ClassLoader loader = (ClassLoader) constructor.newInstance(
347*795d594fSAndroid Build Coastguard Worker                 DEX_FILE, LIBRARY_SEARCH_PATH, inMemoryLoader);
348*795d594fSAndroid Build Coastguard Worker         Class<?> impl = loader.loadClass("ConflictImpl2");
349*795d594fSAndroid Build Coastguard Worker         ConflictIface iface = (ConflictIface) impl.newInstance();
350*795d594fSAndroid Build Coastguard Worker         $noinline$callAllMethods(iface);
351*795d594fSAndroid Build Coastguard Worker     }
352*795d594fSAndroid Build Coastguard Worker 
testConflictMethod2(Constructor<?> constructor)353*795d594fSAndroid Build Coastguard Worker     private static void testConflictMethod2(Constructor<?> constructor) throws Exception {
354*795d594fSAndroid Build Coastguard Worker         // Load and unload a few class loaders to force re-use of the native memory where we
355*795d594fSAndroid Build Coastguard Worker         // used to allocate the conflict table.
356*795d594fSAndroid Build Coastguard Worker         for (int i = 0; i < 2; i++) {
357*795d594fSAndroid Build Coastguard Worker             $noinline$invokeConflictMethod2(constructor);
358*795d594fSAndroid Build Coastguard Worker             doUnloading();
359*795d594fSAndroid Build Coastguard Worker         }
360*795d594fSAndroid Build Coastguard Worker         Class<?> impl = Class.forName("ConflictSuper");
361*795d594fSAndroid Build Coastguard Worker         ConflictIface iface = (ConflictIface) impl.newInstance();
362*795d594fSAndroid Build Coastguard Worker         $noinline$callAllMethods(iface);
363*795d594fSAndroid Build Coastguard Worker     }
364*795d594fSAndroid Build Coastguard Worker 
testCopiedMethodInStackTrace(Constructor<?> constructor)365*795d594fSAndroid Build Coastguard Worker     private static void testCopiedMethodInStackTrace(Constructor<?> constructor) throws Exception {
366*795d594fSAndroid Build Coastguard Worker         Throwable t = $noinline$createStackTraceWithCopiedMethod(constructor);
367*795d594fSAndroid Build Coastguard Worker         doUnloading();
368*795d594fSAndroid Build Coastguard Worker         assertStackTraceContains(t, "Iface", "invokeRun");
369*795d594fSAndroid Build Coastguard Worker     }
370*795d594fSAndroid Build Coastguard Worker 
$noinline$createStackTraceWithCopiedMethod(Constructor<?> constructor)371*795d594fSAndroid Build Coastguard Worker     private static Throwable $noinline$createStackTraceWithCopiedMethod(Constructor<?> constructor)
372*795d594fSAndroid Build Coastguard Worker             throws Exception {
373*795d594fSAndroid Build Coastguard Worker       ClassLoader loader = (ClassLoader) constructor.newInstance(
374*795d594fSAndroid Build Coastguard Worker               DEX_FILE, LIBRARY_SEARCH_PATH, Main.class.getClassLoader());
375*795d594fSAndroid Build Coastguard Worker       Iface impl = (Iface) loader.loadClass("Impl").newInstance();
376*795d594fSAndroid Build Coastguard Worker       Runnable throwingRunnable = new Runnable() {
377*795d594fSAndroid Build Coastguard Worker           public void run() {
378*795d594fSAndroid Build Coastguard Worker               throw new Error();
379*795d594fSAndroid Build Coastguard Worker           }
380*795d594fSAndroid Build Coastguard Worker       };
381*795d594fSAndroid Build Coastguard Worker       try {
382*795d594fSAndroid Build Coastguard Worker           impl.invokeRun(throwingRunnable);
383*795d594fSAndroid Build Coastguard Worker           System.out.println("UNREACHABLE");
384*795d594fSAndroid Build Coastguard Worker           return null;
385*795d594fSAndroid Build Coastguard Worker       } catch (Error expected) {
386*795d594fSAndroid Build Coastguard Worker           return expected;
387*795d594fSAndroid Build Coastguard Worker       }
388*795d594fSAndroid Build Coastguard Worker     }
389*795d594fSAndroid Build Coastguard Worker 
testCopiedBcpMethodInStackTrace()390*795d594fSAndroid Build Coastguard Worker     private static void testCopiedBcpMethodInStackTrace() {
391*795d594fSAndroid Build Coastguard Worker         Consumer<Object> consumer = new Consumer<Object>() {
392*795d594fSAndroid Build Coastguard Worker             public void accept(Object o) {
393*795d594fSAndroid Build Coastguard Worker                 throw new Error();
394*795d594fSAndroid Build Coastguard Worker             }
395*795d594fSAndroid Build Coastguard Worker         };
396*795d594fSAndroid Build Coastguard Worker         Error err = null;
397*795d594fSAndroid Build Coastguard Worker         try {
398*795d594fSAndroid Build Coastguard Worker             Arrays.asList(new Object[] { new Object() }).iterator().forEachRemaining(consumer);
399*795d594fSAndroid Build Coastguard Worker         } catch (Error expected) {
400*795d594fSAndroid Build Coastguard Worker             err = expected;
401*795d594fSAndroid Build Coastguard Worker         }
402*795d594fSAndroid Build Coastguard Worker         assertStackTraceContains(err, "Main", "testCopiedBcpMethodInStackTrace");
403*795d594fSAndroid Build Coastguard Worker     }
404*795d594fSAndroid Build Coastguard Worker 
testCopiedAppImageMethodInStackTrace()405*795d594fSAndroid Build Coastguard Worker     private static void testCopiedAppImageMethodInStackTrace() throws Exception {
406*795d594fSAndroid Build Coastguard Worker         Iface limpl = (Iface) Class.forName("Impl2").newInstance();
407*795d594fSAndroid Build Coastguard Worker         Runnable throwingRunnable = new Runnable() {
408*795d594fSAndroid Build Coastguard Worker             public void run() {
409*795d594fSAndroid Build Coastguard Worker                 throw new Error();
410*795d594fSAndroid Build Coastguard Worker             }
411*795d594fSAndroid Build Coastguard Worker         };
412*795d594fSAndroid Build Coastguard Worker         Error err = null;
413*795d594fSAndroid Build Coastguard Worker         try {
414*795d594fSAndroid Build Coastguard Worker             limpl.invokeRun(throwingRunnable);
415*795d594fSAndroid Build Coastguard Worker         } catch (Error expected) {
416*795d594fSAndroid Build Coastguard Worker             err = expected;
417*795d594fSAndroid Build Coastguard Worker         }
418*795d594fSAndroid Build Coastguard Worker         assertStackTraceContains(err, "Main", "testCopiedAppImageMethodInStackTrace");
419*795d594fSAndroid Build Coastguard Worker     }
420*795d594fSAndroid Build Coastguard Worker 
setUpUnloadClassWeak(Constructor<?> constructor)421*795d594fSAndroid Build Coastguard Worker     private static WeakReference<Class> setUpUnloadClassWeak(Constructor<?> constructor)
422*795d594fSAndroid Build Coastguard Worker             throws Exception {
423*795d594fSAndroid Build Coastguard Worker         return new WeakReference<Class>(setUpUnloadClass(constructor));
424*795d594fSAndroid Build Coastguard Worker     }
425*795d594fSAndroid Build Coastguard Worker 
setUpUnloadLoader(Constructor<?> constructor, boolean waitForCompilation)426*795d594fSAndroid Build Coastguard Worker     private static WeakReference<ClassLoader> setUpUnloadLoader(Constructor<?> constructor,
427*795d594fSAndroid Build Coastguard Worker                                                                 boolean waitForCompilation)
428*795d594fSAndroid Build Coastguard Worker         throws Exception {
429*795d594fSAndroid Build Coastguard Worker         ClassLoader loader = (ClassLoader) constructor.newInstance(
430*795d594fSAndroid Build Coastguard Worker             DEX_FILE, LIBRARY_SEARCH_PATH, ClassLoader.getSystemClassLoader());
431*795d594fSAndroid Build Coastguard Worker         Class<?> intHolder = loader.loadClass("IntHolder");
432*795d594fSAndroid Build Coastguard Worker         Method setValue = intHolder.getDeclaredMethod("setValue", Integer.TYPE);
433*795d594fSAndroid Build Coastguard Worker         setValue.invoke(intHolder, 2);
434*795d594fSAndroid Build Coastguard Worker         if (waitForCompilation) {
435*795d594fSAndroid Build Coastguard Worker             waitForCompilation(intHolder);
436*795d594fSAndroid Build Coastguard Worker         }
437*795d594fSAndroid Build Coastguard Worker         return new WeakReference(loader);
438*795d594fSAndroid Build Coastguard Worker     }
439*795d594fSAndroid Build Coastguard Worker 
waitForCompilation(Class<?> intHolder)440*795d594fSAndroid Build Coastguard Worker     private static void waitForCompilation(Class<?> intHolder) throws Exception {
441*795d594fSAndroid Build Coastguard Worker       // Load the native library so that we can call waitForCompilation.
442*795d594fSAndroid Build Coastguard Worker       Method loadLibrary = intHolder.getDeclaredMethod("loadLibrary", String.class);
443*795d594fSAndroid Build Coastguard Worker       loadLibrary.invoke(intHolder, nativeLibraryName);
444*795d594fSAndroid Build Coastguard Worker       // Wait for JIT compilation to finish since the async threads may prevent unloading.
445*795d594fSAndroid Build Coastguard Worker       Method waitForCompilation = intHolder.getDeclaredMethod("waitForCompilation");
446*795d594fSAndroid Build Coastguard Worker       waitForCompilation.invoke(intHolder);
447*795d594fSAndroid Build Coastguard Worker     }
448*795d594fSAndroid Build Coastguard Worker 
setUpLoadLibrary(Constructor<?> constructor)449*795d594fSAndroid Build Coastguard Worker     private static WeakReference<ClassLoader> setUpLoadLibrary(Constructor<?> constructor)
450*795d594fSAndroid Build Coastguard Worker         throws Exception {
451*795d594fSAndroid Build Coastguard Worker         ClassLoader loader = (ClassLoader) constructor.newInstance(
452*795d594fSAndroid Build Coastguard Worker             DEX_FILE, LIBRARY_SEARCH_PATH, ClassLoader.getSystemClassLoader());
453*795d594fSAndroid Build Coastguard Worker         Class<?> intHolder = loader.loadClass("IntHolder");
454*795d594fSAndroid Build Coastguard Worker         Method loadLibrary = intHolder.getDeclaredMethod("loadLibrary", String.class);
455*795d594fSAndroid Build Coastguard Worker         loadLibrary.invoke(intHolder, nativeLibraryName);
456*795d594fSAndroid Build Coastguard Worker         waitForCompilation(intHolder);
457*795d594fSAndroid Build Coastguard Worker         return new WeakReference(loader);
458*795d594fSAndroid Build Coastguard Worker     }
459*795d594fSAndroid Build Coastguard Worker 
getPid()460*795d594fSAndroid Build Coastguard Worker     private static int getPid() throws Exception {
461*795d594fSAndroid Build Coastguard Worker         return Integer.parseInt(new File("/proc/self").getCanonicalFile().getName());
462*795d594fSAndroid Build Coastguard Worker     }
463*795d594fSAndroid Build Coastguard Worker 
stopJit()464*795d594fSAndroid Build Coastguard Worker     public static native void stopJit();
startJit()465*795d594fSAndroid Build Coastguard Worker     public static native void startJit();
466*795d594fSAndroid Build Coastguard Worker 
467*795d594fSAndroid Build Coastguard Worker 
468*795d594fSAndroid Build Coastguard Worker     /* Corresponds to:
469*795d594fSAndroid Build Coastguard Worker      *
470*795d594fSAndroid Build Coastguard Worker      * public abstract class AbstractClass extends ConflictSuper { }
471*795d594fSAndroid Build Coastguard Worker      *
472*795d594fSAndroid Build Coastguard Worker      */
473*795d594fSAndroid Build Coastguard Worker     private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
474*795d594fSAndroid Build Coastguard Worker         "ZGV4CjAzNQAOZ0WGvUad/2dEp77oyy9K2tx8txklUZ1wAgAAcAAAAHhWNBIAAAAAAAAAANwBAAAG" +
475*795d594fSAndroid Build Coastguard Worker         "AAAAcAAAAAMAAACIAAAAAQAAAJQAAAAAAAAAAAAAAAIAAACgAAAAAQAAALAAAACgAQAA0AAAAOwA" +
476*795d594fSAndroid Build Coastguard Worker         "AAD0AAAACAEAABkBAAAqAQAALQEAAAIAAAADAAAABAAAAAQAAAACAAAAAAAAAAAAAAAAAAAAAQAA" +
477*795d594fSAndroid Build Coastguard Worker         "AAAAAAAAAAAAAQQAAAEAAAAAAAAAAQAAAAAAAADLAQAAAAAAAAEAAQABAAAA6AAAAAQAAABwEAEA" +
478*795d594fSAndroid Build Coastguard Worker         "AAAOABEADgAGPGluaXQ+ABJBYnN0cmFjdENsYXNzLmphdmEAD0xBYnN0cmFjdENsYXNzOwAPTENv" +
479*795d594fSAndroid Build Coastguard Worker         "bmZsaWN0U3VwZXI7AAFWAJsBfn5EOHsiYmFja2VuZCI6ImRleCIsImNvbXBpbGF0aW9uLW1vZGUi" +
480*795d594fSAndroid Build Coastguard Worker         "OiJkZWJ1ZyIsImhhcy1jaGVja3N1bXMiOmZhbHNlLCJtaW4tYXBpIjoxLCJzaGEtMSI6ImI3MmIx" +
481*795d594fSAndroid Build Coastguard Worker         "NWJjODQ2N2Y0M2FhNTdlYjk5ZDAyMjU0Nzg5ODYwZjRlOWEiLCJ2ZXJzaW9uIjoiOC41LjEtZGV2" +
482*795d594fSAndroid Build Coastguard Worker         "In0AAAABAACBgATQAQAAAAAAAAAMAAAAAAAAAAEAAAAAAAAAAQAAAAYAAABwAAAAAgAAAAMAAACI" +
483*795d594fSAndroid Build Coastguard Worker         "AAAAAwAAAAEAAACUAAAABQAAAAIAAACgAAAABgAAAAEAAACwAAAAASAAAAEAAADQAAAAAyAAAAEA" +
484*795d594fSAndroid Build Coastguard Worker         "AADoAAAAAiAAAAYAAADsAAAAACAAAAEAAADLAQAAAxAAAAEAAADYAQAAABAAAAEAAADcAQAA");
485*795d594fSAndroid Build Coastguard Worker }
486