15d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao/*
25d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao * Copyright (C) 2010 The Android Open Source Project
35d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao *
45d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao * Licensed under the Apache License, Version 2.0 (the "License");
55d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao * you may not use this file except in compliance with the License.
65d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao * You may obtain a copy of the License at
75d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao *
85d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao *      http://www.apache.org/licenses/LICENSE-2.0
95d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao *
105d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao * Unless required by applicable law or agreed to in writing, software
115d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao * distributed under the License is distributed on an "AS IS" BASIS,
125d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao * See the License for the specific language governing permissions and
145d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao * limitations under the License.
155d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao */
165d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao
175d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhaoimport java.lang.reflect.Constructor;
185d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhaoimport java.lang.reflect.Method;
195d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhaoimport java.lang.reflect.InvocationTargetException;
205d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao
215d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao/**
225d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao * Class loader test.
235d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao */
245d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhaopublic class Main {
255d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao    /**
265d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao     * Thrown when an unexpected Exception is caught internally.
275d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao     */
285d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao    static class TestFailed extends Exception {
295d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao        public TestFailed(Throwable cause) {
305d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao            super(cause);
315d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao        }
325d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao    }
335d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao
345d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao    /**
355d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao     * A class loader which loads classes from the dex file
365d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao     * "test.jar". However, it will return null when asked to load the
375d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao     * class InaccessibleSuper.
385d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao     *
395d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao     * When testing code calls BrokenDexLoader's findBrokenClass(),
405d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao     * a BrokenDexLoader will be the defining loader for the class
415d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao     * Inaccessible.  The VM will call the defining loader for
425d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao     * "InaccessibleSuper", which will return null, which the VM
435d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao     * should be able to deal with gracefully.
445d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao     *
455d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao     * Note that this depends heavily on the Dalvik test harness.
465d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao     */
475d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao    static class BrokenDexLoader extends ClassLoader {
485d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao
495d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao        /** We return null when asked to load InaccessibleSuper. */
505d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao        private static class InaccessibleSuper {}
515d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao        private static class Inaccessible extends InaccessibleSuper {}
525d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao
535d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao        private static final String SUPERCLASS_NAME =
545d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                "Main$BrokenDexLoader$InaccessibleSuper";
555d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao        private static final String CLASS_NAME =
565d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                "Main$BrokenDexLoader$Inaccessible";
575d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao
586ce558b97f80d4ef7be2ef43333101d1aac7dcbfTDYa        private static final String DEX_FILE = System.getenv("DEX_LOCATION") + "/087-gc-after-link.jar";
595d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao
605d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao        public BrokenDexLoader(ClassLoader parent) {
615d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao            super(parent);
625d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao        }
635d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao
645d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao        /**
655d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao         * Finds the class with the specified binary name, from DEX_FILE.
665d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao         *
675d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao         * If we don't find a match, we throw an exception.
685d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao         */
695d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao        private Class<?> findDexClass(String name)
705d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                throws TestFailed, InvocationTargetException
715d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao        {
725d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao            Object dexFile = null;
735d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao            Class dexClass = null;
745d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao
755d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao            try {
765d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                try {
775d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                    /*
785d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                     * Find the DexFile class, and construct a DexFile object
795d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                     * through reflection, then call loadClass on it.
805d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                     */
815d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                    dexClass = ClassLoader.getSystemClassLoader().
82741b5b7ef4c7fd4a786364bbf60d515489caff47Elliott Hughes                            loadClass("dalvik.system.DexFile");
835d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                    Constructor ctor = dexClass.
845d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                            getConstructor(new Class[] {String.class});
855d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                    dexFile = ctor.newInstance(DEX_FILE);
865d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                    Method meth = dexClass.getMethod("loadClass",
875d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                            new Class[] { String.class, ClassLoader.class });
885d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                    /*
895d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                     * Invoking loadClass on CLASS_NAME is expected to
905d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                     * throw an InvocationTargetException. Anything else
915d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                     * is an error we can't recover from.
925d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                     */
935d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                    meth.invoke(dexFile, name, this);
9400310e0bb4ee541b99f0b687dbf5f706db2aabcaMathieu Chartier                    System.out.println("Unreachable");
955d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                } finally {
965d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                    if (dexFile != null) {
975d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                        /* close the DexFile to make CloseGuard happy */
985d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                        Method meth = dexClass.getMethod("close", (Class[]) null);
995d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                        meth.invoke(dexFile);
1005d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                    }
1015d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                }
1025d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao            } catch (NoSuchMethodException nsme) {
1035d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                throw new TestFailed(nsme);
1045d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao            } catch (InstantiationException ie) {
1055d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                throw new TestFailed(ie);
1065d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao            } catch (IllegalAccessException iae) {
1075d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                throw new TestFailed(iae);
1085d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao            } catch (ClassNotFoundException cnfe) {
1095d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                throw new TestFailed(cnfe);
1105d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao            }
1115d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao
1125d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao            return null;
1135d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao        }
1145d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao
1155d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao        /**
1165d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao         * Load a class.
1175d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao         *
1185d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao         * Return null if the class's name is SUPERCLASS_NAME;
1195d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao         * otherwise invoke the super's loadClass method.
1205d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao         */
1215d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao        public Class<?> loadClass(String name, boolean resolve)
1225d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                throws ClassNotFoundException
1235d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao        {
1245d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao            if (SUPERCLASS_NAME.equals(name)) {
1255d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                return null;
1265d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao            }
1275d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao
1285d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao            return super.loadClass(name, resolve);
1295d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao        }
1305d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao
1315d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao        /**
1325d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao         * Attempt to find the class with the superclass we refuse to
1335d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao         * load.  This is expected to throw an
1345d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao         * InvocationTargetException, with a NullPointerException as
1355d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao         * its cause.
1365d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao         */
1375d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao        public void findBrokenClass()
1385d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                throws TestFailed, InvocationTargetException
1395d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao        {
1405d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao            findDexClass(CLASS_NAME);
1415d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao        }
1425d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao    }
1435d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao
1445d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao    /**
1455d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao     * Main entry point.
1465d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao     */
1475d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao    public static void main(String[] args)
1485d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao            throws TestFailed, ClassNotFoundException {
1495d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao        /*
1505d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao         * Run test.
1515d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao         */
1525d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao        testFailLoadAndGc();
1535d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao    }
1545d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao
1555d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao    /**
1565d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao     * See if we can GC after a failed load.
1575d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao     */
1585d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao    static void testFailLoadAndGc() throws TestFailed {
159831b1cc088ee21dfd0495fcce139d482b7380f6fMathieu Chartier        processFailLoadAndGc();
160831b1cc088ee21dfd0495fcce139d482b7380f6fMathieu Chartier        Runtime.getRuntime().gc();
161831b1cc088ee21dfd0495fcce139d482b7380f6fMathieu Chartier        System.out.println("GC complete.");
162831b1cc088ee21dfd0495fcce139d482b7380f6fMathieu Chartier    }
163831b1cc088ee21dfd0495fcce139d482b7380f6fMathieu Chartier
164831b1cc088ee21dfd0495fcce139d482b7380f6fMathieu Chartier    private static void processFailLoadAndGc() throws TestFailed {
1655d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao        try {
1665d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao            BrokenDexLoader loader;
1675d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao
1685d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao            loader = new BrokenDexLoader(ClassLoader.getSystemClassLoader());
1695d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao            loader.findBrokenClass();
1705d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao            System.err.println("ERROR: Inaccessible was accessible");
1715d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao        } catch (InvocationTargetException ite) {
1725d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao            Throwable cause = ite.getCause();
1735d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao            if (cause instanceof NullPointerException) {
1745d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                System.err.println("Got expected ITE/NPE");
1755d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao            } else {
1765d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                System.err.println("Got unexpected ITE");
1775d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao                ite.printStackTrace();
1785d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao            }
1795d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao        }
1805d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao    }
1815d1ac920fdaef5d4ec8f66bb734488cd9660b024jeffhao}
182