1 /* 2 * Copyright (C) 2018 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.lang.ref.WeakReference; 18 import java.lang.reflect.InvocationHandler; 19 import java.lang.reflect.Constructor; 20 import java.lang.reflect.Method; 21 22 public class Main { 23 static final String DEX_FILE = System.getenv("DEX_LOCATION") + "/616-cha-unloading-ex.jar"; 24 static final String LIBRARY_SEARCH_PATH = System.getProperty("java.library.path"); 25 static Constructor<? extends ClassLoader> sConstructor; 26 27 private static class CHAUnloaderRetType { CHAUnloaderRetType(WeakReference<ClassLoader> cl, AbstractCHATester obj, long methodPtr)28 private CHAUnloaderRetType(WeakReference<ClassLoader> cl, 29 AbstractCHATester obj, 30 long methodPtr) { 31 this.cl = cl; 32 this.obj = obj; 33 this.methodPtr = methodPtr; 34 } 35 public WeakReference<ClassLoader> cl; 36 public AbstractCHATester obj; 37 public long methodPtr; 38 } 39 main(String[] args)40 public static void main(String[] args) throws Exception { 41 System.loadLibrary(args[0]); 42 43 Class<ClassLoader> pathClassLoader = (Class<ClassLoader>) Class.forName("dalvik.system.PathClassLoader"); 44 sConstructor = 45 pathClassLoader.getDeclaredConstructor(String.class, String.class, ClassLoader.class); 46 47 testUnload(); 48 } 49 testUnload()50 private static void testUnload() throws Exception { 51 // Load a concrete class, then unload it. Get a deleted ArtMethod to test if it'll be inlined. 52 CHAUnloaderRetType result = doUnloadLoader(); 53 WeakReference<ClassLoader> loader = result.cl; 54 long methodPtr = result.methodPtr; 55 // Check that the classloader is indeed unloaded. 56 if (loader.get() != null) { 57 throw new Error("Expected class loader to be unloaded"); 58 } 59 60 // Reuse the linear alloc used by the unloaded class loader. 61 reuseArenaOfMethod(methodPtr); 62 63 // Try to JIT-compile under dangerous conditions. 64 ensureJitCompiled(Main.class, "targetMethodForJit"); 65 System.out.println("Done"); 66 } 67 doUnloading()68 private static void doUnloading() { 69 // Do multiple GCs to prevent rare flakiness if some other thread is keeping the 70 // classloader live. 71 for (int i = 0; i < 5; ++i) { 72 Runtime.getRuntime().gc(); 73 } 74 } 75 setupLoader()76 private static CHAUnloaderRetType setupLoader() 77 throws Exception { 78 ClassLoader loader = sConstructor.newInstance( 79 DEX_FILE, LIBRARY_SEARCH_PATH, ClassLoader.getSystemClassLoader()); 80 Class<?> concreteCHATester = loader.loadClass("ConcreteCHATester"); 81 82 // Preemptively compile methods to prevent delayed JIT tasks from blocking the unloading. 83 ensureJitCompiled(concreteCHATester, "<init>"); 84 ensureJitCompiled(concreteCHATester, "lonelyMethod"); 85 86 Object obj = concreteCHATester.newInstance(); 87 Method lonelyMethod = concreteCHATester.getDeclaredMethod("lonelyMethod"); 88 89 // Get a pointer to a region that shall be not used after the unloading. 90 long artMethod = getArtMethod(lonelyMethod); 91 92 AbstractCHATester ret = null; 93 return new CHAUnloaderRetType(new WeakReference(loader), ret, artMethod); 94 } 95 targetMethodForJit(int mode)96 private static CHAUnloaderRetType targetMethodForJit(int mode) 97 throws Exception { 98 CHAUnloaderRetType ret = new CHAUnloaderRetType(null, null, 0); 99 if (mode == 0) { 100 ret = setupLoader(); 101 } else if (mode == 1) { 102 // This branch is not supposed to be executed. It shall trigger "lonelyMethod" inlining 103 // during jit compilation of "targetMethodForJit". 104 ret = setupLoader(); 105 AbstractCHATester obj = ret.obj; 106 obj.lonelyMethod(); 107 } 108 return ret; 109 } 110 doUnloadLoader()111 private static CHAUnloaderRetType doUnloadLoader() 112 throws Exception { 113 CHAUnloaderRetType result = targetMethodForJit(0); 114 doUnloading(); 115 return result; 116 } 117 ensureJitCompiled(Class<?> itf, String method_name)118 private static native void ensureJitCompiled(Class<?> itf, String method_name); getArtMethod(Object javaMethod)119 private static native long getArtMethod(Object javaMethod); reuseArenaOfMethod(long artMethod)120 private static native void reuseArenaOfMethod(long artMethod); 121 } 122