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 package art; 18 19 import java.lang.ref.Reference; 20 import java.lang.reflect.Constructor; 21 import java.lang.reflect.Proxy; 22 import java.nio.ByteBuffer; 23 import java.util.ArrayList; 24 import java.util.Arrays; 25 import java.util.Base64; 26 import java.util.Comparator; 27 28 public class Test912 { run()29 public static void run() throws Exception { 30 doTest(); 31 } 32 doTest()33 public static void doTest() throws Exception { 34 testClass("java.lang.Object"); 35 testClass("java.lang.String"); 36 testClass("java.lang.Math"); 37 testClass("java.util.List"); 38 39 testClass(getProxyClass()); 40 41 testClass(int.class); 42 testClass(double[].class); 43 44 testClassType(int.class); 45 testClassType(getProxyClass()); 46 testClassType(Runnable.class); 47 testClassType(String.class); 48 testClassType(ArrayList.class); 49 50 testClassType(int[].class); 51 testClassType(Runnable[].class); 52 testClassType(String[].class); 53 54 testClassFields(Integer.class); 55 testClassFields(int.class); 56 testClassFields(String[].class); 57 58 testClassMethods(Integer.class); 59 testClassMethods(int.class); 60 testClassMethods(String[].class); 61 62 testClassStatus(int.class); 63 testClassStatus(String[].class); 64 testClassStatus(Object.class); 65 testClassStatus(TestForNonInit.class); 66 try { 67 System.out.println(TestForInitFail.intValue); 68 } catch (ExceptionInInitializerError e) { 69 } 70 testClassStatus(TestForInitFail.class); 71 72 testInterfaces(int.class); 73 testInterfaces(String[].class); 74 testInterfaces(Object.class); 75 testInterfaces(InfA.class); 76 testInterfaces(InfB.class); 77 testInterfaces(InfC.class); 78 testInterfaces(ClassA.class); 79 testInterfaces(ClassB.class); 80 testInterfaces(ClassC.class); 81 82 testClassLoader(String.class); 83 testClassLoader(String[].class); 84 testClassLoader(InfA.class); 85 testClassLoader(getProxyClass()); 86 87 testClassLoaderClasses(); 88 89 System.out.println(); 90 91 testClassVersion(); 92 93 System.out.println(); 94 95 // Use a dedicated thread to have a well-defined current thread. 96 Thread classEventsThread = new Thread("ClassEvents") { 97 @Override 98 public void run() { 99 try { 100 testClassEvents(); 101 } catch (Exception e) { 102 throw new RuntimeException(e); 103 } 104 } 105 }; 106 classEventsThread.start(); 107 classEventsThread.join(); 108 109 // b/146170757 110 TestRecursiveClassPrepareEvents(); 111 } 112 testClass(String className)113 private static void testClass(String className) throws Exception { 114 Class<?> base = Class.forName(className); 115 testClass(base); 116 } 117 testClass(Class<?> base)118 private static void testClass(Class<?> base) throws Exception { 119 String[] result = getClassSignature(base); 120 System.out.println(Arrays.toString(result)); 121 int mod = getClassModifiers(base); 122 if (mod != base.getModifiers()) { 123 throw new RuntimeException("Unexpected modifiers: " + base.getModifiers() + " vs " + mod); 124 } 125 System.out.println(Integer.toHexString(mod)); 126 } 127 testClassType(Class<?> c)128 private static void testClassType(Class<?> c) throws Exception { 129 boolean isInterface = isInterface(c); 130 boolean isArray = isArrayClass(c); 131 boolean isModifiable = isModifiableClass(c); 132 System.out.println(c.getName() + " interface=" + isInterface + " array=" + isArray + 133 " modifiable=" + isModifiable); 134 } 135 testClassFields(Class<?> c)136 private static void testClassFields(Class<?> c) throws Exception { 137 System.out.println(Arrays.toString(getClassFields(c))); 138 } 139 testClassMethods(Class<?> c)140 private static void testClassMethods(Class<?> c) throws Exception { 141 System.out.println(Arrays.toString(getClassMethods(c))); 142 } 143 testClassStatus(Class<?> c)144 private static void testClassStatus(Class<?> c) { 145 System.out.println(c + " " + Integer.toBinaryString(getClassStatus(c))); 146 } 147 testInterfaces(Class<?> c)148 private static void testInterfaces(Class<?> c) { 149 System.out.println(c + " " + Arrays.toString(getImplementedInterfaces(c))); 150 } 151 IsBootClassLoader(ClassLoader l)152 private static boolean IsBootClassLoader(ClassLoader l) { 153 // Hacky check for Android's fake boot classloader. 154 return l.getClass().getName().equals("java.lang.BootClassLoader"); 155 } 156 testClassLoader(Class<?> c)157 private static void testClassLoader(Class<?> c) { 158 Object cl = getClassLoader(c); 159 System.out.println(c + " " + (cl != null ? cl.getClass().getName() : "null")); 160 if (cl == null) { 161 if (c.getClassLoader() != null && !IsBootClassLoader(c.getClassLoader())) { 162 throw new RuntimeException("Expected " + c.getClassLoader() + ", but got null."); 163 } 164 } else { 165 if (!(cl instanceof ClassLoader)) { 166 throw new RuntimeException("Unexpected \"classloader\": " + cl + " (" + cl.getClass() + 167 ")"); 168 } 169 if (cl != c.getClassLoader()) { 170 throw new RuntimeException("Unexpected classloader: " + c.getClassLoader() + " vs " + cl); 171 } 172 } 173 } 174 testClassLoaderClasses()175 private static void testClassLoaderClasses() throws Exception { 176 System.out.println(); 177 System.out.println("boot <- (B) <- (A,C)"); 178 ClassLoader cl1 = DexData.create2(DexData.create1()); 179 Class.forName("B", false, cl1); 180 Class.forName("A", false, cl1); 181 printClassLoaderClasses(cl1); 182 183 System.out.println(); 184 System.out.println("boot <- (B) <- (A, List)"); 185 ClassLoader cl2 = DexData.create2(DexData.create1()); 186 Class.forName("A", false, cl2); 187 Class.forName("java.util.List", false, cl2); 188 Class.forName("B", false, cl2.getParent()); 189 printClassLoaderClasses(cl2); 190 191 System.out.println(); 192 System.out.println("boot <- 1+2 (A,B)"); 193 ClassLoader cl3 = DexData.create12(); 194 Class.forName("B", false, cl3); 195 Class.forName("A", false, cl3); 196 printClassLoaderClasses(cl3); 197 198 // Check that the boot classloader dumps something non-empty. 199 ClassLoader boot = ClassLoader.getSystemClassLoader().getParent(); 200 while (boot.getParent() != null) { 201 boot = boot.getParent(); 202 } 203 204 Class<?>[] bootClasses = getClassLoaderClasses(boot); 205 if (bootClasses.length == 0) { 206 throw new RuntimeException("No classes initiated by boot classloader."); 207 } 208 // Check that at least java.util.List is loaded. 209 boolean foundList = false; 210 for (Class<?> c : bootClasses) { 211 if (c == java.util.List.class) { 212 foundList = true; 213 break; 214 } 215 } 216 if (!foundList) { 217 System.out.println(Arrays.toString(bootClasses)); 218 throw new RuntimeException("Could not find class java.util.List."); 219 } 220 } 221 222 /** 223 * base64 encoded class/dex file for 224 * class Transform { 225 * public void sayHi() { 226 * System.out.println("Goodbye"); 227 * } 228 * } 229 */ 230 private static final byte[] DEX_BYTES = Base64.getDecoder().decode( 231 "ZGV4CjAzNQCLXSBQ5FiS3f16krSYZFF8xYZtFVp0GRXMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" + 232 "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" + 233 "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" + 234 "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" + 235 "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" + 236 "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" + 237 "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" + 238 "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" + 239 "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTMuMzYAA291" + 240 "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgATAAcOhQAAAAEBAICABKACAQG4Ag0AAAAAAAAAAQAAAAAA" + 241 "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" + 242 "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" + 243 "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA="); testClassVersion()244 private static void testClassVersion() throws Exception { 245 Class<?> class_loader_class = Class.forName("dalvik.system.InMemoryDexClassLoader"); 246 Constructor<?> ctor = class_loader_class.getConstructor(ByteBuffer.class, ClassLoader.class); 247 Class target = ((ClassLoader)ctor.newInstance( 248 ByteBuffer.wrap(DEX_BYTES), Test912.class.getClassLoader())).loadClass("Transform"); 249 System.out.println(Arrays.toString(getClassVersion(target))); 250 } 251 testClassEvents()252 private static void testClassEvents() throws Exception { 253 ClassLoader cl = Main.class.getClassLoader(); 254 while (cl.getParent() != null) { 255 cl = cl.getParent(); 256 } 257 final ClassLoader boot = cl; 258 259 // The JIT may deeply inline and load some classes. Preload these for test determinism. 260 final String PRELOAD_FOR_JIT[] = { 261 "java.nio.charset.CoderMalfunctionError", 262 "java.util.NoSuchElementException", 263 "java.io.FileNotFoundException", // b/63581208 264 "java.util.zip.ZipException", // b/63581208 265 "sun.invoke.util.Wrapper", // For "ClassEvents" thread in JIT/no-image config. 266 }; 267 for (String s : PRELOAD_FOR_JIT) { 268 Class.forName(s); 269 } 270 271 Runnable r = new Runnable() { 272 @Override 273 public void run() { 274 try { 275 ClassLoader cl6 = DexData.create12(); 276 System.out.println("C, true"); 277 Class.forName("C", true, cl6); 278 printClassLoadMessages(); 279 } catch (Exception e) { 280 throw new RuntimeException(e); 281 } 282 } 283 }; 284 285 Thread noopThread = new Thread(); 286 noopThread.start(); 287 noopThread.join(); 288 289 enableClassLoadPreparePrintEvents(true, Thread.currentThread()); 290 291 ClassLoader cl1 = DexData.create12(); 292 System.out.println("B, false"); 293 Class.forName("B", false, cl1); 294 printClassLoadMessages(); 295 296 ClassLoader cl2 = DexData.create12(); 297 System.out.println("B, true"); 298 Class.forName("B", true, cl2); 299 printClassLoadMessages(); 300 301 ClassLoader cl3 = DexData.create12(); 302 System.out.println("C, false"); 303 Class.forName("C", false, cl3); 304 printClassLoadMessages(); 305 System.out.println("A, false"); 306 Class.forName("A", false, cl3); 307 printClassLoadMessages(); 308 309 ClassLoader cl4 = DexData.create12(); 310 System.out.println("C, true"); 311 Class.forName("C", true, cl4); 312 printClassLoadMessages(); 313 System.out.println("A, true"); 314 Class.forName("A", true, cl4); 315 printClassLoadMessages(); 316 317 ClassLoader cl5 = DexData.create12(); 318 System.out.println("A, true"); 319 Class.forName("A", true, cl5); 320 printClassLoadMessages(); 321 System.out.println("C, true"); 322 Class.forName("C", true, cl5); 323 printClassLoadMessages(); 324 325 enableClassLoadPreparePrintEvents(false, null); 326 327 Thread t = new Thread(r, "TestRunner"); 328 enableClassLoadPreparePrintEvents(true, t); 329 t.start(); 330 t.join(); 331 enableClassLoadPreparePrintEvents(false, null); 332 333 enableClassLoadPreparePrintEvents(true, Thread.currentThread()); 334 335 // Check creation of arrays and proxies. 336 Proxy.getProxyClass(Main.class.getClassLoader(), new Class[] { Comparable.class, I0.class }); 337 Class.forName("[Lart.Test912;"); 338 printClassLoadMessages(); 339 340 enableClassLoadPreparePrintEvents(false, null); 341 342 testClassLoadPrepareEquality(); 343 } 344 testClassLoadPrepareEquality()345 private static void testClassLoadPrepareEquality() throws Exception { 346 setEqualityEventStorageClass(ClassF.class); 347 348 enableClassLoadPrepareEqualityEvents(true); 349 350 Class.forName("art.Test912$ClassE"); 351 352 enableClassLoadPrepareEqualityEvents(false); 353 } 354 printClassLoaderClasses(ClassLoader cl)355 private static void printClassLoaderClasses(ClassLoader cl) { 356 for (;;) { 357 if (cl == null || !cl.getClass().getName().startsWith("dalvik.system")) { 358 break; 359 } 360 361 Class<?> classes[] = getClassLoaderClasses(cl); 362 Arrays.sort(classes, new ClassNameComparator()); 363 System.out.println(Arrays.toString(classes)); 364 365 cl = cl.getParent(); 366 } 367 } 368 printClassLoadMessages()369 private static void printClassLoadMessages() { 370 for (String s : getClassLoadMessages()) { 371 System.out.println(s); 372 } 373 } 374 isModifiableClass(Class<?> c)375 private static native boolean isModifiableClass(Class<?> c); getClassSignature(Class<?> c)376 private static native String[] getClassSignature(Class<?> c); 377 isInterface(Class<?> c)378 private static native boolean isInterface(Class<?> c); isArrayClass(Class<?> c)379 private static native boolean isArrayClass(Class<?> c); 380 getClassModifiers(Class<?> c)381 private static native int getClassModifiers(Class<?> c); 382 getClassFields(Class<?> c)383 private static native Object[] getClassFields(Class<?> c); getClassMethods(Class<?> c)384 private static native Object[] getClassMethods(Class<?> c); getImplementedInterfaces(Class<?> c)385 private static native Class<?>[] getImplementedInterfaces(Class<?> c); 386 getClassStatus(Class<?> c)387 private static native int getClassStatus(Class<?> c); 388 getClassLoader(Class<?> c)389 private static native Object getClassLoader(Class<?> c); 390 getClassLoaderClasses(ClassLoader cl)391 private static native Class<?>[] getClassLoaderClasses(ClassLoader cl); 392 getClassVersion(Class<?> c)393 private static native int[] getClassVersion(Class<?> c); 394 enableClassLoadPreparePrintEvents(boolean b, Thread filter)395 private static native void enableClassLoadPreparePrintEvents(boolean b, Thread filter); getClassLoadMessages()396 private static native String[] getClassLoadMessages(); 397 setEqualityEventStorageClass(Class<?> c)398 private static native void setEqualityEventStorageClass(Class<?> c); enableClassLoadPrepareEqualityEvents(boolean b)399 private static native void enableClassLoadPrepareEqualityEvents(boolean b); 400 runRecursiveClassPrepareEvents(Runnable forceLoad)401 private static native void runRecursiveClassPrepareEvents(Runnable forceLoad); 402 TestRecursiveClassPrepareEvents()403 private static void TestRecursiveClassPrepareEvents() { 404 final int[] called = new int[] { 0 }; 405 runRecursiveClassPrepareEvents(() -> { 406 if (called[0] == 2) { 407 return; 408 } else { 409 called[0]++; 410 } 411 try { 412 System.out.println("class-prepare event START!"); 413 // Load a new class in a new class-loader. 414 Class<?> class_loader_class = Class.forName("dalvik.system.InMemoryDexClassLoader"); 415 Constructor<?> ctor = class_loader_class.getConstructor(ByteBuffer.class, ClassLoader.class); 416 Class<?> target = ((ClassLoader)ctor.newInstance( 417 ByteBuffer.wrap(DEX_BYTES), Test912.class.getClassLoader())).loadClass("Transform"); 418 target.newInstance(); 419 } catch (Exception e) { } 420 System.out.println("class-prepare event END!"); 421 }); 422 if (called[0] != 2) { 423 System.out.println("Failed to cause recursive Class prepare."); 424 } 425 } 426 427 private static class TestForNonInit { 428 public static double doubleValue = Math.random(); // So it can't be compile-time initialized. 429 } 430 431 @SuppressWarnings("RandomCast") 432 private static class TestForInitFail { 433 public static int intValue = ((int)Math.random())/0; // So it throws when initializing. 434 } 435 436 public static interface InfA { 437 } 438 public static interface InfB extends InfA { 439 } 440 public static interface InfC extends InfB { 441 } 442 443 public abstract static class ClassA implements InfA { 444 } 445 public abstract static class ClassB extends ClassA implements InfB { 446 } 447 public abstract static class ClassC implements InfA, InfC { 448 } 449 450 public static class ClassE { foo()451 public void foo() { 452 } bar()453 public void bar() { 454 } 455 } 456 457 public static class ClassF { 458 public static Object STATIC = null; 459 public static Reference<Object> WEAK = null; 460 } 461 462 private static class ClassNameComparator implements Comparator<Class<?>> { compare(Class<?> c1, Class<?> c2)463 public int compare(Class<?> c1, Class<?> c2) { 464 return c1.getName().compareTo(c2.getName()); 465 } 466 } 467 468 // See run-test 910 for an explanation. 469 470 private static Class<?> proxyClass = null; 471 getProxyClass()472 private static Class<?> getProxyClass() throws Exception { 473 if (proxyClass != null) { 474 return proxyClass; 475 } 476 477 for (int i = 1; i <= 21; i++) { 478 proxyClass = createProxyClass(i); 479 String name = proxyClass.getName(); 480 if (name.equals("$Proxy20")) { 481 return proxyClass; 482 } 483 } 484 return proxyClass; 485 } 486 createProxyClass(int i)487 private static Class<?> createProxyClass(int i) throws Exception { 488 int count = Integer.bitCount(i); 489 Class<?>[] input = new Class<?>[count + 1]; 490 input[0] = Runnable.class; 491 int inputIndex = 1; 492 int bitIndex = 0; 493 while (i != 0) { 494 if ((i & 1) != 0) { 495 input[inputIndex++] = Class.forName("art.Test912$I" + bitIndex); 496 } 497 i >>>= 1; 498 bitIndex++; 499 } 500 return Proxy.getProxyClass(Test912.class.getClassLoader(), input); 501 } 502 503 // Need this for the proxy naming. 504 public static interface I0 { 505 } 506 public static interface I1 { 507 } 508 public static interface I2 { 509 } 510 public static interface I3 { 511 } 512 public static interface I4 { 513 } 514 } 515