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