1fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes/*
2fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes * Copyright (C) 2010 The Android Open Source Project
3fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes *
4fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes * Licensed under the Apache License, Version 2.0 (the "License");
5fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes * you may not use this file except in compliance with the License.
6fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes * You may obtain a copy of the License at
7fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes *
8fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes *      http://www.apache.org/licenses/LICENSE-2.0
9fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes *
10fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes * Unless required by applicable law or agreed to in writing, software
11fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes * distributed under the License is distributed on an "AS IS" BASIS,
12fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes * See the License for the specific language governing permissions and
14fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes * limitations under the License.
15fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes */
16fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes
17fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayesimport java.lang.reflect.Constructor;
18fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayesimport java.lang.reflect.Method;
19fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayesimport java.lang.reflect.InvocationTargetException;
20fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes
21fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes/**
22fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes * Class loader test.
23fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes */
24fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayespublic class Main {
2582b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes    /**
2682b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes     * Thrown when an unexpected Exception is caught internally.
2782b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes     */
2882b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes    static class TestFailed extends Exception {
2982b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes        public TestFailed(Throwable cause) {
3082b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes            super(cause);
3182b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes        }
3282b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes    }
33fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes
34fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes    /**
35fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes     * A class loader which loads classes from the dex file
36fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes     * "test.jar". However, it will return null when asked to load the
37fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes     * class InaccessibleSuper.
38fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes     *
39fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes     * When testing code calls BrokenDexLoader's findBrokenClass(),
40fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes     * a BrokenDexLoader will be the defining loader for the class
41fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes     * Inaccessible.  The VM will call the defining loader for
42fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes     * "InaccessibleSuper", which will return null, which the VM
43fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes     * should be able to deal with gracefully.
44fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes     *
45fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes     * Note that this depends heavily on the Dalvik test harness.
46fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes     */
47fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes    static class BrokenDexLoader extends ClassLoader {
48fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes
49fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes        /** We return null when asked to load InaccessibleSuper. */
50fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes        private static class InaccessibleSuper {}
51fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes        private static class Inaccessible extends InaccessibleSuper {}
52fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes
53fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes        private static final String SUPERCLASS_NAME =
54fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes                "Main$BrokenDexLoader$InaccessibleSuper";
55fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes        private static final String CLASS_NAME =
56fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes                "Main$BrokenDexLoader$Inaccessible";
57fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes
58fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes        private static final String DEX_FILE = "test.jar";
59fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes
60fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes        public BrokenDexLoader(ClassLoader parent) {
61fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes            super(parent);
62fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes        }
63fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes
64fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes        /**
65fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes         * Finds the class with the specified binary name, from DEX_FILE.
66fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes         *
67fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes         * If we don't find a match, we throw an exception.
68fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes         */
6982b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes        private Class<?> findDexClass(String name)
7082b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes                throws TestFailed, InvocationTargetException
71fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes        {
72fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes
73fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes            try {
7482b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes                /*
7582b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes                 * Find the DexFile class, and construct a DexFile object
7682b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes                 * through reflection, then call loadCLass on it.
7782b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes                 */
7882b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes                Class mDexClass = ClassLoader.getSystemClassLoader().
79a5a184892e60a89b564ca7c74e50b2ecb27d9f80Andy McFadden                        loadClass("dalvik.system.DexFile");
8082b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes                Constructor ctor = mDexClass.
8182b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes                        getConstructor(new Class[] {String.class});
8282b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes                Object mDexFile = ctor.newInstance(DEX_FILE);
8382b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes                Method meth = mDexClass.
8482b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes                        getMethod("loadClass",
8582b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes                            new Class[] { String.class, ClassLoader.class });
8682b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes                /*
8782b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes                 * Invoking loadClass on CLASS_NAME is expected to
8882b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes                 * throw an InvocationTargetException. Anything else
8982b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes                 * is an error we can't recover from.
9082b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes                 */
9182b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes                meth.invoke(mDexFile, name, this);
92fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes            } catch (NoSuchMethodException nsme) {
9382b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes                throw new TestFailed(nsme);
94fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes            } catch (InstantiationException ie) {
9582b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes                throw new TestFailed(ie);
96fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes            } catch (IllegalAccessException iae) {
9782b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes                throw new TestFailed(iae);
9882b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes            } catch (ClassNotFoundException cnfe) {
9982b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes                throw new TestFailed(cnfe);
100fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes            }
101fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes
102fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes            return null;
103fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes        }
104fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes
105fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes        /**
106fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes         * Load a class.
107fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes         *
108fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes         * Return null if the class's name is SUPERCLASS_NAME;
109fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes         * otherwise invoke the super's loadClass method.
110fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes         */
111fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes        public Class<?> loadClass(String name, boolean resolve)
112fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes                throws ClassNotFoundException
113fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes        {
114fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes            if (SUPERCLASS_NAME.equals(name)) {
115fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes                return null;
116fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes            }
117fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes
118fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes            return super.loadClass(name, resolve);
119fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes        }
120fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes
121fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes        /**
122fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes         * Attempt to find the class with the superclass we refuse to
12382b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes         * load.  This is expected to throw an
12482b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes         * InvocationTargetException, with a NullPointerException as
12582b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes         * its cause.
126fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes         */
12782b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes        public void findBrokenClass()
12882b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes                throws TestFailed, InvocationTargetException
129fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes        {
130fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes            findDexClass(CLASS_NAME);
131fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes        }
132fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes    }
133fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes
134fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes    /**
135fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes     * Main entry point.
136fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes     */
13782b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes    public static void main(String[] args)
13882b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes            throws TestFailed, ClassNotFoundException {
139fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes        /*
14082b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes         * Run test.
141fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes         */
14282b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes        testFailLoadAndGc();
143fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes    }
144fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes
145fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes    /**
14682b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes     * See if we can GC after a failed load.
147fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes     */
14882b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes    static void testFailLoadAndGc() throws TestFailed {
149fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes        try {
150fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes            BrokenDexLoader loader;
151fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes
152fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes            loader = new BrokenDexLoader(ClassLoader.getSystemClassLoader());
153fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes            loader.findBrokenClass();
154fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes            System.err.println("ERROR: Inaccessible was accessible");
15582b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes        } catch (InvocationTargetException ite) {
15682b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes            Throwable cause = ite.getCause();
157fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes            if (cause instanceof NullPointerException) {
15882b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes                System.err.println("Got expected ITE/NPE");
159fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes            } else {
16082b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes                System.err.println("Got unexpected ITE");
16182b596d087f29cd6b22f36dae28f1d25125e82c8Barry Hayes                ite.printStackTrace();
162fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes            }
163fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes        }
164fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes    }
165fbb80d7f726e551161fccbf0e347624459aefedfBarry Hayes}
166