1581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes/*
2581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * Copyright (C) 2010 The Android Open Source Project
3581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes *
4581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * Licensed under the Apache License, Version 2.0 (the "License");
5581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * you may not use this file except in compliance with the License.
6581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * You may obtain a copy of the License at
7581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes *
8581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes *      http://www.apache.org/licenses/LICENSE-2.0
9581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes *
10581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * Unless required by applicable law or agreed to in writing, software
11581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * distributed under the License is distributed on an "AS IS" BASIS,
12581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * See the License for the specific language governing permissions and
14581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * limitations under the License.
15581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes */
16581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes
17581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayesimport java.lang.reflect.Constructor;
18581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayesimport java.lang.reflect.Method;
19581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayesimport java.lang.reflect.InvocationTargetException;
20581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes
21581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes/**
22581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * Class loader test.
23581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes */
24581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayespublic class Main {
25581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes    /**
26581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes     * Thrown when an unexpected Exception is caught internally.
27581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes     */
28581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes    static class TestFailed extends Exception {
29581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes        public TestFailed(Throwable cause) {
30581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes            super(cause);
31581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes        }
32581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes    }
33581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes
34581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes    /**
35581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes     * A class loader which loads classes from the dex file
36581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes     * "test.jar". However, it will return null when asked to load the
37581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes     * class InaccessibleSuper.
38581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes     *
39581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes     * When testing code calls BrokenDexLoader's findBrokenClass(),
40581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes     * a BrokenDexLoader will be the defining loader for the class
41581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes     * Inaccessible.  The VM will call the defining loader for
42581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes     * "InaccessibleSuper", which will return null, which the VM
43581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes     * should be able to deal with gracefully.
44581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes     *
45581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes     * Note that this depends heavily on the Dalvik test harness.
46581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes     */
47581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes    static class BrokenDexLoader extends ClassLoader {
48581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes
49581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes        /** We return null when asked to load InaccessibleSuper. */
50581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes        private static class InaccessibleSuper {}
51581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes        private static class Inaccessible extends InaccessibleSuper {}
52581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes
53581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes        private static final String SUPERCLASS_NAME =
54581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes                "Main$BrokenDexLoader$InaccessibleSuper";
55581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes        private static final String CLASS_NAME =
56581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes                "Main$BrokenDexLoader$Inaccessible";
57581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes
58581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes        private static final String DEX_FILE = "test.jar";
59581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes
60581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes        public BrokenDexLoader(ClassLoader parent) {
61581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes            super(parent);
62581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes        }
63581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes
64581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes        /**
65581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes         * Finds the class with the specified binary name, from DEX_FILE.
66581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes         *
67581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes         * If we don't find a match, we throw an exception.
68581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes         */
69581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes        private Class<?> findDexClass(String name)
70581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes                throws TestFailed, InvocationTargetException
71581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes        {
7232fed2dee7399137908042a37aec28fbbda385caAndy McFadden            Object dexFile = null;
7332fed2dee7399137908042a37aec28fbbda385caAndy McFadden            Class dexClass = null;
74581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes
75581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes            try {
7632fed2dee7399137908042a37aec28fbbda385caAndy McFadden                try {
7732fed2dee7399137908042a37aec28fbbda385caAndy McFadden                    /*
7832fed2dee7399137908042a37aec28fbbda385caAndy McFadden                     * Find the DexFile class, and construct a DexFile object
7932fed2dee7399137908042a37aec28fbbda385caAndy McFadden                     * through reflection, then call loadClass on it.
8032fed2dee7399137908042a37aec28fbbda385caAndy McFadden                     */
8132fed2dee7399137908042a37aec28fbbda385caAndy McFadden                    dexClass = ClassLoader.getSystemClassLoader().
82a5a184892e60a89b564ca7c74e50b2ecb27d9f80Andy McFadden                            loadClass("dalvik.system.DexFile");
8332fed2dee7399137908042a37aec28fbbda385caAndy McFadden                    Constructor ctor = dexClass.
8432fed2dee7399137908042a37aec28fbbda385caAndy McFadden                            getConstructor(new Class[] {String.class});
8532fed2dee7399137908042a37aec28fbbda385caAndy McFadden                    dexFile = ctor.newInstance(DEX_FILE);
8632fed2dee7399137908042a37aec28fbbda385caAndy McFadden                    Method meth = dexClass.getMethod("loadClass",
87581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes                            new Class[] { String.class, ClassLoader.class });
8832fed2dee7399137908042a37aec28fbbda385caAndy McFadden                    /*
8932fed2dee7399137908042a37aec28fbbda385caAndy McFadden                     * Invoking loadClass on CLASS_NAME is expected to
9032fed2dee7399137908042a37aec28fbbda385caAndy McFadden                     * throw an InvocationTargetException. Anything else
9132fed2dee7399137908042a37aec28fbbda385caAndy McFadden                     * is an error we can't recover from.
9232fed2dee7399137908042a37aec28fbbda385caAndy McFadden                     */
9332fed2dee7399137908042a37aec28fbbda385caAndy McFadden                    meth.invoke(dexFile, name, this);
9432fed2dee7399137908042a37aec28fbbda385caAndy McFadden                } finally {
9532fed2dee7399137908042a37aec28fbbda385caAndy McFadden                    if (dexFile != null) {
9632fed2dee7399137908042a37aec28fbbda385caAndy McFadden                        /* close the DexFile to make CloseGuard happy */
9732fed2dee7399137908042a37aec28fbbda385caAndy McFadden                        Method meth = dexClass.getMethod("close", (Class[]) null);
9832fed2dee7399137908042a37aec28fbbda385caAndy McFadden                        meth.invoke(dexFile);
9932fed2dee7399137908042a37aec28fbbda385caAndy McFadden                    }
10032fed2dee7399137908042a37aec28fbbda385caAndy McFadden                }
101581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes            } catch (NoSuchMethodException nsme) {
102581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes                throw new TestFailed(nsme);
103581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes            } catch (InstantiationException ie) {
104581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes                throw new TestFailed(ie);
105581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes            } catch (IllegalAccessException iae) {
106581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes                throw new TestFailed(iae);
107581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes            } catch (ClassNotFoundException cnfe) {
108581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes                throw new TestFailed(cnfe);
109581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes            }
110581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes
111581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes            return null;
112581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes        }
113581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes
114581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes        /**
115581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes         * Load a class.
116581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes         *
117581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes         * Return null if the class's name is SUPERCLASS_NAME;
118581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes         * otherwise invoke the super's loadClass method.
119581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes         */
120581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes        public Class<?> loadClass(String name, boolean resolve)
121581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes                throws ClassNotFoundException
122581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes        {
123581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes            if (SUPERCLASS_NAME.equals(name)) {
124581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes                return null;
125581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes            }
126581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes
127581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes            return super.loadClass(name, resolve);
128581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes        }
129581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes
130581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes        /**
131581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes         * Attempt to find the class with the superclass we refuse to
132581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes         * load.  This is expected to throw an
133581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes         * InvocationTargetException, with a NullPointerException as
134581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes         * its cause.
135581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes         */
136581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes        public void findBrokenClass()
137581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes                throws TestFailed, InvocationTargetException
138581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes        {
139581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes            findDexClass(CLASS_NAME);
140581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes        }
141581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes    }
142581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes
143581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes    /**
144581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes     * Main entry point.
145581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes     */
146581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes    public static void main(String[] args)
147581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes            throws TestFailed, ClassNotFoundException {
148581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes        /*
149581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes         * Run test.
150581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes         */
151581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes        testFailLoadAndGc();
152581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes    }
153581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes
154581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes    /**
155581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes     * See if we can GC after a failed load.
156581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes     */
157581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes    static void testFailLoadAndGc() throws TestFailed {
158581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes        try {
159581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes            BrokenDexLoader loader;
160581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes
161581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes            loader = new BrokenDexLoader(ClassLoader.getSystemClassLoader());
162581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes            loader.findBrokenClass();
163581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes            System.err.println("ERROR: Inaccessible was accessible");
164581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes        } catch (InvocationTargetException ite) {
165581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes            Throwable cause = ite.getCause();
166581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes            if (cause instanceof NullPointerException) {
167581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes                System.err.println("Got expected ITE/NPE");
168581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes            } else {
169581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes                System.err.println("Got unexpected ITE");
170581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes                ite.printStackTrace();
171581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes            }
172581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes        }
173581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes        System.gc();
174581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes        System.out.println("GC complete.");
175581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes    }
176581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes}
177