1 /*
2  * Copyright (C) 2015 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 import java.lang.reflect.Field;
18 import java.lang.reflect.Method;
19 import java.util.List;
20 import p1.InP1;
21 import p1.PlaceHolder;
22 
23 
24 // Custom class loader to prevent loading while verifying.
25 class MyClassLoader extends ClassLoader {
MyClassLoader()26   MyClassLoader() throws Exception {
27     super(MyClassLoader.class.getClassLoader());
28 
29     // Some magic to get access to the pathList field of BaseDexClassLoader.
30     ClassLoader loader = getClass().getClassLoader();
31     Class<?> baseDexClassLoader = loader.getClass().getSuperclass();
32     Field f = baseDexClassLoader.getDeclaredField("pathList");
33     f.setAccessible(true);
34     Object pathList = f.get(loader);
35 
36     // Some magic to get access to the dexField field of pathList.
37     f = pathList.getClass().getDeclaredField("dexElements");
38     f.setAccessible(true);
39     dexElements = (Object[]) f.get(pathList);
40     dexFileField = dexElements[0].getClass().getDeclaredField("dexFile");
41     dexFileField.setAccessible(true);
42   }
43 
44   Object[] dexElements;
45   Field dexFileField;
46 
loadClass(String className, boolean resolve)47   protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
48     if (className.equals("p1.OtherInP1") && !p1.PlaceHolder.entered) {
49       // The request comes from the verifier. Return null to get the access check entry
50       // point in the compiled code.
51       return null;
52     }
53     // Mimic what DexPathList.findClass is doing.
54     try {
55       for (Object element : dexElements) {
56         Object dex = dexFileField.get(element);
57         Method method = dex.getClass().getDeclaredMethod(
58             "loadClassBinaryName", String.class, ClassLoader.class, List.class);
59 
60         if (dex != null) {
61           Class<?> clazz = (Class<?>)method.invoke(dex, className, this, null);
62           if (clazz != null) {
63             return clazz;
64           }
65         }
66       }
67     } catch (Exception e) { /* Ignore */ }
68     return getParent().loadClass(className);
69   }
70 }
71 
72 public class Main {
main(String[] args)73     public static void main(String[] args) throws Exception {
74       MyClassLoader o = new MyClassLoader();
75       Class<?> foo = o.loadClass("LoadedByMyClassLoader");
76       Method m = foo.getDeclaredMethod("main");
77       m.invoke(null);
78     }
79 }
80 
81 class LoadedByMyClassLoader {
main()82     public static void main() throws Exception {
83       for (int i = 0; i < 10000; ++i) {
84         // Warm up the JIT.
85         doTheCall(i);
86       }
87       // Sleep a while to let the JIT compile things.
88       // TODO(ngeoffray): Remove the sleep. b/25414532
89       Thread.sleep(2000);
90       doTheCall(10001);
91     }
92 
doTheCall(int i)93     public static void doTheCall(int i) {
94       InP1.$inline$AllocateOtherInP1(i);
95       InP1.$inline$AllocateArrayOtherInP1(i);
96       InP1.$inline$UseStaticFieldOtherInP1(i);
97       InP1.$inline$SetStaticFieldOtherInP1(i);
98       InP1.$inline$UseInstanceFieldOtherInP1(i);
99       InP1.$inline$SetInstanceFieldOtherInP1(i);
100       InP1.$inline$LoadOtherInP1(i);
101       InP1.$inline$StaticCallOtherInP1(i);
102       InP1.$inline$InstanceCallOtherInP1(i);
103     }
104 }
105