1 /* 2 * Copyright (C) 2019 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 dalvik.system.PathClassLoader; 18 import dalvik.system.VMRuntime; 19 20 import java.lang.ref.WeakReference; 21 import java.lang.reflect.Constructor; 22 import java.util.concurrent.atomic.AtomicBoolean; 23 24 public class Main { 25 static final String DEX_FILE = System.getenv("DEX_LOCATION") + "/1002-notify-startup.jar"; 26 static final String LIBRARY_SEARCH_PATH = System.getProperty("java.library.path"); 27 static AtomicBoolean completed = new AtomicBoolean(false); 28 assertFalse(boolean value)29 public static void assertFalse(boolean value) { 30 if (value) { 31 throw new Error("Expected false false"); 32 } 33 } 34 main(String[] args)35 public static void main(String[] args) { 36 System.loadLibrary(args[0]); 37 assertFalse(hasStartupCompleted()); 38 39 Thread workerThread = new WorkerThread(); 40 workerThread.start(); 41 do { 42 resetStartupCompleted(); 43 VMRuntime.getRuntime().notifyStartupCompleted(); 44 Thread.yield(); 45 } while (!completed.get()); 46 try { 47 workerThread.join(); 48 } catch (Throwable e) { 49 System.err.println(e); 50 } 51 while (!hasStartupCompleted()) { 52 Thread.yield(); 53 } 54 } 55 56 private static class WorkerThread extends Thread { 57 static final int NUM_ITERATIONS = 100; 58 $noinline$loadClassInLoader()59 private WeakReference<Class<?>> $noinline$loadClassInLoader() throws Exception { 60 ClassLoader loader = new PathClassLoader( 61 DEX_FILE, LIBRARY_SEARCH_PATH, Object.class.getClassLoader()); 62 Class ret = loader.loadClass("Main"); 63 return new WeakReference(ret); 64 } 65 run()66 public void run() { 67 for (int i = 0; i < NUM_ITERATIONS; ++i) { 68 try { 69 WeakReference<Class<?>> ref = $noinline$loadClassInLoader(); 70 Runtime.getRuntime().gc(); 71 Thread.yield(); 72 // Don't validate the unloading since app images will keep classes live (for now). 73 } catch (Throwable e) { 74 System.err.println(e); 75 break; 76 } 77 } 78 completed.set(true); 79 } 80 } 81 hasStartupCompleted()82 private static native boolean hasStartupCompleted(); resetStartupCompleted()83 private static native void resetStartupCompleted(); 84 } 85