1 /*
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 
17 public class RacyMisbehavingLoader extends DefiningLoader {
18     static {
19         // For JVM, register as parallel capable.
20         // Android treats all class loaders as parallel capable and makes this a no-op.
registerAsParallelCapable()21         registerAsParallelCapable();
22     }
23 
24     private Object lock = new Object();
25     private int index = 0;
26     private int count;
27     private boolean throw_error;
28 
29     private DefiningLoader[] defining_loaders;
30 
RacyMisbehavingLoader(ClassLoader parent, int count, boolean throw_error)31     public RacyMisbehavingLoader(ClassLoader parent, int count, boolean throw_error) {
32         super(parent);
33         this.count = count;
34         this.throw_error = throw_error;
35         defining_loaders = new DefiningLoader[2];
36         for (int i = 0; i != defining_loaders.length; ++i) {
37             defining_loaders[i] = new DefiningLoader(parent);
38         }
39     }
40 
reportAfterLoading()41     public void reportAfterLoading() {
42         synchronized (lock) {
43             ++index;
44             if (index == 2 * count) {
45                 lock.notifyAll();
46             }
47         }
48     }
49 
findClass(String name)50     protected Class<?> findClass(String name) throws ClassNotFoundException
51     {
52         if (name.equals("Test")) {
53             throw new Error("Unexpected RacyLoader.findClass(\"" + name + "\")");
54         }
55         return super.findClass(name);
56     }
57 
loadClass(String name, boolean resolve)58     protected Class<?> loadClass(String name, boolean resolve)
59         throws ClassNotFoundException
60     {
61         if (name.equals("Test")) {
62             int my_index = syncWithOtherInstances(count);
63             Class<?> result;
64             if ((my_index & 1) == 0) {
65               // Do not delay loading the correct class.
66               result = defining_loaders[my_index & 1].loadClass(name, resolve);
67             } else {
68               // Delay loading the wrong class.
69               syncWithOtherInstances(2 * count);
70               if (throw_error) {
71                 throw new Error("RacyMisbehavingLoader throw_error=true");
72               }
73               result = defining_loaders[my_index & 1].loadClass("Test3", resolve);
74             }
75             return result;
76         }
77         return super.loadClass(name, resolve);
78     }
79 
syncWithOtherInstances(int limit)80     private int syncWithOtherInstances(int limit) {
81         int my_index;
82         synchronized (lock) {
83             my_index = index;
84             ++index;
85             if (index != limit) {
86                 do {
87                     try {
88                         lock.wait();
89                     } catch (InterruptedException ie) {
90                         throw new Error(ie);
91                     }
92                 } while (index < limit);
93             } else {
94                 lock.notifyAll();
95             }
96         }
97         return my_index;
98     }
99 }
100