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