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