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