xref: /aosp_15_r20/art/test/693-vdex-inmem-loader-evict/src/Main.java (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2019 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker import dalvik.system.InMemoryDexClassLoader;
18*795d594fSAndroid Build Coastguard Worker import java.lang.reflect.Method;
19*795d594fSAndroid Build Coastguard Worker import java.io.File;
20*795d594fSAndroid Build Coastguard Worker import java.nio.ByteBuffer;
21*795d594fSAndroid Build Coastguard Worker import java.util.Base64;
22*795d594fSAndroid Build Coastguard Worker 
23*795d594fSAndroid Build Coastguard Worker public class Main {
main(String[] args)24*795d594fSAndroid Build Coastguard Worker   public static void main(String[] args) throws Exception {
25*795d594fSAndroid Build Coastguard Worker     System.loadLibrary(args[0]);
26*795d594fSAndroid Build Coastguard Worker 
27*795d594fSAndroid Build Coastguard Worker     // Feature only enabled for target SDK version Q and later.
28*795d594fSAndroid Build Coastguard Worker     setTargetSdkVersion(/* Q */ 29);
29*795d594fSAndroid Build Coastguard Worker 
30*795d594fSAndroid Build Coastguard Worker     if (isDebuggable()) {
31*795d594fSAndroid Build Coastguard Worker       // Background verification is disabled in debuggable mode. This test makes
32*795d594fSAndroid Build Coastguard Worker       // no sense then.
33*795d594fSAndroid Build Coastguard Worker       return;
34*795d594fSAndroid Build Coastguard Worker     }
35*795d594fSAndroid Build Coastguard Worker 
36*795d594fSAndroid Build Coastguard Worker     if (!hasOatFile()) {
37*795d594fSAndroid Build Coastguard Worker       // We only generate vdex files if the oat directories are created.
38*795d594fSAndroid Build Coastguard Worker       return;
39*795d594fSAndroid Build Coastguard Worker     }
40*795d594fSAndroid Build Coastguard Worker 
41*795d594fSAndroid Build Coastguard Worker     setProcessDataDir(DEX_LOCATION);
42*795d594fSAndroid Build Coastguard Worker 
43*795d594fSAndroid Build Coastguard Worker     final int maxCacheSize = getVdexCacheSize();
44*795d594fSAndroid Build Coastguard Worker     final int numDexFiles = DEX_BYTES_CHECKSUMS.length;
45*795d594fSAndroid Build Coastguard Worker     if (numDexFiles <= maxCacheSize) {
46*795d594fSAndroid Build Coastguard Worker       throw new IllegalStateException("Not enough dex files to test cache eviction");
47*795d594fSAndroid Build Coastguard Worker     }
48*795d594fSAndroid Build Coastguard Worker 
49*795d594fSAndroid Build Coastguard Worker     // Simply load each dex file one by one.
50*795d594fSAndroid Build Coastguard Worker     check(0, getCurrentCacheSize(), "There should be no vdex files in the beginning");
51*795d594fSAndroid Build Coastguard Worker     for (int i = 0; i < numDexFiles; ++i) {
52*795d594fSAndroid Build Coastguard Worker       ClassLoader loader = loadDex(i);
53*795d594fSAndroid Build Coastguard Worker       waitForVerifier();
54*795d594fSAndroid Build Coastguard Worker       check(true, hasVdexFile(loader), "Loading dex file should have produced a vdex");
55*795d594fSAndroid Build Coastguard Worker       check(Math.min(i + 1, maxCacheSize), getCurrentCacheSize(),
56*795d594fSAndroid Build Coastguard Worker           "Unexpected number of cache entries");
57*795d594fSAndroid Build Coastguard Worker     }
58*795d594fSAndroid Build Coastguard Worker 
59*795d594fSAndroid Build Coastguard Worker     // More complicated pattern where some dex files get reused.
60*795d594fSAndroid Build Coastguard Worker     for (int s = 1; s < numDexFiles; ++s) {
61*795d594fSAndroid Build Coastguard Worker       for (int i = 0; i < maxCacheSize; ++i) {
62*795d594fSAndroid Build Coastguard Worker         ClassLoader loader = loadDex(i);
63*795d594fSAndroid Build Coastguard Worker         waitForVerifier();
64*795d594fSAndroid Build Coastguard Worker         check(true, hasVdexFile(loader), "Loading dex file should have produced a vdex");
65*795d594fSAndroid Build Coastguard Worker         check(maxCacheSize, getCurrentCacheSize(), "Unexpected number of cache entries");
66*795d594fSAndroid Build Coastguard Worker       }
67*795d594fSAndroid Build Coastguard Worker     }
68*795d594fSAndroid Build Coastguard Worker   }
69*795d594fSAndroid Build Coastguard Worker 
isDebuggable()70*795d594fSAndroid Build Coastguard Worker   private static native boolean isDebuggable();
hasOatFile()71*795d594fSAndroid Build Coastguard Worker   private static native boolean hasOatFile();
setTargetSdkVersion(int version)72*795d594fSAndroid Build Coastguard Worker   private static native int setTargetSdkVersion(int version);
setProcessDataDir(String path)73*795d594fSAndroid Build Coastguard Worker   private static native void setProcessDataDir(String path);
waitForVerifier()74*795d594fSAndroid Build Coastguard Worker   private static native void waitForVerifier();
hasVdexFile(ClassLoader loader)75*795d594fSAndroid Build Coastguard Worker   private static native boolean hasVdexFile(ClassLoader loader);
getVdexCacheSize()76*795d594fSAndroid Build Coastguard Worker   private static native int getVdexCacheSize();
isAnonymousVdexBasename(String basename)77*795d594fSAndroid Build Coastguard Worker   private static native boolean isAnonymousVdexBasename(String basename);
78*795d594fSAndroid Build Coastguard Worker 
check(T expected, T actual, String message)79*795d594fSAndroid Build Coastguard Worker   private static <T> void check(T expected, T actual, String message) {
80*795d594fSAndroid Build Coastguard Worker     if (!expected.equals(actual)) {
81*795d594fSAndroid Build Coastguard Worker       System.err.println("ERROR: " + message + " (expected=" + expected.toString() +
82*795d594fSAndroid Build Coastguard Worker           ", actual=" + actual.toString() + ")");
83*795d594fSAndroid Build Coastguard Worker     }
84*795d594fSAndroid Build Coastguard Worker   }
85*795d594fSAndroid Build Coastguard Worker 
getCurrentCacheSize()86*795d594fSAndroid Build Coastguard Worker   private static int getCurrentCacheSize() {
87*795d594fSAndroid Build Coastguard Worker     int count = 0;
88*795d594fSAndroid Build Coastguard Worker     File folder = new File(DEX_LOCATION, "oat");
89*795d594fSAndroid Build Coastguard Worker     File[] subfolders = folder.listFiles();
90*795d594fSAndroid Build Coastguard Worker     if (subfolders.length != 1) {
91*795d594fSAndroid Build Coastguard Worker       throw new IllegalStateException("Expect only one subfolder - isa");
92*795d594fSAndroid Build Coastguard Worker     }
93*795d594fSAndroid Build Coastguard Worker     folder = subfolders[0];
94*795d594fSAndroid Build Coastguard Worker     for (File f : folder.listFiles()) {
95*795d594fSAndroid Build Coastguard Worker       if (f.isFile() && isAnonymousVdexBasename(f.getName())) {
96*795d594fSAndroid Build Coastguard Worker         count++;
97*795d594fSAndroid Build Coastguard Worker       }
98*795d594fSAndroid Build Coastguard Worker     }
99*795d594fSAndroid Build Coastguard Worker     return count;
100*795d594fSAndroid Build Coastguard Worker   }
101*795d594fSAndroid Build Coastguard Worker 
createDex(int index)102*795d594fSAndroid Build Coastguard Worker   private static byte[] createDex(int index) {
103*795d594fSAndroid Build Coastguard Worker     if (index >= 100) {
104*795d594fSAndroid Build Coastguard Worker       throw new IllegalArgumentException("Not more than two decimals");
105*795d594fSAndroid Build Coastguard Worker     }
106*795d594fSAndroid Build Coastguard Worker 
107*795d594fSAndroid Build Coastguard Worker     // Clone the base dex file. This is the dex file for index 0 (class ID "01").
108*795d594fSAndroid Build Coastguard Worker     byte[] dex = DEX_BYTES_BASE.clone();
109*795d594fSAndroid Build Coastguard Worker 
110*795d594fSAndroid Build Coastguard Worker     // Overwrite the checksum and sha1 signature.
111*795d594fSAndroid Build Coastguard Worker     System.arraycopy(DEX_BYTES_CHECKSUMS[index], 0, dex, DEX_BYTES_CHECKSUM_OFFSET,
112*795d594fSAndroid Build Coastguard Worker         DEX_BYTES_CHECKSUM_SIZE);
113*795d594fSAndroid Build Coastguard Worker 
114*795d594fSAndroid Build Coastguard Worker     // Check that the class ID offsets match expectations - they should contains "01".
115*795d594fSAndroid Build Coastguard Worker     if (dex[DEX_BYTES_CLASS_ID_OFFSET1 + 0] != 0x30 ||
116*795d594fSAndroid Build Coastguard Worker         dex[DEX_BYTES_CLASS_ID_OFFSET1 + 1] != 0x31 ||
117*795d594fSAndroid Build Coastguard Worker         dex[DEX_BYTES_CLASS_ID_OFFSET2 + 0] != 0x30 ||
118*795d594fSAndroid Build Coastguard Worker         dex[DEX_BYTES_CLASS_ID_OFFSET2 + 1] != 0x31) {
119*795d594fSAndroid Build Coastguard Worker       throw new IllegalStateException("Wrong class name values");
120*795d594fSAndroid Build Coastguard Worker     }
121*795d594fSAndroid Build Coastguard Worker 
122*795d594fSAndroid Build Coastguard Worker     // Overwrite class ID.
123*795d594fSAndroid Build Coastguard Worker     byte str_id1 = (byte) (0x30 + ((index + 1) / 10));
124*795d594fSAndroid Build Coastguard Worker     byte str_id2 = (byte) (0x30 + ((index + 1) % 10));
125*795d594fSAndroid Build Coastguard Worker     dex[DEX_BYTES_CLASS_ID_OFFSET1 + 0] = str_id1;
126*795d594fSAndroid Build Coastguard Worker     dex[DEX_BYTES_CLASS_ID_OFFSET1 + 1] = str_id2;
127*795d594fSAndroid Build Coastguard Worker     dex[DEX_BYTES_CLASS_ID_OFFSET2 + 0] = str_id1;
128*795d594fSAndroid Build Coastguard Worker     dex[DEX_BYTES_CLASS_ID_OFFSET2 + 1] = str_id2;
129*795d594fSAndroid Build Coastguard Worker 
130*795d594fSAndroid Build Coastguard Worker     return dex;
131*795d594fSAndroid Build Coastguard Worker   }
132*795d594fSAndroid Build Coastguard Worker 
loadDex(int index)133*795d594fSAndroid Build Coastguard Worker   private static ClassLoader loadDex(int index) {
134*795d594fSAndroid Build Coastguard Worker     return new InMemoryDexClassLoader(ByteBuffer.wrap(createDex(index)), /*parent*/ null);
135*795d594fSAndroid Build Coastguard Worker   }
136*795d594fSAndroid Build Coastguard Worker 
137*795d594fSAndroid Build Coastguard Worker   private static final String DEX_LOCATION = System.getenv("DEX_LOCATION");
138*795d594fSAndroid Build Coastguard Worker 
139*795d594fSAndroid Build Coastguard Worker   private static final int DEX_BYTES_CLASS_ID_OFFSET1 = 0xfd;
140*795d594fSAndroid Build Coastguard Worker   private static final int DEX_BYTES_CLASS_ID_OFFSET2 = 0x11d;
141*795d594fSAndroid Build Coastguard Worker   private static final int DEX_BYTES_CHECKSUM_OFFSET = 8;
142*795d594fSAndroid Build Coastguard Worker   private static final int DEX_BYTES_CHECKSUM_SIZE = 24;
143*795d594fSAndroid Build Coastguard Worker 
144*795d594fSAndroid Build Coastguard Worker   // Dex file for: "public class MyClass01 {}".
145*795d594fSAndroid Build Coastguard Worker   private static final byte[] DEX_BYTES_BASE = Base64.getDecoder().decode(
146*795d594fSAndroid Build Coastguard Worker     "ZGV4CjAzNQBHVjDjQ9WQ2TSezZ0exFH00hvlJrenqvNEAgAAcAAAAHhWNBIAAAAAAAAAALABAAAG" +
147*795d594fSAndroid Build Coastguard Worker     "AAAAcAAAAAMAAACIAAAAAQAAAJQAAAAAAAAAAAAAAAIAAACgAAAAAQAAALAAAAB0AQAA0AAAAOwA" +
148*795d594fSAndroid Build Coastguard Worker     "AAD0AAAAAQEAABUBAAAlAQAAKAEAAAEAAAACAAAABAAAAAQAAAACAAAAAAAAAAAAAAAAAAAAAQAA" +
149*795d594fSAndroid Build Coastguard Worker     "AAAAAAAAAAAAAQAAAAEAAAAAAAAAAwAAAAAAAACfAQAAAAAAAAEAAQABAAAA6AAAAAQAAABwEAEA" +
150*795d594fSAndroid Build Coastguard Worker     "AAAOAAEADgAGPGluaXQ+AAtMTXlDbGFzczAxOwASTGphdmEvbGFuZy9PYmplY3Q7AA5NeUNsYXNz" +
151*795d594fSAndroid Build Coastguard Worker     "MDEuamF2YQABVgB1fn5EOHsiY29tcGlsYXRpb24tbW9kZSI6ImRlYnVnIiwibWluLWFwaSI6MSwi" +
152*795d594fSAndroid Build Coastguard Worker     "c2hhLTEiOiI4ZjI5NTlkMDExNmMyYjdmZTZlMDUxNWQ3MTQxZTRmMGY0ZTczYzBiIiwidmVyc2lv" +
153*795d594fSAndroid Build Coastguard Worker     "biI6IjEuNS41LWRldiJ9AAAAAQAAgYAE0AEAAAAAAAAADAAAAAAAAAABAAAAAAAAAAEAAAAGAAAA" +
154*795d594fSAndroid Build Coastguard Worker     "cAAAAAIAAAADAAAAiAAAAAMAAAABAAAAlAAAAAUAAAACAAAAoAAAAAYAAAABAAAAsAAAAAEgAAAB" +
155*795d594fSAndroid Build Coastguard Worker     "AAAA0AAAAAMgAAABAAAA6AAAAAIgAAAGAAAA7AAAAAAgAAABAAAAnwEAAAMQAAABAAAArAEAAAAQ" +
156*795d594fSAndroid Build Coastguard Worker     "AAABAAAAsAEAAA==");
157*795d594fSAndroid Build Coastguard Worker 
158*795d594fSAndroid Build Coastguard Worker   // Checksum/SHA1 signature diff for classes MyClass01 - MyClassXX.
159*795d594fSAndroid Build Coastguard Worker   // This is just a convenient way of storing many similar dex files.
160*795d594fSAndroid Build Coastguard Worker   private static final byte[][] DEX_BYTES_CHECKSUMS = new byte[][] {
161*795d594fSAndroid Build Coastguard Worker     Base64.getDecoder().decode("R1Yw40PVkNk0ns2dHsRR9NIb5Sa3p6rz"),
162*795d594fSAndroid Build Coastguard Worker     Base64.getDecoder().decode("i1V1U3C8nexVk4uw185lXZd9kzd82iaA"),
163*795d594fSAndroid Build Coastguard Worker     Base64.getDecoder().decode("tFPbVPdpzuoDWqH71Ak5HpltBHg0frMU"),
164*795d594fSAndroid Build Coastguard Worker     Base64.getDecoder().decode("eFSc7dENiK8nxviKBmd/O2s7h/NAj+l/"),
165*795d594fSAndroid Build Coastguard Worker     Base64.getDecoder().decode("DlUfNQ3cuVrCHRyw/cOFhqEe+0r6wlUP"),
166*795d594fSAndroid Build Coastguard Worker     Base64.getDecoder().decode("KVaBmdG8Y8kx8ltEPXWyi9OCdL14yeiW"),
167*795d594fSAndroid Build Coastguard Worker     Base64.getDecoder().decode("K1bioDTHtPwmrPXkvZ0XYCiripH6KsC2"),
168*795d594fSAndroid Build Coastguard Worker     Base64.getDecoder().decode("oVHctdpHG3YTNeQlVCshTkFKVra9TG4k"),
169*795d594fSAndroid Build Coastguard Worker     Base64.getDecoder().decode("eVWMFHRY+w4lpn9Uo9jn+eNAmaRK4HEw"),
170*795d594fSAndroid Build Coastguard Worker     Base64.getDecoder().decode("/lW3Q3U4ot5A2qkhiv4Aj+s8zv7984MA"),
171*795d594fSAndroid Build Coastguard Worker     Base64.getDecoder().decode("BFRB+4HwRbuD164DB3sVy28dc+Ea5YVQ"),
172*795d594fSAndroid Build Coastguard Worker     Base64.getDecoder().decode("klQBLEXyr0cviHDHlqFyWPGKaQQnqMiD"),
173*795d594fSAndroid Build Coastguard Worker     Base64.getDecoder().decode("jlTcJAkpnbDI/E4msuvMyWqKxNMTN0YU"),
174*795d594fSAndroid Build Coastguard Worker     Base64.getDecoder().decode("vlUOrp4aN0PxcaqQrQmm597P+Ymu5Adt"),
175*795d594fSAndroid Build Coastguard Worker     Base64.getDecoder().decode("HlXyT1GoJk1m33O8OMaYxqy3K1Byyf1S"),
176*795d594fSAndroid Build Coastguard Worker     Base64.getDecoder().decode("d1O5toIKjTXNZkgP3p9RiiafhuKw4gUH"),
177*795d594fSAndroid Build Coastguard Worker     Base64.getDecoder().decode("11RsuG9UrFHPipOj9zjuGU9obctMJbq6"),
178*795d594fSAndroid Build Coastguard Worker     Base64.getDecoder().decode("dlSW5egObqheoHSRthlR2c2jVKLGQ3QL"),
179*795d594fSAndroid Build Coastguard Worker     Base64.getDecoder().decode("ulMgQEhC0XMhmKxHtgdURY6B6JEqNb3E"),
180*795d594fSAndroid Build Coastguard Worker     Base64.getDecoder().decode("YFV08vrcs49xYr1OBhrza5H8Ha86FODz"),
181*795d594fSAndroid Build Coastguard Worker     Base64.getDecoder().decode("jFKPxTFd3kn6K0p6n8YEPgm0hiozXW1p"),
182*795d594fSAndroid Build Coastguard Worker     Base64.getDecoder().decode("LlUZdlCXwAn4qksYL6Urw+bZC/fYuJ1T"),
183*795d594fSAndroid Build Coastguard Worker     Base64.getDecoder().decode("K1SuRt9xZX5lAVtbpMauOWLVXs2KooUA"),
184*795d594fSAndroid Build Coastguard Worker     Base64.getDecoder().decode("2FJAWIk0JS9EdvkgHjquLL9qdcLeHaRJ"),
185*795d594fSAndroid Build Coastguard Worker     Base64.getDecoder().decode("YVResABr9IvZLV8eeIhM3TXfGC+Y6/x1"),
186*795d594fSAndroid Build Coastguard Worker     Base64.getDecoder().decode("UVTrkVGIh8u7FBHgcbS9flI0CY5g2E3m"),
187*795d594fSAndroid Build Coastguard Worker     Base64.getDecoder().decode("oVIu6RsrT6HgnbPzNGiYZSpKS0cqNi+a"),
188*795d594fSAndroid Build Coastguard Worker     Base64.getDecoder().decode("2FR/slWq9YC6kJRDEw21RVGmJhr3/uKZ"),
189*795d594fSAndroid Build Coastguard Worker     Base64.getDecoder().decode("CFbaSi70ZVaumL7zsXWlD/ernHxCZPx6"),
190*795d594fSAndroid Build Coastguard Worker     Base64.getDecoder().decode("7FTY+T1/qevWQM6Yoe+OwNcUdgcCUomJ"),
191*795d594fSAndroid Build Coastguard Worker   };
192*795d594fSAndroid Build Coastguard Worker }
193