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