1 /* 2 * Copyright (C) 2016 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 package art; 18 19 import java.util.*; 20 import java.util.function.*; 21 import java.lang.reflect.*; 22 import java.nio.ByteBuffer; 23 import dalvik.system.InMemoryDexClassLoader; 24 25 public class Test1946 { 26 // Base64 encoded dex file containing the following classes. Note the class E cannot be loaded. 27 // public class A {} 28 // public class B {} 29 // public class C {} 30 // public class D {} 31 // public class E extends ClassNotThere {} 32 private static final byte[] TEST_CLASSES = Base64.getDecoder().decode( 33 "ZGV4CjAzNQDzTO8rVDlKlz80vQF4NLYV5MjMMjHlOtRoAwAAcAAAAHhWNBIAAAAAAAAAAOACAAAO" + 34 "AAAAcAAAAAgAAACoAAAAAQAAAMgAAAAAAAAAAAAAAAcAAADUAAAABQAAAAwBAAC8AQAArAEAACQC" + 35 "AAAsAgAANAIAADwCAABEAgAATAIAAFQCAABZAgAAXgIAAGMCAAB0AgAAeQIAAH4CAACSAgAABgAA" + 36 "AAcAAAAIAAAACQAAAAoAAAALAAAADAAAAA0AAAANAAAABwAAAAAAAAAAAAAAAAAAAAEAAAAAAAAA" + 37 "AgAAAAAAAAADAAAAAAAAAAQAAAAAAAAABQAAAAAAAAAGAAAAAAAAAAAAAAAAAAAABgAAAAAAAAAB" + 38 "AAAAAAAAAK4CAAAAAAAAAQAAAAAAAAAGAAAAAAAAAAIAAAAAAAAAuAIAAAAAAAACAAAAAAAAAAYA" + 39 "AAAAAAAAAwAAAAAAAADCAgAAAAAAAAQAAAAAAAAABgAAAAAAAAAEAAAAAAAAAMwCAAAAAAAABQAA" + 40 "AAAAAAADAAAAAAAAAAUAAAAAAAAA1gIAAAAAAAABAAEAAQAAAJUCAAAEAAAAcBAGAAAADgABAAEA" + 41 "AQAAAJoCAAAEAAAAcBAGAAAADgABAAEAAQAAAJ8CAAAEAAAAcBAGAAAADgABAAEAAQAAAKQCAAAE" + 42 "AAAAcBAGAAAADgABAAEAAQAAAKkCAAAEAAAAcBADAAAADgAGPGluaXQ+AAZBLmphdmEABkIuamF2" + 43 "YQAGQy5qYXZhAAZELmphdmEABkUuamF2YQADTEE7AANMQjsAA0xDOwAPTENsYXNzTm90VGhlcmU7" + 44 "AANMRDsAA0xFOwASTGphdmEvbGFuZy9PYmplY3Q7AAFWAAEABw4AAQAHDgABAAcOAAEABw4AAQAH" + 45 "DgAAAAEAAICABKwDAAABAAGAgATEAwAAAQACgIAE3AMAAAEABICABPQDAAABAAWAgASMBAsAAAAA" + 46 "AAAAAQAAAAAAAAABAAAADgAAAHAAAAACAAAACAAAAKgAAAADAAAAAQAAAMgAAAAFAAAABwAAANQA" + 47 "AAAGAAAABQAAAAwBAAABIAAABQAAAKwBAAACIAAADgAAACQCAAADIAAABQAAAJUCAAAAIAAABQAA" + 48 "AK4CAAAAEAAAAQAAAOACAAA="); 49 public class TMP1 {} 50 public class TMP2 {} 51 public class TMP3 extends ArrayList {} 52 check(boolean b, Supplier<String> msg)53 private static void check(boolean b, Supplier<String> msg) { 54 if (!b) { 55 throw new Error("Test failed! " + msg.get()); 56 } 57 } 58 checkEq(T[] full, T[] sub, final String msg)59 private static <T> void checkEq(T[] full, T[] sub, final String msg) { 60 List<T> f = Arrays.asList(full); 61 check(full.length == sub.length, () -> "not equal length"); 62 Supplier<String> msgGen = 63 () -> Arrays.toString(full) + " is not same as " + Arrays.toString(sub) + ": " + msg; 64 check(new HashSet<T>(Arrays.asList(full)).containsAll(Arrays.asList(sub)), msgGen); 65 } 66 checkSubset(T[] full, T[] sub, final String msg)67 private static <T> void checkSubset(T[] full, T[] sub, final String msg) { 68 Supplier<String> msgGen = 69 () -> Arrays.toString(full) + " does not contain all of " + Arrays.toString(sub) + ": " + msg; 70 check(new HashSet<T>(Arrays.asList(full)).containsAll(Arrays.asList(sub)), msgGen); 71 } 72 run()73 public static void run() throws Exception { 74 initializeTest(); 75 // Check a few random classes in BCP. 76 checkSubset(getClassloaderDescriptors(null), 77 new String[] { "Ljava/lang/String;", "Ljava/util/TreeSet;" }, 78 "Missing entries for null classloader."); 79 // Make sure that null is the same as BootClassLoader 80 checkEq(getClassloaderDescriptors(null), 81 getClassloaderDescriptors(Object.class.getClassLoader()), "Object not in bcp!"); 82 // Check the current class loader gets expected classes. 83 checkSubset(getClassloaderDescriptors(Test1946.class.getClassLoader()), 84 new String[] { 85 "Lart/Test1946;", 86 "Lart/Test1946$TMP1;", 87 "Lart/Test1946$TMP2;", 88 "Lart/Test1946$TMP3;" 89 }, 90 "Missing entries for current class classloader."); 91 // Check that the result is exactly what we expect and includes classes that fail verification. 92 checkEq(getClassloaderDescriptors(makeClassLoaderFrom(TEST_CLASSES, 93 ClassLoader.getSystemClassLoader())), 94 new String[] { "LA;", "LB;", "LC;", "LD;", "LE;" }, 95 "Unexpected classes in custom classloader"); 96 checkEq(getClassloaderDescriptors(makeClassLoaderFrom(TEST_CLASSES, 97 Object.class.getClassLoader())), 98 new String[] { "LA;", "LB;", "LC;", "LD;", "LE;" }, 99 "Unexpected classes in custom classloader"); 100 checkEq(getClassloaderDescriptors(makeClassLoaderFrom(TEST_CLASSES, 101 Test1946.class.getClassLoader())), 102 new String[] { "LA;", "LB;", "LC;", "LD;", "LE;" }, 103 "Unexpected classes in custom classloader"); 104 // Check we only get 1 copy of each descriptor. 105 checkEq(getClassloaderDescriptors(makeClassLoaderFrom(Arrays.asList(TEST_CLASSES, TEST_CLASSES), 106 Test1946.class.getClassLoader())), 107 new String[] { "LA;", "LB;", "LC;", "LD;", "LE;" }, 108 "Unexpected classes in custom classloader"); 109 System.out.println("Passed!"); 110 } 111 makeClassLoaderFrom(byte[] data, ClassLoader parent)112 private static ClassLoader makeClassLoaderFrom(byte[] data, ClassLoader parent) throws Exception { 113 return new InMemoryDexClassLoader(ByteBuffer.wrap(data), parent); 114 } 115 makeClassLoaderFrom(List<byte[]> data, ClassLoader parent)116 private static ClassLoader makeClassLoaderFrom(List<byte[]> data, ClassLoader parent) 117 throws Exception { 118 ArrayList<ByteBuffer> bufs = new ArrayList<>(); 119 for (byte[] d : data) { 120 bufs.add(ByteBuffer.wrap(d)); 121 } 122 return new InMemoryDexClassLoader(bufs.toArray(new ByteBuffer[0]), parent); 123 } 124 initializeTest()125 private static native void initializeTest(); getClassloaderDescriptors(ClassLoader loader)126 private static native String[] getClassloaderDescriptors(ClassLoader loader); 127 } 128