blob: 361e2938e3be7b4bab19999fefb5b166224f2ccd [file] [log] [blame]
jeffhao5d1ac922011-09-29 17:41:15 -07001/*
2 * Copyright (C) 2008 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/**
18 * Class loader test.
19 */
20public class Main {
21 /**
22 * Main entry point.
23 */
Brian Carlstrom59885472015-04-20 21:55:19 -070024 public static void main(String[] args) throws Exception {
jeffhao5d1ac922011-09-29 17:41:15 -070025 FancyLoader loader;
26
27 loader = new FancyLoader(ClassLoader.getSystemClassLoader());
28 //System.out.println("SYSTEM: " + ClassLoader.getSystemClassLoader());
29 //System.out.println("ALTERN: " + loader);
30
31 /*
32 * This statement has no effect on this program, but it can
33 * change the point where a LinkageException is thrown in
34 * testImplement(). When this is present the "reference
35 * implementation" throws an exception from Class.newInstance(),
36 * when it's absent the exception is deferred until the first time
37 * we call a method that isn't actually implemented.
38 *
39 * This isn't the class that fails -- it's a class with the same
40 * name in the "fancy" class loader -- but the VM thinks it has a
41 * reference to one of these; presumably the difference is that
42 * without this the VM finds itself holding a reference to an
43 * instance of an uninitialized class.
44 */
45 System.out.println("base: " + DoubledImplement.class);
46 System.out.println("base2: " + DoubledImplement2.class);
47
48 /*
49 * Run tests.
50 */
51 testAccess1(loader);
52 testAccess2(loader);
53 testAccess3(loader);
54
55 testExtend(loader);
56 testExtendOkay(loader);
57 testInterface(loader);
58 testAbstract(loader);
59 testImplement(loader);
60 testIfaceImplement(loader);
Andreas Gampe26684c02015-04-15 23:23:51 -070061
62 testSeparation();
Brian Carlstrom59885472015-04-20 21:55:19 -070063
64 testClassForName();
Andreas Gampe26684c02015-04-15 23:23:51 -070065 }
66
67 static void testSeparation() {
68 FancyLoader loader1 = new FancyLoader(ClassLoader.getSystemClassLoader());
69 FancyLoader loader2 = new FancyLoader(ClassLoader.getSystemClassLoader());
70
71 try {
72 Class target1 = loader1.loadClass("MutationTarget");
73 Class target2 = loader2.loadClass("MutationTarget");
74
75 if (target1 == target2) {
76 throw new RuntimeException("target1 should not be equal to target2");
77 }
78
79 Class mutator1 = loader1.loadClass("Mutator");
80 Class mutator2 = loader2.loadClass("Mutator");
81
82 if (mutator1 == mutator2) {
83 throw new RuntimeException("mutator1 should not be equal to mutator2");
84 }
85
86 runMutator(mutator1, 1);
87
88 int value = getMutationTargetValue(target1);
89 if (value != 1) {
90 throw new RuntimeException("target 1 has unexpected value " + value);
91 }
92 value = getMutationTargetValue(target2);
93 if (value != 0) {
94 throw new RuntimeException("target 2 has unexpected value " + value);
95 }
96
97 runMutator(mutator2, 2);
98
99 value = getMutationTargetValue(target1);
100 if (value != 1) {
101 throw new RuntimeException("target 1 has unexpected value " + value);
102 }
103 value = getMutationTargetValue(target2);
104 if (value != 2) {
105 throw new RuntimeException("target 2 has unexpected value " + value);
106 }
107 } catch (Exception ex) {
108 ex.printStackTrace();
109 }
110 }
111
112 private static void runMutator(Class c, int v) throws Exception {
113 java.lang.reflect.Method m = c.getDeclaredMethod("mutate", int.class);
114 m.invoke(null, v);
115 }
116
117 private static int getMutationTargetValue(Class c) throws Exception {
118 java.lang.reflect.Field f = c.getDeclaredField("value");
119 return f.getInt(null);
jeffhao5d1ac922011-09-29 17:41:15 -0700120 }
121
122 /**
123 * See if we can load a class that isn't public to us. We should be
124 * able to load it but not instantiate it.
125 */
126 static void testAccess1(ClassLoader loader) {
127 Class altClass;
128
129 try {
130 altClass = loader.loadClass("Inaccessible1");
131 } catch (ClassNotFoundException cnfe) {
132 System.err.println("loadClass failed");
133 cnfe.printStackTrace();
134 return;
135 }
136
137 /* instantiate */
138 Object obj;
139 try {
140 obj = altClass.newInstance();
141 System.err.println("ERROR: Inaccessible1 was accessible");
142 } catch (InstantiationException ie) {
143 System.err.println("newInstance failed: " + ie);
144 return;
145 } catch (IllegalAccessException iae) {
146 System.out.println("Got expected access exception #1");
147 //System.out.println("+++ " + iae);
148 return;
149 }
150 }
151
152 /**
153 * See if we can load a class whose base class is not accessible to it
154 * (though the base *is* accessible to us).
155 */
156 static void testAccess2(ClassLoader loader) {
157 Class altClass;
158
159 try {
160 altClass = loader.loadClass("Inaccessible2");
Brian Carlstrom4d9716c2012-01-30 01:49:33 -0800161 System.err.println("ERROR: Inaccessible2 was accessible: " + altClass);
jeffhao5d1ac922011-09-29 17:41:15 -0700162 } catch (ClassNotFoundException cnfe) {
163 Throwable cause = cnfe.getCause();
164 if (cause instanceof IllegalAccessError) {
165 System.out.println("Got expected CNFE/IAE #2");
166 } else {
167 System.err.println("Got unexpected CNFE/IAE #2");
168 cnfe.printStackTrace();
169 }
170 }
171 }
172
173 /**
174 * See if we can load a class with an inaccessible interface.
175 */
176 static void testAccess3(ClassLoader loader) {
177 Class altClass;
178
179 try {
180 altClass = loader.loadClass("Inaccessible3");
Brian Carlstrom4d9716c2012-01-30 01:49:33 -0800181 System.err.println("ERROR: Inaccessible3 was accessible: " + altClass);
jeffhao5d1ac922011-09-29 17:41:15 -0700182 } catch (ClassNotFoundException cnfe) {
183 Throwable cause = cnfe.getCause();
184 if (cause instanceof IllegalAccessError) {
185 System.out.println("Got expected CNFE/IAE #3");
186 } else {
187 System.err.println("Got unexpected CNFE/IAE #3");
188 cnfe.printStackTrace();
189 }
190 }
191 }
192
193 /**
194 * Test a doubled class that extends the base class.
195 */
196 static void testExtend(ClassLoader loader) {
197 Class doubledExtendClass;
198 Object obj;
199
200 /* get the "alternate" version of DoubledExtend */
201 try {
202 doubledExtendClass = loader.loadClass("DoubledExtend");
203 //System.out.println("+++ DoubledExtend is " + doubledExtendClass
204 // + " in " + doubledExtendClass.getClassLoader());
205 } catch (ClassNotFoundException cnfe) {
206 System.err.println("loadClass failed: " + cnfe);
207 return;
208 }
209
210 /* instantiate */
211 try {
212 obj = doubledExtendClass.newInstance();
213 } catch (InstantiationException ie) {
214 System.err.println("newInstance failed: " + ie);
215 return;
216 } catch (IllegalAccessException iae) {
217 System.err.println("newInstance failed: " + iae);
218 return;
219 } catch (LinkageError le) {
220 System.out.println("Got expected LinkageError on DE");
221 return;
222 }
223
224 /* use the base class reference to get a CL-specific instance */
225 Base baseRef = (Base) obj;
226 DoubledExtend de = baseRef.getExtended();
227
228 /* try to call through it */
229 try {
230 String result;
231
232 result = Base.doStuff(de);
233 System.err.println("ERROR: did not get LinkageError on DE");
234 System.err.println("(result=" + result + ")");
235 } catch (LinkageError le) {
236 System.out.println("Got expected LinkageError on DE");
237 return;
238 }
239 }
240
241 /**
242 * Test a doubled class that extends the base class, but is okay since
243 * it doesn't override the base class method.
244 */
245 static void testExtendOkay(ClassLoader loader) {
246 Class doubledExtendOkayClass;
247 Object obj;
248
249 /* get the "alternate" version of DoubledExtendOkay */
250 try {
251 doubledExtendOkayClass = loader.loadClass("DoubledExtendOkay");
252 } catch (ClassNotFoundException cnfe) {
253 System.err.println("loadClass failed: " + cnfe);
254 return;
255 }
256
257 /* instantiate */
258 try {
259 obj = doubledExtendOkayClass.newInstance();
260 } catch (InstantiationException ie) {
261 System.err.println("newInstance failed: " + ie);
262 return;
263 } catch (IllegalAccessException iae) {
264 System.err.println("newInstance failed: " + iae);
265 return;
266 } catch (LinkageError le) {
267 System.err.println("Got unexpected LinkageError on DEO");
268 le.printStackTrace();
269 return;
270 }
271
272 /* use the base class reference to get a CL-specific instance */
273 BaseOkay baseRef = (BaseOkay) obj;
274 DoubledExtendOkay de = baseRef.getExtended();
275
276 /* try to call through it */
277 try {
278 String result;
279
280 result = BaseOkay.doStuff(de);
281 System.out.println("Got DEO result " + result);
282 } catch (LinkageError le) {
283 System.err.println("Got unexpected LinkageError on DEO");
284 le.printStackTrace();
285 return;
286 }
287 }
288
289 /**
290 * Try to access a doubled class through a class that implements
291 * an interface declared in a different class.
292 */
293 static void testInterface(ClassLoader loader) {
294 Class getDoubledClass;
295 Object obj;
296
297 /* get GetDoubled from the "alternate" class loader */
298 try {
299 getDoubledClass = loader.loadClass("GetDoubled");
300 } catch (ClassNotFoundException cnfe) {
301 System.err.println("loadClass failed: " + cnfe);
302 return;
303 }
304
305 /* instantiate */
306 try {
307 obj = getDoubledClass.newInstance();
308 } catch (InstantiationException ie) {
309 System.err.println("newInstance failed: " + ie);
310 return;
311 } catch (IllegalAccessException iae) {
312 System.err.println("newInstance failed: " + iae);
313 return;
314 } catch (LinkageError le) {
315 // Dalvik bails here
316 System.out.println("Got LinkageError on GD");
317 return;
318 }
319
320 /*
321 * Cast the object to the interface, and try to use it.
322 */
323 IGetDoubled iface = (IGetDoubled) obj;
324 try {
325 /* "de" will be the wrong variety of DoubledExtendOkay */
326 DoubledExtendOkay de = iface.getDoubled();
327 // reference impl bails here
328 String str = de.getStr();
329 } catch (LinkageError le) {
330 System.out.println("Got LinkageError on GD");
331 return;
332 }
333 System.err.println("Should have failed by now on GetDoubled");
334 }
335
336 /**
337 * Throw an abstract class into the middle and see what happens.
338 */
339 static void testAbstract(ClassLoader loader) {
340 Class abstractGetClass;
341 Object obj;
342
343 /* get AbstractGet from the "alternate" loader */
344 try {
345 abstractGetClass = loader.loadClass("AbstractGet");
346 } catch (ClassNotFoundException cnfe) {
347 System.err.println("loadClass ta failed: " + cnfe);
348 return;
349 }
350
351 /* instantiate */
352 try {
353 obj = abstractGetClass.newInstance();
354 } catch (InstantiationException ie) {
355 System.err.println("newInstance failed: " + ie);
356 return;
357 } catch (IllegalAccessException iae) {
358 System.err.println("newInstance failed: " + iae);
359 return;
360 } catch (LinkageError le) {
361 System.out.println("Got LinkageError on TA");
362 return;
363 }
364
365 /* use the base class reference to get a CL-specific instance */
366 BaseOkay baseRef = (BaseOkay) obj;
367 DoubledExtendOkay de = baseRef.getExtended();
368
369 /* try to call through it */
370 try {
371 String result;
372
373 result = BaseOkay.doStuff(de);
374 } catch (LinkageError le) {
375 System.out.println("Got LinkageError on TA");
376 return;
377 }
378 System.err.println("Should have failed by now in testAbstract");
379 }
380
381 /**
382 * Test a doubled class that implements a common interface.
383 */
384 static void testImplement(ClassLoader loader) {
385 Class doubledImplementClass;
386 Object obj;
387
388 useImplement(new DoubledImplement(), true);
389
390 /* get the "alternate" version of DoubledImplement */
391 try {
392 doubledImplementClass = loader.loadClass("DoubledImplement");
393 } catch (ClassNotFoundException cnfe) {
394 System.err.println("loadClass failed: " + cnfe);
395 return;
396 }
397
398 /* instantiate */
399 try {
400 obj = doubledImplementClass.newInstance();
401 } catch (InstantiationException ie) {
402 System.err.println("newInstance failed: " + ie);
403 return;
404 } catch (IllegalAccessException iae) {
405 System.err.println("newInstance failed: " + iae);
406 return;
407 } catch (LinkageError le) {
408 System.out.println("Got LinkageError on DI (early)");
409 return;
410 }
411
412 /* if we lived this long, try to do something with it */
413 ICommon icommon = (ICommon) obj;
414 useImplement(icommon.getDoubledInstance(), false);
415 }
416
417 /**
418 * Do something with a DoubledImplement instance.
419 */
420 static void useImplement(DoubledImplement di, boolean isOne) {
421 //System.out.println("useObject: " + di.toString() + " -- "
422 // + di.getClass().getClassLoader());
423 try {
424 di.one();
425 if (!isOne) {
426 System.err.println("ERROR: did not get LinkageError on DI");
427 }
428 } catch (LinkageError le) {
429 if (!isOne) {
430 System.out.println("Got LinkageError on DI (late)");
431 } else {
432 throw le;
433 }
434 }
435 }
436
437
438 /**
439 * Test a class that implements an interface with a super-interface
440 * that refers to a doubled class.
441 */
442 static void testIfaceImplement(ClassLoader loader) {
443 Class ifaceImplClass;
444 Object obj;
445
446 /*
447 * Create an instance of IfaceImpl. We also pull in
448 * DoubledImplement2 from the other class loader; without this
449 * we don't fail in some implementations.
450 */
451 try {
452 ifaceImplClass = loader.loadClass("IfaceImpl");
453 ifaceImplClass = loader.loadClass("DoubledImplement2");
454 } catch (ClassNotFoundException cnfe) {
455 System.err.println("loadClass failed: " + cnfe);
456 return;
457 }
458
459 /* instantiate */
460 try {
461 obj = ifaceImplClass.newInstance();
462 } catch (InstantiationException ie) {
463 System.err.println("newInstance failed: " + ie);
464 return;
465 } catch (IllegalAccessException iae) {
466 System.err.println("newInstance failed: " + iae);
467 return;
468 } catch (LinkageError le) {
469 System.out.println("Got LinkageError on IDI (early)");
470 //System.out.println(le);
471 return;
472 }
473
474 /*
475 * Without the pre-load of FancyLoader->DoubledImplement2, some
476 * implementations will happily execute through this part. "obj"
477 * comes from FancyLoader, but the di2 returned from ifaceSuper
478 * comes from the application class loader.
479 */
480 IfaceSuper ifaceSuper = (IfaceSuper) obj;
481 DoubledImplement2 di2 = ifaceSuper.getDoubledInstance2();
482 di2.one();
483 }
Brian Carlstrom59885472015-04-20 21:55:19 -0700484
485 static void testClassForName() throws Exception {
486 System.out.println(Class.forName("Main").toString());
487 try {
488 System.out.println(Class.forName("Main", false, null).toString());
489 } catch (ClassNotFoundException expected) {
490 System.out.println("Got expected ClassNotFoundException");
491 }
492 }
jeffhao5d1ac922011-09-29 17:41:15 -0700493}