blob: 3ebe2c1cda63e1b608e7d896fe2afc6d4a4ffc48 [file] [log] [blame]
David Brazdil331a5e12019-04-01 22:46:16 +00001/*
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
17import dalvik.system.InMemoryDexClassLoader;
18import java.lang.reflect.Method;
19import java.io.File;
20import java.nio.ByteBuffer;
21import java.util.Base64;
22
23public 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
David Brazdil35a3f6a2019-03-04 15:59:06 +000043 private static void test(ClassLoader loader,
44 boolean expectedHasVdexFile,
David Brazdil7126c5b2019-03-05 00:02:51 +000045 boolean expectedBackedByOat,
David Brazdil35a3f6a2019-03-04 15:59:06 +000046 boolean invokeMethod) throws Exception {
47 // If ART created a vdex file, it must have verified all the classes.
David Brazdil7126c5b2019-03-05 00:02:51 +000048 // 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;
David Brazdil35a3f6a2019-03-04 15:59:06 +000051
David Brazdil331a5e12019-04-01 22:46:16 +000052 waitForVerifier();
David Brazdil35a3f6a2019-03-04 15:59:06 +000053 check(expectedClassesVerified, areClassesVerified(loader), "areClassesVerified");
54 check(expectedHasVdexFile, hasVdexFile(loader), "areClassesVerified");
David Brazdil7126c5b2019-03-05 00:02:51 +000055 check(expectedBackedByOat, isBackedByOatFile(loader), "isBackedByOatFile");
56 check(expectedBackedByOat, areClassesPreverified(loader), "areClassesPreverified");
David Brazdil331a5e12019-04-01 22:46:16 +000057
58 if (invokeMethod) {
59 loader.loadClass("art.ClassB").getDeclaredMethod("printHello").invoke(null);
Nicolas Geoffrayd1cda882019-10-23 15:18:20 +010060
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 }
David Brazdil331a5e12019-04-01 22:46:16 +000067 }
68 }
69
70 public static void main(String[] args) throws Exception {
71 System.loadLibrary(args[0]);
72 ClassLoader[] loaders = null;
David Brazdil7126c5b2019-03-05 00:02:51 +000073
David Brazdil527072e2019-04-03 15:15:40 +010074 // Feature only enabled for target SDK version Q and later.
75 setTargetSdkVersion(/* Q */ 29);
76
David Brazdil7126c5b2019-03-05 00:02:51 +000077 // Feature is disabled in debuggable mode because runtime threads are not
78 // allowed to load classes.
David Brazdil35a3f6a2019-03-04 15:59:06 +000079 boolean featureEnabled = !isDebuggable();
David Brazdil331a5e12019-04-01 22:46:16 +000080
David Brazdil35a3f6a2019-03-04 15:59:06 +000081 // Data directory not set. Background verification job should not have run
82 // and vdex should not have been created.
David Brazdil7126c5b2019-03-05 00:02:51 +000083 test(singleLoader(), /*hasVdex*/ false, /*backedByOat*/ false, /*invokeMethod*/ true);
David Brazdil35a3f6a2019-03-04 15:59:06 +000084
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.
David Brazdil7126c5b2019-03-05 00:02:51 +000090 test(singleLoader(), /*hasVdex*/ featureEnabled, /*backedByOat*/ false, /*invokeMethod*/ true);
David Brazdil30167d22019-04-03 14:30:45 +010091 test(singleLoader(), /*hasVdex*/ featureEnabled, /*backedByOat*/ featureEnabled,
92 /*invokeMethod*/ true);
David Brazdil331a5e12019-04-01 22:46:16 +000093
94 // Test loading the two dex files with separate class loaders.
95 // Background verification task should still verify all classes.
96 loaders = multiLoader();
David Brazdil7126c5b2019-03-05 00:02:51 +000097 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);
David Brazdil331a5e12019-04-01 22:46:16 +0000118 }
119
120 private static native boolean isDebuggable();
David Brazdil527072e2019-04-03 15:15:40 +0100121 private static native int setTargetSdkVersion(int version);
David Brazdil35a3f6a2019-03-04 15:59:06 +0000122 private static native void setProcessDataDir(String path);
David Brazdil331a5e12019-04-01 22:46:16 +0000123 private static native void waitForVerifier();
124 private static native boolean areClassesVerified(ClassLoader loader);
David Brazdil35a3f6a2019-03-04 15:59:06 +0000125 private static native boolean hasVdexFile(ClassLoader loader);
David Brazdil7126c5b2019-03-05 00:02:51 +0000126 private static native boolean isBackedByOatFile(ClassLoader loader);
127 private static native boolean areClassesPreverified(ClassLoader loader);
Nicolas Geoffrayd1cda882019-10-23 15:18:20 +0100128 private static native String getCompilerFilter(Class cls);
David Brazdil331a5e12019-04-01 22:46:16 +0000129
130 // Defined in 674-hiddenapi.
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}