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