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