blob: 8d8f6b66aeeb585464d815c72c11e6968de7faf4 [file] [log] [blame]
Vladimir Markoe47172b2016-11-25 11:47:20 +00001/*
2 * Copyright (C) 2016 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.ref.WeakReference;
18import java.lang.reflect.Field;
19import java.lang.reflect.InvocationTargetException;
20import java.lang.reflect.Method;
21
22public class Main {
23 public static void main(String[] args) throws Exception {
24 try {
25 System.loadLibrary(args[0]);
26 } catch (UnsatisfiedLinkError ule) {
27 usingRI = true;
28 // Add expected JNI_OnLoad log line to match expected.txt.
29 System.out.println("JNI_OnLoad called");
30 }
31
32 testClearDexCache();
33 testMultiDex();
34 testRacyLoader();
35 testRacyLoader2();
36 testMisbehavingLoader();
37 testRacyMisbehavingLoader();
38 testRacyMisbehavingLoader2();
39 }
40
41 private static void testClearDexCache() throws Exception {
42 DelegatingLoader delegating_loader = createDelegatingLoader();
43 Class<?> helper = delegating_loader.loadClass("Helper1");
44
45 WeakReference<Class<?>> weak_test1 = wrapHelperGet(helper);
46 changeInner(delegating_loader);
47 clearResolvedTypes(helper);
48 Runtime.getRuntime().gc();
49 WeakReference<Class<?>> weak_test2 = wrapHelperGet(helper);
50 Runtime.getRuntime().gc();
51
52 Class<?> test1 = weak_test1.get();
53 if (test1 == null) {
54 System.out.println("test1 disappeared");
55 }
56 Class<?> test2 = weak_test2.get();
57 if (test2 == null) {
58 System.out.println("test2 disappeared");
59 }
60 if (test1 != test2) {
61 System.out.println("test1 != test2");
62 }
63
64 System.out.println("testClearDexCache done");
65 }
66
67 private static void testMultiDex() throws Exception {
68 DelegatingLoader delegating_loader = createDelegatingLoader();
69
70 Class<?> helper1 = delegating_loader.loadClass("Helper1");
71 WeakReference<Class<?>> weak_test1 = wrapHelperGet(helper1);
72
73 changeInner(delegating_loader);
74
75 Class<?> helper2 = delegating_loader.loadClass("Helper2");
76 WeakReference<Class<?>> weak_test2 = wrapHelperGet(helper2);
77
78 Runtime.getRuntime().gc();
79
80 Class<?> test1 = weak_test1.get();
81 if (test1 == null) {
82 System.out.println("test1 disappeared");
83 }
84 Class<?> test2 = weak_test2.get();
85 if (test2 == null) {
86 System.out.println("test2 disappeared");
87 }
88 if (test1 != test2) {
89 System.out.println("test1 != test2");
90 }
91
92 System.out.println("testMultiDex done");
93 }
94
95 private static void testMisbehavingLoader() throws Exception {
96 ClassLoader system_loader = ClassLoader.getSystemClassLoader();
97 DefiningLoader defining_loader = new DefiningLoader(system_loader);
98 MisbehavingLoader misbehaving_loader =
99 new MisbehavingLoader(system_loader, defining_loader);
100 Class<?> helper = misbehaving_loader.loadClass("Helper1");
101
102 try {
103 WeakReference<Class<?>> weak_test = wrapHelperGet(helper);
104 } catch (InvocationTargetException ite) {
105 String message = ite.getCause().getMessage();
106 if (usingRI && "Test".equals(message)) {
107 // Replace RI message with dalvik message to match expected.txt.
108 message = "Initiating class loader of type " +
109 misbehaving_loader.getClass().getName() +
110 " returned class Helper2 instead of Test.";
111 }
112 System.out.println(ite.getCause().getClass().getName() + ": " + message);
113 }
114 System.out.println("testMisbehavingLoader done");
115 }
116
117 private static void testRacyLoader() throws Exception {
118 final ClassLoader system_loader = ClassLoader.getSystemClassLoader();
119
120 final Thread[] threads = new Thread[4];
121 final Object[] results = new Object[threads.length];
122
123 final RacyLoader racy_loader = new RacyLoader(system_loader, threads.length);
124 final Class<?> helper1 = racy_loader.loadClass("Helper1");
125 skipVerification(helper1); // Avoid class loading during verification.
126
127 for (int i = 0; i != threads.length; ++i) {
128 final int my_index = i;
129 Thread t = new Thread() {
130 public void run() {
131 try {
132 Method get = helper1.getDeclaredMethod("get");
133 results[my_index] = get.invoke(null);
134 } catch (InvocationTargetException ite) {
135 results[my_index] = ite.getCause();
136 } catch (Throwable t) {
137 results[my_index] = t;
138 }
139 }
140 };
141 t.start();
142 threads[i] = t;
143 }
144 for (Thread t : threads) {
145 t.join();
146 }
147 dumpResultStats(results);
148 System.out.println("testRacyLoader done");
149 }
150
151 private static void testRacyLoader2() throws Exception {
152 final ClassLoader system_loader = ClassLoader.getSystemClassLoader();
153
154 final Thread[] threads = new Thread[4];
155 final Object[] results = new Object[threads.length];
156
157 final RacyLoader racy_loader = new RacyLoader(system_loader, threads.length);
158 final Class<?> helper1 = racy_loader.loadClass("Helper1");
159 skipVerification(helper1); // Avoid class loading during verification.
160 final Class<?> helper3 = racy_loader.loadClass("Helper3");
161 skipVerification(helper3); // Avoid class loading during verification.
162
163 for (int i = 0; i != threads.length; ++i) {
164 final int my_index = i;
165 Thread t = new Thread() {
166 public void run() {
167 try {
168 Class<?> helper = (my_index < threads.length / 2) ? helper1 : helper3;
169 Method get = helper.getDeclaredMethod("get");
170 results[my_index] = get.invoke(null);
171 } catch (InvocationTargetException ite) {
172 results[my_index] = ite.getCause();
173 } catch (Throwable t) {
174 results[my_index] = t;
175 }
176 }
177 };
178 t.start();
179 threads[i] = t;
180 }
181 for (Thread t : threads) {
182 t.join();
183 }
184 dumpResultStats(results);
185 System.out.println("testRacyLoader2 done");
186 }
187
188 private static void dumpResultStats(Object[] results) throws Exception {
189 int throwables = 0;
190 int class_weaks = 0;
191 int unique_class_weaks = 0;
192 for (int i = 0; i != results.length; ++i) {
193 Object r = results[i];
194 if (r instanceof Throwable) {
195 ++throwables;
196 System.out.println(((Throwable) r).getMessage());
197 } else if (isClassPair(r)) {
198 printPair(r);
199 Object ref = getSecond(r);
200 ++class_weaks;
201 ++unique_class_weaks;
202 for (int j = 0; j != i; ++j) {
203 Object rj = results[j];
204 if (isClassPair(results[j]) && getSecond(results[j]) == ref) {
205 --unique_class_weaks;
206 break;
207 }
208 }
209 }
210 }
211 System.out.println("total: " + results.length);
212 System.out.println(" throwables: " + throwables);
213 System.out.println(" class_weaks: " + class_weaks
214 + " (" + unique_class_weaks + " unique)");
215 }
216
217 private static void testRacyMisbehavingLoader() throws Exception {
218 final ClassLoader system_loader = ClassLoader.getSystemClassLoader();
219
220 final Thread[] threads = new Thread[4];
221 final Object[] results = new Object[threads.length];
222
223 final RacyMisbehavingLoader racy_loader =
224 new RacyMisbehavingLoader(system_loader, threads.length, false);
225 final Class<?> helper1 = racy_loader.loadClass("RacyMisbehavingHelper");
226 skipVerification(helper1); // Avoid class loading during verification.
227
228 for (int i = 0; i != threads.length; ++i) {
229 final int my_index = i;
230 Thread t = new Thread() {
231 public void run() {
232 try {
233 Method get = helper1.getDeclaredMethod("get");
234 results[my_index] = get.invoke(null);
235 } catch (InvocationTargetException ite) {
236 results[my_index] = ite.getCause();
237 } catch (Throwable t) {
238 results[my_index] = t;
239 }
240 }
241 };
242 t.start();
243 threads[i] = t;
244 }
245 for (Thread t : threads) {
246 t.join();
247 }
248 dumpResultStats(results);
249 System.out.println("testRacyMisbehavingLoader done");
250 }
251
252 private static void testRacyMisbehavingLoader2() throws Exception {
253 final ClassLoader system_loader = ClassLoader.getSystemClassLoader();
254
255 final Thread[] threads = new Thread[4];
256 final Object[] results = new Object[threads.length];
257
258 final RacyMisbehavingLoader racy_loader =
259 new RacyMisbehavingLoader(system_loader, threads.length, true);
260 final Class<?> helper1 = racy_loader.loadClass("RacyMisbehavingHelper");
261 skipVerification(helper1); // Avoid class loading during verification.
262
263 for (int i = 0; i != threads.length; ++i) {
264 final int my_index = i;
265 Thread t = new Thread() {
266 public void run() {
267 try {
268 Method get = helper1.getDeclaredMethod("get");
269 results[my_index] = get.invoke(null);
270 } catch (InvocationTargetException ite) {
271 results[my_index] = ite.getCause();
272 } catch (Throwable t) {
273 results[my_index] = t;
274 }
275 }
276 };
277 t.start();
278 threads[i] = t;
279 }
280 for (Thread t : threads) {
281 t.join();
282 }
283 dumpResultStats(results);
284 System.out.println("testRacyMisbehavingLoader2 done");
285 }
286
287 private static DelegatingLoader createDelegatingLoader() {
288 ClassLoader system_loader = ClassLoader.getSystemClassLoader();
289 DefiningLoader defining_loader = new DefiningLoader(system_loader);
290 return new DelegatingLoader(system_loader, defining_loader);
291 }
292
293 private static void changeInner(DelegatingLoader delegating_loader) {
294 ClassLoader system_loader = ClassLoader.getSystemClassLoader();
295 DefiningLoader defining_loader = new DefiningLoader(system_loader);
296 delegating_loader.resetDefiningLoader(defining_loader);
297 }
298
299 private static WeakReference<Class<?>> wrapHelperGet(Class<?> helper) throws Exception {
300 Method get = helper.getDeclaredMethod("get");
301 Object pair = get.invoke(null);
302 printPair(pair);
303 return new WeakReference<Class<?>>(getSecond(pair));
304 }
305
306 private static void printPair(Object pair) throws Exception {
307 Method print = pair.getClass().getDeclaredMethod("print");
308 print.invoke(pair);
309 }
310
311 private static Class<?> getSecond(Object pair) throws Exception {
312 Field second = pair.getClass().getDeclaredField("second");
313 return (Class<?>) second.get(pair);
314 }
315
316 private static boolean isClassPair(Object r) {
317 return r != null && r.getClass().getName().equals("ClassPair");
318 }
319
320 public static void clearResolvedTypes(Class<?> c) {
321 if (!usingRI) {
322 nativeClearResolvedTypes(c);
323 }
324 }
325
326 // Skip verification of a class on ART. Verification can cause classes to be loaded
327 // while holding a lock on the class being verified and holding that lock can interfere
328 // with the intent of the "racy" tests. In these tests we're waiting in the loadClass()
329 // for all the tested threads to synchronize and they cannot reach that point if they
330 // are waiting for the class lock on ClassLinker::InitializeClass(Helper1/Helper3).
331 public static void skipVerification(Class<?> c) {
332 if (!usingRI) {
333 nativeSkipVerification(c);
334 }
335 }
336
337 public static native void nativeClearResolvedTypes(Class<?> c);
338 public static native void nativeSkipVerification(Class<?> c);
339
340 static boolean usingRI = false;
341}