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