| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| public class RacyMisbehavingLoader extends DefiningLoader { |
| static { |
| // For JVM, register as parallel capable. |
| // Android treats all class loaders as parallel capable and makes this a no-op. |
| registerAsParallelCapable(); |
| } |
| |
| private Object lock = new Object(); |
| private int index = 0; |
| private int count; |
| private boolean throw_error; |
| |
| private DefiningLoader[] defining_loaders; |
| |
| public RacyMisbehavingLoader(ClassLoader parent, int count, boolean throw_error) { |
| super(parent); |
| this.count = count; |
| this.throw_error = throw_error; |
| defining_loaders = new DefiningLoader[2]; |
| for (int i = 0; i != defining_loaders.length; ++i) { |
| defining_loaders[i] = new DefiningLoader(parent); |
| } |
| } |
| |
| public void reportAfterLoading() { |
| synchronized (lock) { |
| ++index; |
| if (index == 2 * count) { |
| lock.notifyAll(); |
| } |
| } |
| } |
| |
| protected Class<?> findClass(String name) throws ClassNotFoundException |
| { |
| if (name.equals("Test")) { |
| throw new Error("Unexpected RacyLoader.findClass(\"" + name + "\")"); |
| } |
| return super.findClass(name); |
| } |
| |
| protected Class<?> loadClass(String name, boolean resolve) |
| throws ClassNotFoundException |
| { |
| if (name.equals("Test")) { |
| int my_index = syncWithOtherInstances(count); |
| Class<?> result; |
| if ((my_index & 1) == 0) { |
| // Do not delay loading the correct class. |
| result = defining_loaders[my_index & 1].loadClass(name, resolve); |
| } else { |
| // Delay loading the wrong class. |
| syncWithOtherInstances(2 * count); |
| if (throw_error) { |
| throw new Error("RacyMisbehavingLoader throw_error=true"); |
| } |
| result = defining_loaders[my_index & 1].loadClass("Test3", resolve); |
| } |
| return result; |
| } |
| return super.loadClass(name, resolve); |
| } |
| |
| private int syncWithOtherInstances(int limit) { |
| int my_index; |
| synchronized (lock) { |
| my_index = index; |
| ++index; |
| if (index != limit) { |
| do { |
| try { |
| lock.wait(); |
| } catch (InterruptedException ie) { |
| throw new Error(ie); |
| } |
| } while (index < limit); |
| } else { |
| lock.notifyAll(); |
| } |
| } |
| return my_index; |
| } |
| } |