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.dummy); 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 }; 266 for (String s : PRELOAD_FOR_JIT) { 267 Class.forName(s); 268 } 269 270 Runnable r = new Runnable() { 271 @Override 272 public void run() { 273 try { 274 ClassLoader cl6 = DexData.create12(); 275 System.out.println("C, true"); 276 Class.forName("C", true, cl6); 277 printClassLoadMessages(); 278 } catch (Exception e) { 279 throw new RuntimeException(e); 280 } 281 } 282 }; 283 284 Thread dummyThread = new Thread(); 285 dummyThread.start(); 286 dummyThread.join(); 287 288 enableClassLoadPreparePrintEvents(true, Thread.currentThread()); 289 290 ClassLoader cl1 = DexData.create12(); 291 System.out.println("B, false"); 292 Class.forName("B", false, cl1); 293 printClassLoadMessages(); 294 295 ClassLoader cl2 = DexData.create12(); 296 System.out.println("B, true"); 297 Class.forName("B", true, cl2); 298 printClassLoadMessages(); 299 300 ClassLoader cl3 = DexData.create12(); 301 System.out.println("C, false"); 302 Class.forName("C", false, cl3); 303 printClassLoadMessages(); 304 System.out.println("A, false"); 305 Class.forName("A", false, cl3); 306 printClassLoadMessages(); 307 308 ClassLoader cl4 = DexData.create12(); 309 System.out.println("C, true"); 310 Class.forName("C", true, cl4); 311 printClassLoadMessages(); 312 System.out.println("A, true"); 313 Class.forName("A", true, cl4); 314 printClassLoadMessages(); 315 316 ClassLoader cl5 = DexData.create12(); 317 System.out.println("A, true"); 318 Class.forName("A", true, cl5); 319 printClassLoadMessages(); 320 System.out.println("C, true"); 321 Class.forName("C", true, cl5); 322 printClassLoadMessages(); 323 324 enableClassLoadPreparePrintEvents(false, null); 325 326 Thread t = new Thread(r, "TestRunner"); 327 enableClassLoadPreparePrintEvents(true, t); 328 t.start(); 329 t.join(); 330 enableClassLoadPreparePrintEvents(false, null); 331 332 enableClassLoadPreparePrintEvents(true, Thread.currentThread()); 333 334 // Check creation of arrays and proxies. 335 Proxy.getProxyClass(Main.class.getClassLoader(), new Class[] { Comparable.class, I0.class }); 336 Class.forName("[Lart.Test912;"); 337 printClassLoadMessages(); 338 339 enableClassLoadPreparePrintEvents(false, null); 340 341 testClassLoadPrepareEquality(); 342 } 343 testClassLoadPrepareEquality()344 private static void testClassLoadPrepareEquality() throws Exception { 345 setEqualityEventStorageClass(ClassF.class); 346 347 enableClassLoadPrepareEqualityEvents(true); 348 349 Class.forName("art.Test912$ClassE"); 350 351 enableClassLoadPrepareEqualityEvents(false); 352 } 353 printClassLoaderClasses(ClassLoader cl)354 private static void printClassLoaderClasses(ClassLoader cl) { 355 for (;;) { 356 if (cl == null || !cl.getClass().getName().startsWith("dalvik.system")) { 357 break; 358 } 359 360 Class<?> classes[] = getClassLoaderClasses(cl); 361 Arrays.sort(classes, new ClassNameComparator()); 362 System.out.println(Arrays.toString(classes)); 363 364 cl = cl.getParent(); 365 } 366 } 367 printClassLoadMessages()368 private static void printClassLoadMessages() { 369 for (String s : getClassLoadMessages()) { 370 System.out.println(s); 371 } 372 } 373 isModifiableClass(Class<?> c)374 private static native boolean isModifiableClass(Class<?> c); getClassSignature(Class<?> c)375 private static native String[] getClassSignature(Class<?> c); 376 isInterface(Class<?> c)377 private static native boolean isInterface(Class<?> c); isArrayClass(Class<?> c)378 private static native boolean isArrayClass(Class<?> c); 379 getClassModifiers(Class<?> c)380 private static native int getClassModifiers(Class<?> c); 381 getClassFields(Class<?> c)382 private static native Object[] getClassFields(Class<?> c); getClassMethods(Class<?> c)383 private static native Object[] getClassMethods(Class<?> c); getImplementedInterfaces(Class<?> c)384 private static native Class<?>[] getImplementedInterfaces(Class<?> c); 385 getClassStatus(Class<?> c)386 private static native int getClassStatus(Class<?> c); 387 getClassLoader(Class<?> c)388 private static native Object getClassLoader(Class<?> c); 389 getClassLoaderClasses(ClassLoader cl)390 private static native Class<?>[] getClassLoaderClasses(ClassLoader cl); 391 getClassVersion(Class<?> c)392 private static native int[] getClassVersion(Class<?> c); 393 enableClassLoadPreparePrintEvents(boolean b, Thread filter)394 private static native void enableClassLoadPreparePrintEvents(boolean b, Thread filter); getClassLoadMessages()395 private static native String[] getClassLoadMessages(); 396 setEqualityEventStorageClass(Class<?> c)397 private static native void setEqualityEventStorageClass(Class<?> c); enableClassLoadPrepareEqualityEvents(boolean b)398 private static native void enableClassLoadPrepareEqualityEvents(boolean b); 399 runRecursiveClassPrepareEvents(Runnable forceLoad)400 private static native void runRecursiveClassPrepareEvents(Runnable forceLoad); 401 TestRecursiveClassPrepareEvents()402 private static void TestRecursiveClassPrepareEvents() { 403 final int[] called = new int[] { 0 }; 404 runRecursiveClassPrepareEvents(() -> { 405 if (called[0] == 2) { 406 return; 407 } else { 408 called[0]++; 409 } 410 try { 411 System.out.println("class-prepare event START!"); 412 // Load a new class in a new class-loader. 413 Class<?> class_loader_class = Class.forName("dalvik.system.InMemoryDexClassLoader"); 414 Constructor<?> ctor = class_loader_class.getConstructor(ByteBuffer.class, ClassLoader.class); 415 Class<?> target = ((ClassLoader)ctor.newInstance( 416 ByteBuffer.wrap(DEX_BYTES), Test912.class.getClassLoader())).loadClass("Transform"); 417 target.newInstance(); 418 } catch (Exception e) { } 419 System.out.println("class-prepare event END!"); 420 }); 421 if (called[0] != 2) { 422 System.out.println("Failed to cause recursive Class prepare."); 423 } 424 } 425 426 private static class TestForNonInit { 427 public static double dummy = Math.random(); // So it can't be compile-time initialized. 428 } 429 430 @SuppressWarnings("RandomCast") 431 private static class TestForInitFail { 432 public static int dummy = ((int)Math.random())/0; // So it throws when initializing. 433 } 434 435 public static interface InfA { 436 } 437 public static interface InfB extends InfA { 438 } 439 public static interface InfC extends InfB { 440 } 441 442 public abstract static class ClassA implements InfA { 443 } 444 public abstract static class ClassB extends ClassA implements InfB { 445 } 446 public abstract static class ClassC implements InfA, InfC { 447 } 448 449 public static class ClassE { foo()450 public void foo() { 451 } bar()452 public void bar() { 453 } 454 } 455 456 public static class ClassF { 457 public static Object STATIC = null; 458 public static Reference<Object> WEAK = null; 459 } 460 461 private static class ClassNameComparator implements Comparator<Class<?>> { compare(Class<?> c1, Class<?> c2)462 public int compare(Class<?> c1, Class<?> c2) { 463 return c1.getName().compareTo(c2.getName()); 464 } 465 } 466 467 // See run-test 910 for an explanation. 468 469 private static Class<?> proxyClass = null; 470 getProxyClass()471 private static Class<?> getProxyClass() throws Exception { 472 if (proxyClass != null) { 473 return proxyClass; 474 } 475 476 for (int i = 1; i <= 21; i++) { 477 proxyClass = createProxyClass(i); 478 String name = proxyClass.getName(); 479 if (name.equals("$Proxy20")) { 480 return proxyClass; 481 } 482 } 483 return proxyClass; 484 } 485 createProxyClass(int i)486 private static Class<?> createProxyClass(int i) throws Exception { 487 int count = Integer.bitCount(i); 488 Class<?>[] input = new Class<?>[count + 1]; 489 input[0] = Runnable.class; 490 int inputIndex = 1; 491 int bitIndex = 0; 492 while (i != 0) { 493 if ((i & 1) != 0) { 494 input[inputIndex++] = Class.forName("art.Test912$I" + bitIndex); 495 } 496 i >>>= 1; 497 bitIndex++; 498 } 499 return Proxy.getProxyClass(Test912.class.getClassLoader(), input); 500 } 501 502 // Need this for the proxy naming. 503 public static interface I0 { 504 } 505 public static interface I1 { 506 } 507 public static interface I2 { 508 } 509 public static interface I3 { 510 } 511 public static interface I4 { 512 } 513 } 514