Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (C) 2019 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 import dalvik.system.InMemoryDexClassLoader;
     18 import java.lang.reflect.Method;
     19 import java.io.File;
     20 import java.nio.ByteBuffer;
     21 import java.util.Base64;
     22 
     23 public class Main {
     24   private static void check(boolean expected, boolean actual, String message) {
     25     if (expected != actual) {
     26       System.err.println(
     27           "ERROR: " + message + " (expected=" + expected + ", actual=" + actual + ")");
     28     }
     29   }
     30 
     31   private static ClassLoader singleLoader() {
     32     return new InMemoryDexClassLoader(
     33         new ByteBuffer[] { ByteBuffer.wrap(DEX_BYTES_A), ByteBuffer.wrap(DEX_BYTES_B) },
     34         /*parent*/null);
     35   }
     36 
     37   private static ClassLoader[] multiLoader() {
     38     ClassLoader clA = new InMemoryDexClassLoader(ByteBuffer.wrap(DEX_BYTES_A), /*parent*/ null);
     39     ClassLoader clB = new InMemoryDexClassLoader(ByteBuffer.wrap(DEX_BYTES_B), /*parent*/ clA);
     40     return new ClassLoader[] { clA, clB };
     41   }
     42 
     43   private static void test(ClassLoader loader,
     44                            boolean expectedHasVdexFile,
     45                            boolean expectedBackedByOat,
     46                            boolean invokeMethod) throws Exception {
     47     // If ART created a vdex file, it must have verified all the classes.
     48     // That happens if and only if we expect a vdex at the end of the test but
     49     // do not expect it to have been loaded.
     50     boolean expectedClassesVerified = expectedHasVdexFile && !expectedBackedByOat;
     51 
     52     waitForVerifier();
     53     check(expectedClassesVerified, areClassesVerified(loader), "areClassesVerified");
     54     check(expectedHasVdexFile, hasVdexFile(loader), "areClassesVerified");
     55     check(expectedBackedByOat, isBackedByOatFile(loader), "isBackedByOatFile");
     56     check(expectedBackedByOat, areClassesPreverified(loader), "areClassesPreverified");
     57 
     58     if (invokeMethod) {
     59       loader.loadClass("art.ClassB").getDeclaredMethod("printHello").invoke(null);
     60     }
     61   }
     62 
     63   public static void main(String[] args) throws Exception {
     64     System.loadLibrary(args[0]);
     65     ClassLoader[] loaders = null;
     66 
     67     // Feature only enabled for target SDK version Q and later.
     68     setTargetSdkVersion(/* Q */ 29);
     69 
     70     // Feature is disabled in debuggable mode because runtime threads are not
     71     // allowed to load classes.
     72     boolean featureEnabled = !isDebuggable();
     73 
     74     // Data directory not set. Background verification job should not have run
     75     // and vdex should not have been created.
     76     test(singleLoader(), /*hasVdex*/ false, /*backedByOat*/ false, /*invokeMethod*/ true);
     77 
     78     // Set data directory for this process.
     79     setProcessDataDir(DEX_LOCATION);
     80 
     81     // Data directory is now set. Background verification job should have run,
     82     // should have verified classes and written results to a vdex.
     83     test(singleLoader(), /*hasVdex*/ featureEnabled, /*backedByOat*/ false, /*invokeMethod*/ true);
     84     test(singleLoader(), /*hasVdex*/ featureEnabled, /*backedByOat*/ featureEnabled,
     85         /*invokeMethod*/ true);
     86 
     87     // Test loading the two dex files with separate class loaders.
     88     // Background verification task should still verify all classes.
     89     loaders = multiLoader();
     90     test(loaders[0], /*hasVdex*/ featureEnabled, /*backedByOat*/ false, /*invokeMethod*/ false);
     91     test(loaders[1], /*hasVdex*/ featureEnabled, /*backedByOat*/ false, /*invokeMethod*/ true);
     92 
     93     loaders = multiLoader();
     94     test(loaders[0], /*hasVdex*/ featureEnabled, /*backedByOat*/ featureEnabled,
     95         /*invokeMethod*/ false);
     96     test(loaders[1], /*hasVdex*/ featureEnabled, /*backedByOat*/ featureEnabled,
     97         /*invokeMethod*/ true);
     98 
     99     // Change boot classpath checksum.
    100     appendToBootClassLoader(DEX_EXTRA, /*isCorePlatform*/ false);
    101 
    102     loaders = multiLoader();
    103     test(loaders[0], /*hasVdex*/ featureEnabled, /*backedByOat*/ false, /*invokeMethod*/ false);
    104     test(loaders[1], /*hasVdex*/ featureEnabled, /*backedByOat*/ false, /*invokeMethod*/ true);
    105 
    106     loaders = multiLoader();
    107     test(loaders[0], /*hasVdex*/ featureEnabled, /*backedByOat*/ featureEnabled,
    108         /*invokeMethod*/ false);
    109     test(loaders[1], /*hasVdex*/ featureEnabled, /*backedByOat*/ featureEnabled,
    110         /*invokeMethod*/ true);
    111   }
    112 
    113   private static native boolean isDebuggable();
    114   private static native int setTargetSdkVersion(int version);
    115   private static native void setProcessDataDir(String path);
    116   private static native void waitForVerifier();
    117   private static native boolean areClassesVerified(ClassLoader loader);
    118   private static native boolean hasVdexFile(ClassLoader loader);
    119   private static native boolean isBackedByOatFile(ClassLoader loader);
    120   private static native boolean areClassesPreverified(ClassLoader loader);
    121 
    122   // Defined in 674-hiddenapi.
    123   private static native void appendToBootClassLoader(String dexPath, boolean isCorePlatform);
    124 
    125   private static final String DEX_LOCATION = System.getenv("DEX_LOCATION");
    126   private static final String DEX_EXTRA =
    127       new File(DEX_LOCATION, "692-vdex-inmem-loader-ex.jar").getAbsolutePath();
    128 
    129   private static final byte[] DEX_BYTES_A = Base64.getDecoder().decode(
    130     "ZGV4CjAzNQBxYu/tdPfiHaRPYr5yaT6ko9V/xMinr1OwAgAAcAAAAHhWNBIAAAAAAAAAABwCAAAK" +
    131     "AAAAcAAAAAQAAACYAAAAAgAAAKgAAAAAAAAAAAAAAAMAAADAAAAAAQAAANgAAAC4AQAA+AAAADAB" +
    132     "AAA4AQAARQEAAEwBAABPAQAAXQEAAHEBAACFAQAAiAEAAJIBAAAEAAAABQAAAAYAAAAHAAAAAwAA" +
    133     "AAIAAAAAAAAABwAAAAMAAAAAAAAAAAABAAAAAAAAAAAACAAAAAEAAQAAAAAAAAAAAAEAAAABAAAA" +
    134     "AAAAAAEAAAAAAAAACQIAAAAAAAABAAAAAAAAACwBAAADAAAAGgACABEAAAABAAEAAQAAACgBAAAE" +
    135     "AAAAcBACAAAADgATAA4AFQAOAAY8aW5pdD4AC0NsYXNzQS5qYXZhAAVIZWxsbwABTAAMTGFydC9D" +
    136     "bGFzc0E7ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwABVgAIZ2V0SGVs" +
    137     "bG8AdX5+RDh7ImNvbXBpbGF0aW9uLW1vZGUiOiJkZWJ1ZyIsIm1pbi1hcGkiOjEsInNoYS0xIjoi" +
    138     "OTY2MDhmZDdiYmNjZGQyMjc2Y2Y4OTI4M2QyYjgwY2JmYzRmYzgxYyIsInZlcnNpb24iOiIxLjUu" +
    139     "NC1kZXYifQAAAAIAAIGABJACAQn4AQAAAAAADAAAAAAAAAABAAAAAAAAAAEAAAAKAAAAcAAAAAIA" +
    140     "AAAEAAAAmAAAAAMAAAACAAAAqAAAAAUAAAADAAAAwAAAAAYAAAABAAAA2AAAAAEgAAACAAAA+AAA" +
    141     "AAMgAAACAAAAKAEAAAIgAAAKAAAAMAEAAAAgAAABAAAACQIAAAMQAAABAAAAGAIAAAAQAAABAAAA" +
    142     "HAIAAA==");
    143   private static final byte[] DEX_BYTES_B = Base64.getDecoder().decode(
    144     "ZGV4CjAzNQB+hWvce73hXt7ZVNgp9RAyMLSwQzsWUjV4AwAAcAAAAHhWNBIAAAAAAAAAAMwCAAAQ" +
    145     "AAAAcAAAAAcAAACwAAAAAwAAAMwAAAABAAAA8AAAAAUAAAD4AAAAAQAAACABAAA4AgAAQAEAAI4B" +
    146     "AACWAQAAowEAAKYBAAC0AQAAwgEAANkBAADtAQAAAQIAABUCAAAYAgAAHAIAACYCAAArAgAANwIA" +
    147     "AEACAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAAAgAAAAQAAAAAAAAACQAAAAYAAAAAAAAA" +
    148     "CgAAAAYAAACIAQAABQACAAwAAAAAAAAACwAAAAEAAQAAAAAAAQABAA0AAAACAAIADgAAAAMAAQAA" +
    149     "AAAAAQAAAAEAAAADAAAAAAAAAAEAAAAAAAAAtwIAAAAAAAABAAEAAQAAAHwBAAAEAAAAcBAEAAAA" +
    150     "DgACAAAAAgAAAIABAAAKAAAAYgAAAHEAAAAAAAwBbiADABAADgATAA4AFQAOlgAAAAABAAAABAAG" +
    151     "PGluaXQ+AAtDbGFzc0IuamF2YQABTAAMTGFydC9DbGFzc0E7AAxMYXJ0L0NsYXNzQjsAFUxqYXZh" +
    152     "L2lvL1ByaW50U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsA" +
    153     "EkxqYXZhL2xhbmcvU3lzdGVtOwABVgACVkwACGdldEhlbGxvAANvdXQACnByaW50SGVsbG8AB3By" +
    154     "aW50bG4AdX5+RDh7ImNvbXBpbGF0aW9uLW1vZGUiOiJkZWJ1ZyIsIm1pbi1hcGkiOjEsInNoYS0x" +
    155     "IjoiOTY2MDhmZDdiYmNjZGQyMjc2Y2Y4OTI4M2QyYjgwY2JmYzRmYzgxYyIsInZlcnNpb24iOiIx" +
    156     "LjUuNC1kZXYifQAAAAIAAYGABMACAQnYAgAAAAAAAAAOAAAAAAAAAAEAAAAAAAAAAQAAABAAAABw" +
    157     "AAAAAgAAAAcAAACwAAAAAwAAAAMAAADMAAAABAAAAAEAAADwAAAABQAAAAUAAAD4AAAABgAAAAEA" +
    158     "AAAgAQAAASAAAAIAAABAAQAAAyAAAAIAAAB8AQAAARAAAAEAAACIAQAAAiAAABAAAACOAQAAACAA" +
    159     "AAEAAAC3AgAAAxAAAAEAAADIAgAAABAAAAEAAADMAgAA");
    160 }
    161