blob: f3ff2b06687602d7567c1706620012633ec561d8 [file] [log] [blame]
Andreas Gampee492ae32016-10-28 19:34:57 -07001/*
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
Andreas Gamped5f2ccc2017-04-19 13:37:48 -070017package art;
18
Andreas Gampe52784ac2017-02-13 18:10:09 -080019import java.lang.ref.Reference;
Andreas Gampe70f16392017-01-16 14:20:10 -080020import java.lang.reflect.Constructor;
Andreas Gampee492ae32016-10-28 19:34:57 -070021import java.lang.reflect.Proxy;
Alex Light09f274f2017-02-21 15:00:48 -080022import java.util.ArrayList;
Andreas Gampee492ae32016-10-28 19:34:57 -070023import java.util.Arrays;
Andreas Gampe70f16392017-01-16 14:20:10 -080024import java.util.Comparator;
Andreas Gampee492ae32016-10-28 19:34:57 -070025
Andreas Gamped5f2ccc2017-04-19 13:37:48 -070026public class Test912 {
27 public static void run() throws Exception {
28 art.Main.bindAgentJNIForClass(Test912.class);
Andreas Gampee492ae32016-10-28 19:34:57 -070029 doTest();
30 }
31
32 public static void doTest() throws Exception {
33 testClass("java.lang.Object");
34 testClass("java.lang.String");
35 testClass("java.lang.Math");
36 testClass("java.util.List");
37
38 testClass(getProxyClass());
39
40 testClass(int.class);
41 testClass(double[].class);
Andreas Gampe4fd66ec2017-01-05 14:42:13 -080042
43 testClassType(int.class);
44 testClassType(getProxyClass());
45 testClassType(Runnable.class);
46 testClassType(String.class);
Alex Light09f274f2017-02-21 15:00:48 -080047 testClassType(ArrayList.class);
Andreas Gampe4fd66ec2017-01-05 14:42:13 -080048
49 testClassType(int[].class);
50 testClassType(Runnable[].class);
51 testClassType(String[].class);
Andreas Gampeac587272017-01-05 15:21:34 -080052
53 testClassFields(Integer.class);
54 testClassFields(int.class);
55 testClassFields(String[].class);
Andreas Gampeff9d2092017-01-06 09:12:49 -080056
Andreas Gampe18fee4d2017-01-06 11:36:35 -080057 testClassMethods(Integer.class);
58 testClassMethods(int.class);
59 testClassMethods(String[].class);
60
Andreas Gampeff9d2092017-01-06 09:12:49 -080061 testClassStatus(int.class);
62 testClassStatus(String[].class);
63 testClassStatus(Object.class);
64 testClassStatus(TestForNonInit.class);
65 try {
66 System.out.println(TestForInitFail.dummy);
67 } catch (ExceptionInInitializerError e) {
68 }
69 testClassStatus(TestForInitFail.class);
Andreas Gampe8b07e472017-01-06 14:20:39 -080070
71 testInterfaces(int.class);
72 testInterfaces(String[].class);
73 testInterfaces(Object.class);
74 testInterfaces(InfA.class);
75 testInterfaces(InfB.class);
76 testInterfaces(InfC.class);
77 testInterfaces(ClassA.class);
78 testInterfaces(ClassB.class);
79 testInterfaces(ClassC.class);
Andreas Gampe8f5b6032017-01-06 15:50:55 -080080
81 testClassLoader(String.class);
82 testClassLoader(String[].class);
83 testClassLoader(InfA.class);
84 testClassLoader(getProxyClass());
Andreas Gampe70f16392017-01-16 14:20:10 -080085
86 testClassLoaderClasses();
Andreas Gampe812a2442017-01-19 22:04:46 -080087
88 System.out.println();
89
90 testClassVersion();
Andreas Gampee6377462017-01-20 17:37:50 -080091
92 System.out.println();
93
Andreas Gamped5f2ccc2017-04-19 13:37:48 -070094 // Use a dedicated thread to have a well-defined current thread.
95 Thread classEventsThread = new Thread("ClassEvents") {
96 @Override
97 public void run() {
98 try {
99 testClassEvents();
100 } catch (Exception e) {
101 throw new RuntimeException(e);
102 }
103 }
104 };
105 classEventsThread.start();
106 classEventsThread.join();
Andreas Gampee492ae32016-10-28 19:34:57 -0700107 }
108
109 private static void testClass(String className) throws Exception {
110 Class<?> base = Class.forName(className);
111 testClass(base);
112 }
113
114 private static void testClass(Class<?> base) throws Exception {
115 String[] result = getClassSignature(base);
116 System.out.println(Arrays.toString(result));
Andreas Gampe64013e52017-01-06 13:07:19 -0800117 int mod = getClassModifiers(base);
118 if (mod != base.getModifiers()) {
119 throw new RuntimeException("Unexpected modifiers: " + base.getModifiers() + " vs " + mod);
120 }
121 System.out.println(Integer.toHexString(mod));
Andreas Gampee492ae32016-10-28 19:34:57 -0700122 }
123
Andreas Gampe4fd66ec2017-01-05 14:42:13 -0800124 private static void testClassType(Class<?> c) throws Exception {
125 boolean isInterface = isInterface(c);
126 boolean isArray = isArrayClass(c);
Alex Lighte4a88632017-01-10 07:41:24 -0800127 boolean isModifiable = isModifiableClass(c);
128 System.out.println(c.getName() + " interface=" + isInterface + " array=" + isArray +
129 " modifiable=" + isModifiable);
Andreas Gampe4fd66ec2017-01-05 14:42:13 -0800130 }
131
Andreas Gampeac587272017-01-05 15:21:34 -0800132 private static void testClassFields(Class<?> c) throws Exception {
133 System.out.println(Arrays.toString(getClassFields(c)));
134 }
135
Andreas Gampe18fee4d2017-01-06 11:36:35 -0800136 private static void testClassMethods(Class<?> c) throws Exception {
137 System.out.println(Arrays.toString(getClassMethods(c)));
138 }
139
Andreas Gampeff9d2092017-01-06 09:12:49 -0800140 private static void testClassStatus(Class<?> c) {
141 System.out.println(c + " " + Integer.toBinaryString(getClassStatus(c)));
142 }
143
Andreas Gampe8b07e472017-01-06 14:20:39 -0800144 private static void testInterfaces(Class<?> c) {
145 System.out.println(c + " " + Arrays.toString(getImplementedInterfaces(c)));
146 }
147
Andreas Gampe8f5b6032017-01-06 15:50:55 -0800148 private static boolean IsBootClassLoader(ClassLoader l) {
149 // Hacky check for Android's fake boot classloader.
150 return l.getClass().getName().equals("java.lang.BootClassLoader");
151 }
152
153 private static void testClassLoader(Class<?> c) {
154 Object cl = getClassLoader(c);
155 System.out.println(c + " " + (cl != null ? cl.getClass().getName() : "null"));
156 if (cl == null) {
157 if (c.getClassLoader() != null && !IsBootClassLoader(c.getClassLoader())) {
158 throw new RuntimeException("Expected " + c.getClassLoader() + ", but got null.");
159 }
160 } else {
161 if (!(cl instanceof ClassLoader)) {
162 throw new RuntimeException("Unexpected \"classloader\": " + cl + " (" + cl.getClass() +
163 ")");
164 }
165 if (cl != c.getClassLoader()) {
166 throw new RuntimeException("Unexpected classloader: " + c.getClassLoader() + " vs " + cl);
167 }
168 }
169 }
170
Andreas Gampe70f16392017-01-16 14:20:10 -0800171 private static void testClassLoaderClasses() throws Exception {
Andreas Gampe70f16392017-01-16 14:20:10 -0800172 System.out.println();
Andreas Gamped5f2ccc2017-04-19 13:37:48 -0700173 System.out.println("boot <- (B) <- (A,C)");
174 ClassLoader cl1 = DexData.create2(DexData.create1());
Andreas Gampe70f16392017-01-16 14:20:10 -0800175 Class.forName("B", false, cl1);
176 Class.forName("A", false, cl1);
177 printClassLoaderClasses(cl1);
178
179 System.out.println();
Andreas Gamped5f2ccc2017-04-19 13:37:48 -0700180 System.out.println("boot <- (B) <- (A, List)");
181 ClassLoader cl2 = DexData.create2(DexData.create1());
Andreas Gampe70f16392017-01-16 14:20:10 -0800182 Class.forName("A", false, cl2);
183 Class.forName("java.util.List", false, cl2);
184 Class.forName("B", false, cl2.getParent());
185 printClassLoaderClasses(cl2);
186
187 System.out.println();
Andreas Gamped5f2ccc2017-04-19 13:37:48 -0700188 System.out.println("boot <- 1+2 (A,B)");
189 ClassLoader cl3 = DexData.create12();
Andreas Gampe70f16392017-01-16 14:20:10 -0800190 Class.forName("B", false, cl3);
191 Class.forName("A", false, cl3);
192 printClassLoaderClasses(cl3);
193
194 // Check that the boot classloader dumps something non-empty.
Andreas Gamped5f2ccc2017-04-19 13:37:48 -0700195 ClassLoader boot = ClassLoader.getSystemClassLoader().getParent();
196 while (boot.getParent() != null) {
197 boot = boot.getParent();
198 }
199
Andreas Gampe70f16392017-01-16 14:20:10 -0800200 Class<?>[] bootClasses = getClassLoaderClasses(boot);
201 if (bootClasses.length == 0) {
202 throw new RuntimeException("No classes initiated by boot classloader.");
203 }
204 // Check that at least java.util.List is loaded.
205 boolean foundList = false;
206 for (Class<?> c : bootClasses) {
207 if (c == java.util.List.class) {
208 foundList = true;
209 break;
210 }
211 }
212 if (!foundList) {
213 System.out.println(Arrays.toString(bootClasses));
214 throw new RuntimeException("Could not find class java.util.List.");
215 }
216 }
217
Andreas Gampe812a2442017-01-19 22:04:46 -0800218 private static void testClassVersion() {
219 System.out.println(Arrays.toString(getClassVersion(Main.class)));
220 }
221
Andreas Gampee6377462017-01-20 17:37:50 -0800222 private static void testClassEvents() throws Exception {
223 ClassLoader cl = Main.class.getClassLoader();
224 while (cl.getParent() != null) {
225 cl = cl.getParent();
226 }
227 final ClassLoader boot = cl;
228
Andreas Gampee2744c62017-02-08 16:28:59 +0000229 // The JIT may deeply inline and load some classes. Preload these for test determinism.
230 final String PRELOAD_FOR_JIT[] = {
231 "java.nio.charset.CoderMalfunctionError",
232 "java.util.NoSuchElementException"
233 };
234 for (String s : PRELOAD_FOR_JIT) {
235 Class.forName(s);
236 }
237
Andreas Gampe19958592017-01-23 17:29:07 -0800238 Runnable r = new Runnable() {
239 @Override
240 public void run() {
241 try {
Andreas Gamped5f2ccc2017-04-19 13:37:48 -0700242 ClassLoader cl6 = DexData.create12();
Andreas Gampe19958592017-01-23 17:29:07 -0800243 System.out.println("C, true");
244 Class.forName("C", true, cl6);
Andreas Gamped5f2ccc2017-04-19 13:37:48 -0700245 printClassLoadMessages();
Andreas Gampe19958592017-01-23 17:29:07 -0800246 } catch (Exception e) {
247 throw new RuntimeException(e);
248 }
249 }
250 };
251
Andreas Gampe41526612017-01-23 22:48:15 -0800252 Thread dummyThread = new Thread();
253 dummyThread.start();
254 dummyThread.join();
255
Andreas Gamped5f2ccc2017-04-19 13:37:48 -0700256 enableClassLoadPreparePrintEvents(true, Thread.currentThread());
Andreas Gampe41526612017-01-23 22:48:15 -0800257
Andreas Gamped5f2ccc2017-04-19 13:37:48 -0700258 ClassLoader cl1 = DexData.create12();
Andreas Gampee6377462017-01-20 17:37:50 -0800259 System.out.println("B, false");
260 Class.forName("B", false, cl1);
Andreas Gamped5f2ccc2017-04-19 13:37:48 -0700261 printClassLoadMessages();
Andreas Gampee6377462017-01-20 17:37:50 -0800262
Andreas Gamped5f2ccc2017-04-19 13:37:48 -0700263 ClassLoader cl2 = DexData.create12();
Andreas Gampee6377462017-01-20 17:37:50 -0800264 System.out.println("B, true");
265 Class.forName("B", true, cl2);
Andreas Gamped5f2ccc2017-04-19 13:37:48 -0700266 printClassLoadMessages();
Andreas Gampee6377462017-01-20 17:37:50 -0800267
Andreas Gamped5f2ccc2017-04-19 13:37:48 -0700268 ClassLoader cl3 = DexData.create12();
Andreas Gampee6377462017-01-20 17:37:50 -0800269 System.out.println("C, false");
270 Class.forName("C", false, cl3);
Andreas Gamped5f2ccc2017-04-19 13:37:48 -0700271 printClassLoadMessages();
Andreas Gampee6377462017-01-20 17:37:50 -0800272 System.out.println("A, false");
273 Class.forName("A", false, cl3);
Andreas Gamped5f2ccc2017-04-19 13:37:48 -0700274 printClassLoadMessages();
Andreas Gampee6377462017-01-20 17:37:50 -0800275
Andreas Gamped5f2ccc2017-04-19 13:37:48 -0700276 ClassLoader cl4 = DexData.create12();
Andreas Gampee6377462017-01-20 17:37:50 -0800277 System.out.println("C, true");
278 Class.forName("C", true, cl4);
Andreas Gamped5f2ccc2017-04-19 13:37:48 -0700279 printClassLoadMessages();
Andreas Gampee6377462017-01-20 17:37:50 -0800280 System.out.println("A, true");
281 Class.forName("A", true, cl4);
Andreas Gamped5f2ccc2017-04-19 13:37:48 -0700282 printClassLoadMessages();
Andreas Gampee6377462017-01-20 17:37:50 -0800283
Andreas Gamped5f2ccc2017-04-19 13:37:48 -0700284 ClassLoader cl5 = DexData.create12();
Andreas Gampee6377462017-01-20 17:37:50 -0800285 System.out.println("A, true");
286 Class.forName("A", true, cl5);
Andreas Gamped5f2ccc2017-04-19 13:37:48 -0700287 printClassLoadMessages();
Andreas Gampee6377462017-01-20 17:37:50 -0800288 System.out.println("C, true");
289 Class.forName("C", true, cl5);
Andreas Gamped5f2ccc2017-04-19 13:37:48 -0700290 printClassLoadMessages();
291
292 enableClassLoadPreparePrintEvents(false, null);
Andreas Gampee6377462017-01-20 17:37:50 -0800293
Andreas Gampee6377462017-01-20 17:37:50 -0800294 Thread t = new Thread(r, "TestRunner");
Andreas Gamped5f2ccc2017-04-19 13:37:48 -0700295 enableClassLoadPreparePrintEvents(true, t);
Andreas Gampee6377462017-01-20 17:37:50 -0800296 t.start();
297 t.join();
Andreas Gamped5f2ccc2017-04-19 13:37:48 -0700298 enableClassLoadPreparePrintEvents(false, null);
299
300 enableClassLoadPreparePrintEvents(true, Thread.currentThread());
Andreas Gampee6377462017-01-20 17:37:50 -0800301
Andreas Gampe6cfd4c92017-04-06 08:03:32 -0700302 // Check creation of arrays and proxies.
Andreas Gamped5f2ccc2017-04-19 13:37:48 -0700303 Proxy.getProxyClass(Main.class.getClassLoader(), new Class[] { Comparable.class, I0.class });
304 Class.forName("[Lart.Test912;");
305 printClassLoadMessages();
Andreas Gampe6cfd4c92017-04-06 08:03:32 -0700306
Andreas Gamped5f2ccc2017-04-19 13:37:48 -0700307 enableClassLoadPreparePrintEvents(false, null);
Andreas Gampe691051b2017-02-09 09:15:24 -0800308
309 testClassLoadPrepareEquality();
Andreas Gampee2744c62017-02-08 16:28:59 +0000310 }
311
Andreas Gampe691051b2017-02-09 09:15:24 -0800312 private static void testClassLoadPrepareEquality() throws Exception {
Andreas Gampea67354b2017-02-10 16:18:30 -0800313 setEqualityEventStorageClass(ClassF.class);
314
Andreas Gampe691051b2017-02-09 09:15:24 -0800315 enableClassLoadPrepareEqualityEvents(true);
316
Andreas Gamped5f2ccc2017-04-19 13:37:48 -0700317 Class.forName("art.Test912$ClassE");
Andreas Gampe691051b2017-02-09 09:15:24 -0800318
319 enableClassLoadPrepareEqualityEvents(false);
320 }
321
Andreas Gampe70f16392017-01-16 14:20:10 -0800322 private static void printClassLoaderClasses(ClassLoader cl) {
323 for (;;) {
324 if (cl == null || !cl.getClass().getName().startsWith("dalvik.system")) {
325 break;
326 }
327
Andreas Gamped5f2ccc2017-04-19 13:37:48 -0700328 Class<?> classes[] = getClassLoaderClasses(cl);
Andreas Gampe70f16392017-01-16 14:20:10 -0800329 Arrays.sort(classes, new ClassNameComparator());
330 System.out.println(Arrays.toString(classes));
331
Andreas Gamped5f2ccc2017-04-19 13:37:48 -0700332 cl = cl.getParent();
333 }
334 }
335
336 private static void printClassLoadMessages() {
337 for (String s : getClassLoadMessages()) {
338 System.out.println(s);
Andreas Gampe70f16392017-01-16 14:20:10 -0800339 }
340 }
341
Alex Lighte4a88632017-01-10 07:41:24 -0800342 private static native boolean isModifiableClass(Class<?> c);
Andreas Gampee492ae32016-10-28 19:34:57 -0700343 private static native String[] getClassSignature(Class<?> c);
Andreas Gampe4fd66ec2017-01-05 14:42:13 -0800344
345 private static native boolean isInterface(Class<?> c);
346 private static native boolean isArrayClass(Class<?> c);
Andreas Gampeac587272017-01-05 15:21:34 -0800347
Andreas Gampe64013e52017-01-06 13:07:19 -0800348 private static native int getClassModifiers(Class<?> c);
349
Andreas Gampeac587272017-01-05 15:21:34 -0800350 private static native Object[] getClassFields(Class<?> c);
Andreas Gampe18fee4d2017-01-06 11:36:35 -0800351 private static native Object[] getClassMethods(Class<?> c);
Andreas Gampe70f16392017-01-16 14:20:10 -0800352 private static native Class<?>[] getImplementedInterfaces(Class<?> c);
Andreas Gampeff9d2092017-01-06 09:12:49 -0800353
354 private static native int getClassStatus(Class<?> c);
355
Andreas Gampe8f5b6032017-01-06 15:50:55 -0800356 private static native Object getClassLoader(Class<?> c);
357
Andreas Gampe70f16392017-01-16 14:20:10 -0800358 private static native Class<?>[] getClassLoaderClasses(ClassLoader cl);
359
Andreas Gampe812a2442017-01-19 22:04:46 -0800360 private static native int[] getClassVersion(Class<?> c);
361
Andreas Gamped5f2ccc2017-04-19 13:37:48 -0700362 private static native void enableClassLoadPreparePrintEvents(boolean b, Thread filter);
363 private static native String[] getClassLoadMessages();
Andreas Gampe41526612017-01-23 22:48:15 -0800364
Andreas Gampea67354b2017-02-10 16:18:30 -0800365 private static native void setEqualityEventStorageClass(Class<?> c);
Andreas Gampe691051b2017-02-09 09:15:24 -0800366 private static native void enableClassLoadPrepareEqualityEvents(boolean b);
367
Andreas Gampeff9d2092017-01-06 09:12:49 -0800368 private static class TestForNonInit {
369 public static double dummy = Math.random(); // So it can't be compile-time initialized.
370 }
371
372 private static class TestForInitFail {
373 public static int dummy = ((int)Math.random())/0; // So it throws when initializing.
374 }
Andreas Gampe8b07e472017-01-06 14:20:39 -0800375
376 public static interface InfA {
377 }
378 public static interface InfB extends InfA {
379 }
380 public static interface InfC extends InfB {
381 }
382
383 public abstract static class ClassA implements InfA {
384 }
385 public abstract static class ClassB extends ClassA implements InfB {
386 }
387 public abstract static class ClassC implements InfA, InfC {
388 }
Andreas Gampe70f16392017-01-16 14:20:10 -0800389
Andreas Gampe691051b2017-02-09 09:15:24 -0800390 public static class ClassE {
391 public void foo() {
392 }
393 public void bar() {
394 }
395 }
396
Andreas Gampea67354b2017-02-10 16:18:30 -0800397 public static class ClassF {
398 public static Object STATIC = null;
Andreas Gampe52784ac2017-02-13 18:10:09 -0800399 public static Reference<Object> WEAK = null;
Andreas Gampea67354b2017-02-10 16:18:30 -0800400 }
401
Andreas Gampe70f16392017-01-16 14:20:10 -0800402 private static class ClassNameComparator implements Comparator<Class<?>> {
403 public int compare(Class<?> c1, Class<?> c2) {
404 return c1.getName().compareTo(c2.getName());
405 }
406 }
Andreas Gamped5f2ccc2017-04-19 13:37:48 -0700407
408 // See run-test 910 for an explanation.
409
410 private static Class<?> proxyClass = null;
411
412 private static Class<?> getProxyClass() throws Exception {
413 if (proxyClass != null) {
414 return proxyClass;
415 }
416
417 for (int i = 1; i <= 21; i++) {
418 proxyClass = createProxyClass(i);
419 String name = proxyClass.getName();
420 if (name.equals("$Proxy20")) {
421 return proxyClass;
422 }
423 }
424 return proxyClass;
425 }
426
427 private static Class<?> createProxyClass(int i) throws Exception {
428 int count = Integer.bitCount(i);
429 Class<?>[] input = new Class<?>[count + 1];
430 input[0] = Runnable.class;
431 int inputIndex = 1;
432 int bitIndex = 0;
433 while (i != 0) {
434 if ((i & 1) != 0) {
435 input[inputIndex++] = Class.forName("art.Test912$I" + bitIndex);
436 }
437 i >>>= 1;
438 bitIndex++;
439 }
440 return Proxy.getProxyClass(Test912.class.getClassLoader(), input);
441 }
442
443 // Need this for the proxy naming.
444 public static interface I0 {
445 }
446 public static interface I1 {
447 }
448 public static interface I2 {
449 }
450 public static interface I3 {
451 }
452 public static interface I4 {
453 }
Andreas Gampee492ae32016-10-28 19:34:57 -0700454}