1 /*
2  * Copyright (C) 2021 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.PathClassLoader;
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       throw new Error("");
29     }
30   }
31 
singleLoader()32   private static ClassLoader singleLoader() {
33     return new PathClassLoader(DEX_EXTRA, /*parent*/null);
34   }
35 
test(ClassLoader loader, boolean expectedHasVdexFile, boolean expectedBackedByOat, boolean invokeMethod)36   private static void test(ClassLoader loader,
37                            boolean expectedHasVdexFile,
38                            boolean expectedBackedByOat,
39                            boolean invokeMethod) throws Exception {
40     // If ART created a vdex file, it must have verified all the classes.
41     // That happens if and only if we expect a vdex at the end of the test but
42     // do not expect it to have been loaded.
43     boolean expectedClassesVerified = expectedHasVdexFile && !expectedBackedByOat;
44 
45     waitForVerifier();
46     check(expectedClassesVerified, areClassesVerified(loader), "areClassesVerified");
47     check(expectedHasVdexFile, hasVdexFile(loader), "hasVdexFile");
48     check(expectedBackedByOat, isBackedByOatFile(loader), "isBackedByOatFile");
49     check(expectedBackedByOat, areClassesPreverified(loader), "areClassesPreverified");
50 
51     if (invokeMethod) {
52       loader.loadClass("art.ClassB").getDeclaredMethod("printHello").invoke(null);
53     }
54 
55     if (expectedBackedByOat) {
56       String filter = getCompilerFilter(loader.loadClass("art.ClassB"));
57       if (!("verify".equals(filter))) {
58         throw new Error("Expected verify, got " + filter);
59       }
60     }
61   }
62 
main(String[] args)63   public static void main(String[] args) throws Exception {
64     System.loadLibrary(args[0]);
65 
66     // Feature is disabled in debuggable mode because runtime threads are not
67     // allowed to load classes.
68     boolean featureEnabled = !isDebuggable();
69 
70     // SDK version not set. Background verification job should not have run
71     // and vdex should not have been created.
72     test(singleLoader(), /*hasVdex*/ false, /*backedByOat*/ false, /*invokeMethod*/ true);
73 
74     // Feature only enabled for target SDK version Q and later.
75     setTargetSdkVersion(/* Q */ 29);
76 
77     // SDK version directory is now set. Background verification job should have run,
78     // should have verified classes and written results to a vdex.
79     test(singleLoader(), /*hasVdex*/ featureEnabled, /*backedByOat*/ false, /*invokeMethod*/ true);
80     test(singleLoader(), /*hasVdex*/ featureEnabled, /*backedByOat*/ featureEnabled,
81         /*invokeMethod*/ true);
82   }
83 
isDebuggable()84   private static native boolean isDebuggable();
setTargetSdkVersion(int version)85   private static native int setTargetSdkVersion(int version);
waitForVerifier()86   private static native void waitForVerifier();
areClassesVerified(ClassLoader loader)87   private static native boolean areClassesVerified(ClassLoader loader);
hasVdexFile(ClassLoader loader)88   private static native boolean hasVdexFile(ClassLoader loader);
isBackedByOatFile(ClassLoader loader)89   private static native boolean isBackedByOatFile(ClassLoader loader);
areClassesPreverified(ClassLoader loader)90   private static native boolean areClassesPreverified(ClassLoader loader);
getCompilerFilter(Class cls)91   private static native String getCompilerFilter(Class cls);
92 
93   private static final String DEX_LOCATION = System.getenv("DEX_LOCATION");
94   private static final String DEX_EXTRA =
95       new File(DEX_LOCATION, "692-vdex-secondary-loader-ex.jar").getAbsolutePath();
96 }
97