Main.java revision fbb80d7f726e551161fccbf0e347624459aefedf
1/*
2 * Copyright (C) 2010 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
17import java.lang.reflect.Constructor;
18import java.lang.reflect.Method;
19import java.lang.reflect.InvocationTargetException;
20
21/**
22 * Class loader test.
23 */
24public class Main {
25
26    /**
27     * A class loader which loads classes from the dex file
28     * "test.jar". However, it will return null when asked to load the
29     * class InaccessibleSuper.
30     *
31     * When testing code calls BrokenDexLoader's findBrokenClass(),
32     * a BrokenDexLoader will be the defining loader for the class
33     * Inaccessible.  The VM will call the defining loader for
34     * "InaccessibleSuper", which will return null, which the VM
35     * should be able to deal with gracefully.
36     *
37     * Note that this depends heavily on the Dalvik test harness.
38     */
39    static class BrokenDexLoader extends ClassLoader {
40
41        /** We return null when asked to load InaccessibleSuper. */
42        private static class InaccessibleSuper {}
43        private static class Inaccessible extends InaccessibleSuper {}
44
45        private static final String SUPERCLASS_NAME =
46                "Main$BrokenDexLoader$InaccessibleSuper";
47        private static final String CLASS_NAME =
48                "Main$BrokenDexLoader$Inaccessible";
49
50        private static final String DEX_FILE = "test.jar";
51
52        public BrokenDexLoader(ClassLoader parent) {
53            super(parent);
54        }
55
56        /**
57         * Finds the class with the specified binary name, from DEX_FILE.
58         *
59         * If we don't find a match, we throw an exception.
60         */
61        private Class<?> findDexClass(String name) throws ClassNotFoundException
62        {
63            Class mDexClass;
64            Object mDexFile;
65
66            /*
67             * Find the DexFile class, and construct a DexFile object
68             * through reflection.
69             */
70
71            mDexClass = ClassLoader.getSystemClassLoader().
72                    loadClass("dalvik/system/DexFile");
73
74            Constructor ctor;
75            try {
76                ctor = mDexClass.getConstructor(new Class[] {String.class});
77            } catch (NoSuchMethodException nsme) {
78                throw new ClassNotFoundException("getConstructor failed",
79                                                 nsme);
80            }
81
82            try {
83                mDexFile = ctor.newInstance(DEX_FILE);
84            } catch (InstantiationException ie) {
85                throw new ClassNotFoundException("newInstance failed", ie);
86            } catch (IllegalAccessException iae) {
87                throw new ClassNotFoundException("newInstance failed", iae);
88            } catch (InvocationTargetException ite) {
89                throw new ClassNotFoundException("newInstance failed", ite);
90            }
91
92            /*
93             * Call DexFile.loadClass(String, ClassLoader).
94             */
95            Method meth;
96
97            try {
98                meth = mDexClass.getMethod("loadClass",
99                           new Class[] { String.class, ClassLoader.class });
100            } catch (NoSuchMethodException nsme) {
101                throw new ClassNotFoundException("getMethod failed", nsme);
102            }
103
104            try {
105                meth.invoke(mDexFile, name, this);
106            } catch (IllegalAccessException iae) {
107                throw new ClassNotFoundException("loadClass failed", iae);
108            } catch (InvocationTargetException ite) {
109                throw new ClassNotFoundException("loadClass failed",
110                                                 ite.getCause());
111            }
112
113            return null;
114        }
115
116        /**
117         * Load a class.
118         *
119         * Return null if the class's name is SUPERCLASS_NAME;
120         * otherwise invoke the super's loadClass method.
121         */
122        public Class<?> loadClass(String name, boolean resolve)
123                throws ClassNotFoundException
124        {
125            if (SUPERCLASS_NAME.equals(name)) {
126                return null;
127            }
128
129            return super.loadClass(name, resolve);
130        }
131
132        /**
133         * Attempt to find the class with the superclass we refuse to
134         * load.
135         */
136        public void findBrokenClass() throws ClassNotFoundException
137        {
138            findDexClass(CLASS_NAME);
139        }
140    }
141
142    /**
143     * Main entry point.
144     */
145    public static void main(String[] args) throws ClassNotFoundException {
146        /*
147         * Run tests.
148         */
149        testAccess();
150    }
151
152    /**
153     * See if we can load a class when the loader returns null for the
154     * superclass.
155     */
156    static void testAccess() {
157        try {
158            BrokenDexLoader loader;
159
160            loader = new BrokenDexLoader(ClassLoader.getSystemClassLoader());
161            loader.findBrokenClass();
162            System.err.println("ERROR: Inaccessible was accessible");
163        } catch (ClassNotFoundException cnfe) {
164            Throwable cause = cnfe.getCause();
165            if (cause instanceof NullPointerException) {
166                System.out.println("Got expected CNFE/NPE");
167            } else {
168                System.err.println("Got unexpected CNFE");
169                cnfe.printStackTrace();
170            }
171        }
172    }
173}
174