1 /* 2 * Copyright (C) 2016 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.Field; 19 import java.lang.reflect.InvocationTargetException; 20 import java.lang.reflect.Method; 21 import java.util.ArrayList; 22 23 public class Main { main(String[] args)24 public static void main(String[] args) throws Exception { 25 try { 26 // Check if we're running dalvik or RI. 27 Class<?> class_loader_class = Class.forName("dalvik.system.PathClassLoader"); 28 System.loadLibrary(args[0]); 29 } catch (ClassNotFoundException e) { 30 usingRI = true; 31 // Add expected JNI_OnLoad log line to match expected-stdout.txt. 32 System.out.println("JNI_OnLoad called"); 33 } 34 35 testClearDexCache(); 36 testMultiDex(); 37 testRacyLoader(); 38 testRacyLoader2(); 39 testMisbehavingLoader(); 40 testRacyMisbehavingLoader(); 41 testRacyMisbehavingLoader2(); 42 } 43 testClearDexCache()44 private static void testClearDexCache() throws Exception { 45 DelegatingLoader delegating_loader = createDelegatingLoader(); 46 Class<?> helper = delegating_loader.loadClass("Helper1"); 47 48 WeakReference<Class<?>> weak_test1 = wrapHelperGet(helper); 49 changeInner(delegating_loader); 50 clearResolvedTypes(helper); 51 Runtime.getRuntime().gc(); 52 WeakReference<Class<?>> weak_test2 = wrapHelperGet(helper); 53 Runtime.getRuntime().gc(); 54 55 Class<?> test1 = weak_test1.get(); 56 if (test1 == null) { 57 System.out.println("test1 disappeared"); 58 } 59 Class<?> test2 = weak_test2.get(); 60 if (test2 == null) { 61 System.out.println("test2 disappeared"); 62 } 63 if (test1 != test2) { 64 System.out.println("test1 != test2"); 65 } 66 67 System.out.println("testClearDexCache done"); 68 } 69 testMultiDex()70 private static void testMultiDex() throws Exception { 71 DelegatingLoader delegating_loader = createDelegatingLoader(); 72 73 Class<?> helper1 = delegating_loader.loadClass("Helper1"); 74 WeakReference<Class<?>> weak_test1 = wrapHelperGet(helper1); 75 76 changeInner(delegating_loader); 77 78 Class<?> helper2 = delegating_loader.loadClass("Helper2"); 79 WeakReference<Class<?>> weak_test2 = wrapHelperGet(helper2); 80 81 Runtime.getRuntime().gc(); 82 83 Class<?> test1 = weak_test1.get(); 84 if (test1 == null) { 85 System.out.println("test1 disappeared"); 86 } 87 Class<?> test2 = weak_test2.get(); 88 if (test2 == null) { 89 System.out.println("test2 disappeared"); 90 } 91 if (test1 != test2) { 92 System.out.println("test1 != test2"); 93 } 94 95 System.out.println("testMultiDex done"); 96 } 97 testMisbehavingLoader()98 private static void testMisbehavingLoader() throws Exception { 99 ClassLoader system_loader = ClassLoader.getSystemClassLoader(); 100 DefiningLoader defining_loader = new DefiningLoader(system_loader); 101 MisbehavingLoader misbehaving_loader = 102 new MisbehavingLoader(system_loader, defining_loader); 103 Class<?> helper = misbehaving_loader.loadClass("Helper1"); 104 105 try { 106 WeakReference<Class<?>> weak_test = wrapHelperGet(helper); 107 } catch (InvocationTargetException ite) { 108 String message = ite.getCause().getMessage(); 109 if (usingRI && "Test".equals(message)) { 110 // Replace RI message with dalvik message to match expected-stdout.txt. 111 message = "Initiating class loader of type " + 112 misbehaving_loader.getClass().getName() + 113 " returned class Helper2 instead of Test."; 114 } 115 System.out.println(ite.getCause().getClass().getName() + ": " + message); 116 } 117 System.out.println("testMisbehavingLoader done"); 118 } 119 testRacyLoader()120 private static void testRacyLoader() throws Exception { 121 final ClassLoader system_loader = ClassLoader.getSystemClassLoader(); 122 123 final Thread[] threads = new Thread[4]; 124 final Object[] results = new Object[threads.length]; 125 126 final RacyLoader racy_loader = new RacyLoader(system_loader, threads.length); 127 final Class<?> helper1 = racy_loader.loadClass("Helper1"); 128 skipVerification(helper1); // Avoid class loading during verification. 129 130 for (int i = 0; i != threads.length; ++i) { 131 final int my_index = i; 132 Thread t = new Thread() { 133 public void run() { 134 try { 135 Method get = helper1.getDeclaredMethod("get"); 136 results[my_index] = get.invoke(null); 137 } catch (InvocationTargetException ite) { 138 results[my_index] = ite.getCause(); 139 } catch (Throwable t) { 140 results[my_index] = t; 141 } 142 } 143 }; 144 t.start(); 145 threads[i] = t; 146 } 147 for (Thread t : threads) { 148 t.join(); 149 } 150 dumpResultStats(results, 1); 151 System.out.println("testRacyLoader done"); 152 } 153 testRacyLoader2()154 private static void testRacyLoader2() throws Exception { 155 final ClassLoader system_loader = ClassLoader.getSystemClassLoader(); 156 157 final Thread[] threads = new Thread[4]; 158 final Object[] results = new Object[threads.length]; 159 160 final RacyLoader racy_loader = new RacyLoader(system_loader, threads.length); 161 final Class<?> helper1 = racy_loader.loadClass("Helper1"); 162 skipVerification(helper1); // Avoid class loading during verification. 163 final Class<?> helper3 = racy_loader.loadClass("Helper3"); 164 skipVerification(helper3); // Avoid class loading during verification. 165 166 for (int i = 0; i != threads.length; ++i) { 167 final int my_index = i; 168 Thread t = new Thread() { 169 public void run() { 170 try { 171 Class<?> helper = (my_index < threads.length / 2) ? helper1 : helper3; 172 Method get = helper.getDeclaredMethod("get"); 173 results[my_index] = get.invoke(null); 174 } catch (InvocationTargetException ite) { 175 results[my_index] = ite.getCause(); 176 } catch (Throwable t) { 177 results[my_index] = t; 178 } 179 } 180 }; 181 t.start(); 182 threads[i] = t; 183 } 184 for (Thread t : threads) { 185 t.join(); 186 } 187 dumpResultStats(results, 2); 188 System.out.println("testRacyLoader2 done"); 189 } 190 testRacyMisbehavingLoader()191 private static void testRacyMisbehavingLoader() throws Exception { 192 final ClassLoader system_loader = ClassLoader.getSystemClassLoader(); 193 194 final Thread[] threads = new Thread[4]; 195 final Object[] results = new Object[threads.length]; 196 197 final RacyMisbehavingLoader racy_loader = 198 new RacyMisbehavingLoader(system_loader, threads.length, false); 199 final Class<?> helper1 = racy_loader.loadClass("RacyMisbehavingHelper"); 200 skipVerification(helper1); // Avoid class loading during verification. 201 202 for (int i = 0; i != threads.length; ++i) { 203 final int my_index = i; 204 Thread t = new Thread() { 205 public void run() { 206 try { 207 Method get = helper1.getDeclaredMethod("get"); 208 results[my_index] = get.invoke(null); 209 } catch (InvocationTargetException ite) { 210 results[my_index] = ite.getCause(); 211 } catch (Throwable t) { 212 results[my_index] = t; 213 } 214 } 215 }; 216 t.start(); 217 threads[i] = t; 218 } 219 for (Thread t : threads) { 220 t.join(); 221 } 222 dumpResultStats(results, 1); 223 System.out.println("testRacyMisbehavingLoader done"); 224 } 225 testRacyMisbehavingLoader2()226 private static void testRacyMisbehavingLoader2() throws Exception { 227 final ClassLoader system_loader = ClassLoader.getSystemClassLoader(); 228 229 final Thread[] threads = new Thread[4]; 230 final Object[] results = new Object[threads.length]; 231 232 final RacyMisbehavingLoader racy_loader = 233 new RacyMisbehavingLoader(system_loader, threads.length, true); 234 final Class<?> helper1 = racy_loader.loadClass("RacyMisbehavingHelper"); 235 skipVerification(helper1); // Avoid class loading during verification. 236 237 for (int i = 0; i != threads.length; ++i) { 238 final int my_index = i; 239 Thread t = new Thread() { 240 public void run() { 241 try { 242 Method get = helper1.getDeclaredMethod("get"); 243 results[my_index] = get.invoke(null); 244 } catch (InvocationTargetException ite) { 245 results[my_index] = ite.getCause(); 246 } catch (Throwable t) { 247 results[my_index] = t; 248 } 249 } 250 }; 251 t.start(); 252 threads[i] = t; 253 } 254 for (Thread t : threads) { 255 t.join(); 256 } 257 dumpResultStats(results, 1); 258 System.out.println("testRacyMisbehavingLoader2 done"); 259 } 260 dumpResultStats(Object[] results, int expected_unique)261 private static void dumpResultStats(Object[] results, int expected_unique) throws Exception { 262 int throwables = 0; 263 int classes = 0; 264 int unique_classes = 0; 265 for (int i = 0; i != results.length; ++i) { 266 Object r = results[i]; 267 if (r instanceof Throwable) { 268 ++throwables; 269 System.out.println(((Throwable) r).getMessage()); 270 } else if (isClassPair(r)) { 271 printPair(r); 272 Object ref = getSecond(r); 273 ++classes; 274 ++unique_classes; 275 for (int j = 0; j != i; ++j) { 276 Object rj = results[j]; 277 if (isClassPair(results[j]) && getSecond(results[j]) == ref) { 278 --unique_classes; 279 break; 280 } 281 } 282 } 283 } 284 System.out.println("total: " + results.length); 285 System.out.println(" throwables: " + throwables); 286 System.out.println(" classes: " + classes 287 + " (" + unique_classes + " unique)"); 288 if (expected_unique != unique_classes) { 289 System.out.println("MISMATCH with expected_unique: " + expected_unique); 290 ArrayList<Class<?>> list = new ArrayList<Class<?>>(); 291 for (int i = 0; i != results.length; ++i) { 292 Object r = results[i]; 293 if (isClassPair(r)) { 294 list.add(getSecond(r)); 295 } 296 } 297 nativeDumpClasses(list.toArray()); 298 } 299 } 300 createDelegatingLoader()301 private static DelegatingLoader createDelegatingLoader() { 302 ClassLoader system_loader = ClassLoader.getSystemClassLoader(); 303 DefiningLoader defining_loader = new DefiningLoader(system_loader); 304 return new DelegatingLoader(system_loader, defining_loader); 305 } 306 changeInner(DelegatingLoader delegating_loader)307 private static void changeInner(DelegatingLoader delegating_loader) { 308 ClassLoader system_loader = ClassLoader.getSystemClassLoader(); 309 DefiningLoader defining_loader = new DefiningLoader(system_loader); 310 delegating_loader.resetDefiningLoader(defining_loader); 311 } 312 wrapHelperGet(Class<?> helper)313 private static WeakReference<Class<?>> wrapHelperGet(Class<?> helper) throws Exception { 314 Method get = helper.getDeclaredMethod("get"); 315 Object pair = get.invoke(null); 316 printPair(pair); 317 return new WeakReference<Class<?>>(getSecond(pair)); 318 } 319 printPair(Object pair)320 private static void printPair(Object pair) throws Exception { 321 Method print = pair.getClass().getDeclaredMethod("print"); 322 print.invoke(pair); 323 } 324 getSecond(Object pair)325 private static Class<?> getSecond(Object pair) throws Exception { 326 Field second = pair.getClass().getDeclaredField("second"); 327 return (Class<?>) second.get(pair); 328 } 329 isClassPair(Object r)330 private static boolean isClassPair(Object r) { 331 return r != null && r.getClass().getName().equals("ClassPair"); 332 } 333 clearResolvedTypes(Class<?> c)334 public static void clearResolvedTypes(Class<?> c) { 335 if (!usingRI) { 336 nativeClearResolvedTypes(c); 337 } 338 } 339 340 // Skip verification of a class on ART. Verification can cause classes to be loaded 341 // while holding a lock on the class being verified and holding that lock can interfere 342 // with the intent of the "racy" tests. In these tests we're waiting in the loadClass() 343 // for all the tested threads to synchronize and they cannot reach that point if they 344 // are waiting for the class lock on ClassLinker::InitializeClass(Helper1/Helper3). skipVerification(Class<?> c)345 public static void skipVerification(Class<?> c) { 346 if (!usingRI) { 347 nativeSkipVerification(c); 348 } 349 } 350 nativeClearResolvedTypes(Class<?> c)351 public static native void nativeClearResolvedTypes(Class<?> c); nativeSkipVerification(Class<?> c)352 public static native void nativeSkipVerification(Class<?> c); nativeDumpClasses(Object[] array)353 public static native void nativeDumpClasses(Object[] array); 354 355 static boolean usingRI = false; 356 } 357