Home | History | Annotate | Download | only in art
      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