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