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