| /* |
| * Copyright (C) 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| import java.lang.ref.WeakReference; |
| import java.lang.reflect.InvocationHandler; |
| import java.lang.reflect.Constructor; |
| import java.lang.reflect.Method; |
| |
| public class Main { |
| static final String DEX_FILE = System.getenv("DEX_LOCATION") + "/616-cha-unloading-ex.jar"; |
| static final String LIBRARY_SEARCH_PATH = System.getProperty("java.library.path"); |
| static Constructor<? extends ClassLoader> sConstructor; |
| |
| private static class CHAUnloaderRetType { |
| private CHAUnloaderRetType(WeakReference<ClassLoader> cl, |
| AbstractCHATester obj, |
| long methodPtr) { |
| this.cl = cl; |
| this.obj = obj; |
| this.methodPtr = methodPtr; |
| } |
| public WeakReference<ClassLoader> cl; |
| public AbstractCHATester obj; |
| public long methodPtr; |
| } |
| |
| public static void main(String[] args) throws Exception { |
| System.loadLibrary(args[0]); |
| |
| Class<ClassLoader> pathClassLoader = (Class<ClassLoader>) Class.forName("dalvik.system.PathClassLoader"); |
| sConstructor = |
| pathClassLoader.getDeclaredConstructor(String.class, String.class, ClassLoader.class); |
| |
| testUnload(); |
| } |
| |
| private static void testUnload() throws Exception { |
| // Load a concrete class, then unload it. Get a deleted ArtMethod to test if it'll be inlined. |
| CHAUnloaderRetType result = doUnloadLoader(); |
| WeakReference<ClassLoader> loader = result.cl; |
| long methodPtr = result.methodPtr; |
| // Check that the classloader is indeed unloaded. |
| if (loader.get() != null) { |
| throw new Error("Expected class loader to be unloaded"); |
| } |
| |
| // Reuse the linear alloc used by the unloaded class loader. |
| reuseArenaOfMethod(methodPtr); |
| |
| // Try to JIT-compile under dangerous conditions. |
| ensureJitCompiled(Main.class, "targetMethodForJit"); |
| System.out.println("Done"); |
| } |
| |
| private static void doUnloading() { |
| // Do multiple GCs to prevent rare flakiness if some other thread is keeping the |
| // classloader live. |
| for (int i = 0; i < 5; ++i) { |
| Runtime.getRuntime().gc(); |
| } |
| } |
| |
| private static CHAUnloaderRetType setupLoader() |
| throws Exception { |
| ClassLoader loader = sConstructor.newInstance( |
| DEX_FILE, LIBRARY_SEARCH_PATH, ClassLoader.getSystemClassLoader()); |
| Class<?> concreteCHATester = loader.loadClass("ConcreteCHATester"); |
| |
| // Preemptively compile methods to prevent delayed JIT tasks from blocking the unloading. |
| ensureJitCompiled(concreteCHATester, "<init>"); |
| ensureJitCompiled(concreteCHATester, "lonelyMethod"); |
| |
| Object obj = concreteCHATester.newInstance(); |
| Method lonelyMethod = concreteCHATester.getDeclaredMethod("lonelyMethod"); |
| |
| // Get a pointer to a region that shall be not used after the unloading. |
| long artMethod = getArtMethod(lonelyMethod); |
| |
| AbstractCHATester ret = null; |
| return new CHAUnloaderRetType(new WeakReference(loader), ret, artMethod); |
| } |
| |
| private static CHAUnloaderRetType targetMethodForJit(int mode) |
| throws Exception { |
| CHAUnloaderRetType ret = new CHAUnloaderRetType(null, null, 0); |
| if (mode == 0) { |
| ret = setupLoader(); |
| } else if (mode == 1) { |
| // This branch is not supposed to be executed. It shall trigger "lonelyMethod" inlining |
| // during jit compilation of "targetMethodForJit". |
| ret = setupLoader(); |
| AbstractCHATester obj = ret.obj; |
| obj.lonelyMethod(); |
| } |
| return ret; |
| } |
| |
| private static CHAUnloaderRetType doUnloadLoader() |
| throws Exception { |
| CHAUnloaderRetType result = targetMethodForJit(0); |
| doUnloading(); |
| return result; |
| } |
| |
| private static native void ensureJitCompiled(Class<?> itf, String method_name); |
| private static native long getArtMethod(Object javaMethod); |
| private static native void reuseArenaOfMethod(long artMethod); |
| } |