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