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         "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 
    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 
    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 
    365   private static void printClassLoadMessages() {
    366     for (String s : getClassLoadMessages()) {
    367       System.out.println(s);
    368     }
    369   }
    370 
    371   private static native boolean isModifiableClass(Class<?> c);
    372   private static native String[] getClassSignature(Class<?> c);
    373 
    374   private static native boolean isInterface(Class<?> c);
    375   private static native boolean isArrayClass(Class<?> c);
    376 
    377   private static native int getClassModifiers(Class<?> c);
    378 
    379   private static native Object[] getClassFields(Class<?> c);
    380   private static native Object[] getClassMethods(Class<?> c);
    381   private static native Class<?>[] getImplementedInterfaces(Class<?> c);
    382 
    383   private static native int getClassStatus(Class<?> c);
    384 
    385   private static native Object getClassLoader(Class<?> c);
    386 
    387   private static native Class<?>[] getClassLoaderClasses(ClassLoader cl);
    388 
    389   private static native int[] getClassVersion(Class<?> c);
    390 
    391   private static native void enableClassLoadPreparePrintEvents(boolean b, Thread filter);
    392   private static native String[] getClassLoadMessages();
    393 
    394   private static native void setEqualityEventStorageClass(Class<?> c);
    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 {
    421     public void foo() {
    422     }
    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<?>> {
    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 
    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 
    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