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 if (expectedBackedByOat) { 62 String filter = getCompilerFilter(loader.loadClass("art.ClassB")); 63 if (!("verify".equals(filter))) { 64 throw new Error("Expected verify, got " + filter); 65 } 66 } 67 } 68 } 69 main(String[] args)70 public static void main(String[] args) throws Exception { 71 System.loadLibrary(args[0]); 72 ClassLoader[] loaders = null; 73 74 // Feature only enabled for target SDK version Q and later. 75 setTargetSdkVersion(/* Q */ 29); 76 77 // Feature is disabled in debuggable mode because runtime threads are not 78 // allowed to load classes. 79 boolean featureEnabled = !isDebuggable(); 80 81 // Data directory not set. Background verification job should not have run 82 // and vdex should not have been created. 83 test(singleLoader(), /*hasVdex*/ false, /*backedByOat*/ false, /*invokeMethod*/ true); 84 85 // Set data directory for this process. 86 setProcessDataDir(DEX_LOCATION); 87 88 // Data directory is now set. Background verification job should have run, 89 // should have verified classes and written results to a vdex. 90 test(singleLoader(), /*hasVdex*/ featureEnabled, /*backedByOat*/ false, /*invokeMethod*/ true); 91 test(singleLoader(), /*hasVdex*/ featureEnabled, /*backedByOat*/ featureEnabled, 92 /*invokeMethod*/ true); 93 94 // Test loading the two dex files with separate class loaders. 95 // Background verification task should still verify all classes. 96 loaders = multiLoader(); 97 test(loaders[0], /*hasVdex*/ featureEnabled, /*backedByOat*/ false, /*invokeMethod*/ false); 98 test(loaders[1], /*hasVdex*/ featureEnabled, /*backedByOat*/ false, /*invokeMethod*/ true); 99 100 loaders = multiLoader(); 101 test(loaders[0], /*hasVdex*/ featureEnabled, /*backedByOat*/ featureEnabled, 102 /*invokeMethod*/ false); 103 test(loaders[1], /*hasVdex*/ featureEnabled, /*backedByOat*/ featureEnabled, 104 /*invokeMethod*/ true); 105 106 // Change boot classpath checksum. 107 appendToBootClassLoader(DEX_EXTRA, /*isCorePlatform*/ false); 108 109 loaders = multiLoader(); 110 test(loaders[0], /*hasVdex*/ featureEnabled, /*backedByOat*/ false, /*invokeMethod*/ false); 111 test(loaders[1], /*hasVdex*/ featureEnabled, /*backedByOat*/ false, /*invokeMethod*/ true); 112 113 loaders = multiLoader(); 114 test(loaders[0], /*hasVdex*/ featureEnabled, /*backedByOat*/ featureEnabled, 115 /*invokeMethod*/ false); 116 test(loaders[1], /*hasVdex*/ featureEnabled, /*backedByOat*/ featureEnabled, 117 /*invokeMethod*/ true); 118 } 119 isDebuggable()120 private static native boolean isDebuggable(); setTargetSdkVersion(int version)121 private static native int setTargetSdkVersion(int version); setProcessDataDir(String path)122 private static native void setProcessDataDir(String path); waitForVerifier()123 private static native void waitForVerifier(); areClassesVerified(ClassLoader loader)124 private static native boolean areClassesVerified(ClassLoader loader); hasVdexFile(ClassLoader loader)125 private static native boolean hasVdexFile(ClassLoader loader); isBackedByOatFile(ClassLoader loader)126 private static native boolean isBackedByOatFile(ClassLoader loader); areClassesPreverified(ClassLoader loader)127 private static native boolean areClassesPreverified(ClassLoader loader); getCompilerFilter(Class cls)128 private static native String getCompilerFilter(Class cls); 129 130 // Defined in 674-hiddenapi. appendToBootClassLoader(String dexPath, boolean isCorePlatform)131 private static native void appendToBootClassLoader(String dexPath, boolean isCorePlatform); 132 133 private static final String DEX_LOCATION = System.getenv("DEX_LOCATION"); 134 private static final String DEX_EXTRA = 135 new File(DEX_LOCATION, "692-vdex-inmem-loader-ex.jar").getAbsolutePath(); 136 137 private static final byte[] DEX_BYTES_A = Base64.getDecoder().decode( 138 "ZGV4CjAzNQBxYu/tdPfiHaRPYr5yaT6ko9V/xMinr1OwAgAAcAAAAHhWNBIAAAAAAAAAABwCAAAK" + 139 "AAAAcAAAAAQAAACYAAAAAgAAAKgAAAAAAAAAAAAAAAMAAADAAAAAAQAAANgAAAC4AQAA+AAAADAB" + 140 "AAA4AQAARQEAAEwBAABPAQAAXQEAAHEBAACFAQAAiAEAAJIBAAAEAAAABQAAAAYAAAAHAAAAAwAA" + 141 "AAIAAAAAAAAABwAAAAMAAAAAAAAAAAABAAAAAAAAAAAACAAAAAEAAQAAAAAAAAAAAAEAAAABAAAA" + 142 "AAAAAAEAAAAAAAAACQIAAAAAAAABAAAAAAAAACwBAAADAAAAGgACABEAAAABAAEAAQAAACgBAAAE" + 143 "AAAAcBACAAAADgATAA4AFQAOAAY8aW5pdD4AC0NsYXNzQS5qYXZhAAVIZWxsbwABTAAMTGFydC9D" + 144 "bGFzc0E7ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwABVgAIZ2V0SGVs" + 145 "bG8AdX5+RDh7ImNvbXBpbGF0aW9uLW1vZGUiOiJkZWJ1ZyIsIm1pbi1hcGkiOjEsInNoYS0xIjoi" + 146 "OTY2MDhmZDdiYmNjZGQyMjc2Y2Y4OTI4M2QyYjgwY2JmYzRmYzgxYyIsInZlcnNpb24iOiIxLjUu" + 147 "NC1kZXYifQAAAAIAAIGABJACAQn4AQAAAAAADAAAAAAAAAABAAAAAAAAAAEAAAAKAAAAcAAAAAIA" + 148 "AAAEAAAAmAAAAAMAAAACAAAAqAAAAAUAAAADAAAAwAAAAAYAAAABAAAA2AAAAAEgAAACAAAA+AAA" + 149 "AAMgAAACAAAAKAEAAAIgAAAKAAAAMAEAAAAgAAABAAAACQIAAAMQAAABAAAAGAIAAAAQAAABAAAA" + 150 "HAIAAA=="); 151 private static final byte[] DEX_BYTES_B = Base64.getDecoder().decode( 152 "ZGV4CjAzNQB+hWvce73hXt7ZVNgp9RAyMLSwQzsWUjV4AwAAcAAAAHhWNBIAAAAAAAAAAMwCAAAQ" + 153 "AAAAcAAAAAcAAACwAAAAAwAAAMwAAAABAAAA8AAAAAUAAAD4AAAAAQAAACABAAA4AgAAQAEAAI4B" + 154 "AACWAQAAowEAAKYBAAC0AQAAwgEAANkBAADtAQAAAQIAABUCAAAYAgAAHAIAACYCAAArAgAANwIA" + 155 "AEACAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAAAgAAAAQAAAAAAAAACQAAAAYAAAAAAAAA" + 156 "CgAAAAYAAACIAQAABQACAAwAAAAAAAAACwAAAAEAAQAAAAAAAQABAA0AAAACAAIADgAAAAMAAQAA" + 157 "AAAAAQAAAAEAAAADAAAAAAAAAAEAAAAAAAAAtwIAAAAAAAABAAEAAQAAAHwBAAAEAAAAcBAEAAAA" + 158 "DgACAAAAAgAAAIABAAAKAAAAYgAAAHEAAAAAAAwBbiADABAADgATAA4AFQAOlgAAAAABAAAABAAG" + 159 "PGluaXQ+AAtDbGFzc0IuamF2YQABTAAMTGFydC9DbGFzc0E7AAxMYXJ0L0NsYXNzQjsAFUxqYXZh" + 160 "L2lvL1ByaW50U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsA" + 161 "EkxqYXZhL2xhbmcvU3lzdGVtOwABVgACVkwACGdldEhlbGxvAANvdXQACnByaW50SGVsbG8AB3By" + 162 "aW50bG4AdX5+RDh7ImNvbXBpbGF0aW9uLW1vZGUiOiJkZWJ1ZyIsIm1pbi1hcGkiOjEsInNoYS0x" + 163 "IjoiOTY2MDhmZDdiYmNjZGQyMjc2Y2Y4OTI4M2QyYjgwY2JmYzRmYzgxYyIsInZlcnNpb24iOiIx" + 164 "LjUuNC1kZXYifQAAAAIAAYGABMACAQnYAgAAAAAAAAAOAAAAAAAAAAEAAAAAAAAAAQAAABAAAABw" + 165 "AAAAAgAAAAcAAACwAAAAAwAAAAMAAADMAAAABAAAAAEAAADwAAAABQAAAAUAAAD4AAAABgAAAAEA" + 166 "AAAgAQAAASAAAAIAAABAAQAAAyAAAAIAAAB8AQAAARAAAAEAAACIAQAAAiAAABAAAACOAQAAACAA" + 167 "AAEAAAC3AgAAAxAAAAEAAADIAgAAABAAAAEAAADMAgAA"); 168 } 169