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 { check(boolean expected, boolean actual, String message)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 singleLoader()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 multiLoader()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 test(ClassLoader loader, boolean expectedHasVdexFile, boolean expectedBackedByOat, boolean invokeMethod)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 main(String[] args)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 isDebuggable()113 private static native boolean isDebuggable(); setTargetSdkVersion(int version)114 private static native int setTargetSdkVersion(int version); setProcessDataDir(String path)115 private static native void setProcessDataDir(String path); waitForVerifier()116 private static native void waitForVerifier(); areClassesVerified(ClassLoader loader)117 private static native boolean areClassesVerified(ClassLoader loader); hasVdexFile(ClassLoader loader)118 private static native boolean hasVdexFile(ClassLoader loader); isBackedByOatFile(ClassLoader loader)119 private static native boolean isBackedByOatFile(ClassLoader loader); areClassesPreverified(ClassLoader loader)120 private static native boolean areClassesPreverified(ClassLoader loader); 121 122 // Defined in 674-hiddenapi. appendToBootClassLoader(String dexPath, boolean isCorePlatform)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