blob: e0a187a3a0406b4688481f4f61c0341abff27869 [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
TDYa1276ce558b2012-04-11 11:17:55 -070058 private static final String DEX_FILE = System.getenv("DEX_LOCATION") + "/087-gc-after-link.jar";
jeffhao5d1ac922011-09-29 17:41:15 -070059
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 Object dexFile = null;
73 Class dexClass = null;
74
75 try {
76 try {
77 /*
78 * Find the DexFile class, and construct a DexFile object
79 * through reflection, then call loadClass on it.
80 */
81 dexClass = ClassLoader.getSystemClassLoader().
Elliott Hughes741b5b72012-01-31 19:18:51 -080082 loadClass("dalvik.system.DexFile");
jeffhao5d1ac922011-09-29 17:41:15 -070083 Constructor ctor = dexClass.
84 getConstructor(new Class[] {String.class});
85 dexFile = ctor.newInstance(DEX_FILE);
86 Method meth = dexClass.getMethod("loadClass",
87 new Class[] { String.class, ClassLoader.class });
88 /*
89 * Invoking loadClass on CLASS_NAME is expected to
90 * throw an InvocationTargetException. Anything else
91 * is an error we can't recover from.
92 */
93 meth.invoke(dexFile, name, this);
94 } finally {
95 if (dexFile != null) {
96 /* close the DexFile to make CloseGuard happy */
97 Method meth = dexClass.getMethod("close", (Class[]) null);
98 meth.invoke(dexFile);
99 }
100 }
101 } catch (NoSuchMethodException nsme) {
102 throw new TestFailed(nsme);
103 } catch (InstantiationException ie) {
104 throw new TestFailed(ie);
105 } catch (IllegalAccessException iae) {
106 throw new TestFailed(iae);
107 } catch (ClassNotFoundException cnfe) {
108 throw new TestFailed(cnfe);
109 }
110
111 return null;
112 }
113
114 /**
115 * Load a class.
116 *
117 * Return null if the class's name is SUPERCLASS_NAME;
118 * otherwise invoke the super's loadClass method.
119 */
120 public Class<?> loadClass(String name, boolean resolve)
121 throws ClassNotFoundException
122 {
123 if (SUPERCLASS_NAME.equals(name)) {
124 return null;
125 }
126
127 return super.loadClass(name, resolve);
128 }
129
130 /**
131 * Attempt to find the class with the superclass we refuse to
132 * load. This is expected to throw an
133 * InvocationTargetException, with a NullPointerException as
134 * its cause.
135 */
136 public void findBrokenClass()
137 throws TestFailed, InvocationTargetException
138 {
139 findDexClass(CLASS_NAME);
140 }
141 }
142
143 /**
144 * Main entry point.
145 */
146 public static void main(String[] args)
147 throws TestFailed, ClassNotFoundException {
148 /*
149 * Run test.
150 */
151 testFailLoadAndGc();
152 }
153
154 /**
155 * See if we can GC after a failed load.
156 */
157 static void testFailLoadAndGc() throws TestFailed {
158 try {
159 BrokenDexLoader loader;
160
161 loader = new BrokenDexLoader(ClassLoader.getSystemClassLoader());
162 loader.findBrokenClass();
163 System.err.println("ERROR: Inaccessible was accessible");
164 } catch (InvocationTargetException ite) {
165 Throwable cause = ite.getCause();
166 if (cause instanceof NullPointerException) {
167 System.err.println("Got expected ITE/NPE");
168 } else {
169 System.err.println("Got unexpected ITE");
170 ite.printStackTrace();
171 }
172 }
Mathieu Chartier7befd0e2014-02-03 17:48:41 -0800173 Runtime.getRuntime().gc();
jeffhao5d1ac922011-09-29 17:41:15 -0700174 System.out.println("GC complete.");
175 }
176}