xref: /aosp_15_r20/art/test/156-register-dex-file-multi-loader/src/Main.java (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2017 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker import java.lang.reflect.Field;
18*795d594fSAndroid Build Coastguard Worker import java.lang.reflect.InvocationTargetException;
19*795d594fSAndroid Build Coastguard Worker import java.lang.reflect.Method;
20*795d594fSAndroid Build Coastguard Worker import java.util.List;
21*795d594fSAndroid Build Coastguard Worker 
22*795d594fSAndroid Build Coastguard Worker class MyClassLoader extends ClassLoader {
MyClassLoader()23*795d594fSAndroid Build Coastguard Worker   MyClassLoader() throws Exception {
24*795d594fSAndroid Build Coastguard Worker     super(MyClassLoader.class.getClassLoader());
25*795d594fSAndroid Build Coastguard Worker 
26*795d594fSAndroid Build Coastguard Worker     // Some magic to get access to the pathList field of BaseDexClassLoader.
27*795d594fSAndroid Build Coastguard Worker     ClassLoader loader = getClass().getClassLoader();
28*795d594fSAndroid Build Coastguard Worker     Class<?> baseDexClassLoader = loader.getClass().getSuperclass();
29*795d594fSAndroid Build Coastguard Worker     Field f = baseDexClassLoader.getDeclaredField("pathList");
30*795d594fSAndroid Build Coastguard Worker     f.setAccessible(true);
31*795d594fSAndroid Build Coastguard Worker     Object pathList = f.get(loader);
32*795d594fSAndroid Build Coastguard Worker 
33*795d594fSAndroid Build Coastguard Worker     // Some magic to get access to the dexField field of pathList.
34*795d594fSAndroid Build Coastguard Worker     f = pathList.getClass().getDeclaredField("dexElements");
35*795d594fSAndroid Build Coastguard Worker     f.setAccessible(true);
36*795d594fSAndroid Build Coastguard Worker     dexElements = (Object[]) f.get(pathList);
37*795d594fSAndroid Build Coastguard Worker     dexFileField = dexElements[0].getClass().getDeclaredField("dexFile");
38*795d594fSAndroid Build Coastguard Worker     dexFileField.setAccessible(true);
39*795d594fSAndroid Build Coastguard Worker   }
40*795d594fSAndroid Build Coastguard Worker 
41*795d594fSAndroid Build Coastguard Worker   Object[] dexElements;
42*795d594fSAndroid Build Coastguard Worker   Field dexFileField;
43*795d594fSAndroid Build Coastguard Worker 
loadClass(String className, boolean resolve)44*795d594fSAndroid Build Coastguard Worker   protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException {
45*795d594fSAndroid Build Coastguard Worker     // Mimic what DexPathList.findClass is doing.
46*795d594fSAndroid Build Coastguard Worker     try {
47*795d594fSAndroid Build Coastguard Worker       for (Object element : dexElements) {
48*795d594fSAndroid Build Coastguard Worker         Object dex = dexFileField.get(element);
49*795d594fSAndroid Build Coastguard Worker         Method method = dex.getClass().getDeclaredMethod(
50*795d594fSAndroid Build Coastguard Worker             "loadClassBinaryName", String.class, ClassLoader.class, List.class);
51*795d594fSAndroid Build Coastguard Worker 
52*795d594fSAndroid Build Coastguard Worker         if (dex != null) {
53*795d594fSAndroid Build Coastguard Worker           Class<?> clazz = (Class<?>)method.invoke(dex, className, this, null);
54*795d594fSAndroid Build Coastguard Worker           if (clazz != null) {
55*795d594fSAndroid Build Coastguard Worker             return clazz;
56*795d594fSAndroid Build Coastguard Worker           }
57*795d594fSAndroid Build Coastguard Worker         }
58*795d594fSAndroid Build Coastguard Worker       }
59*795d594fSAndroid Build Coastguard Worker     } catch (InvocationTargetException ite) {
60*795d594fSAndroid Build Coastguard Worker       throw new ClassNotFoundException(className, ite.getCause());
61*795d594fSAndroid Build Coastguard Worker     } catch (Exception e) {
62*795d594fSAndroid Build Coastguard Worker       throw new Error(e);
63*795d594fSAndroid Build Coastguard Worker     }
64*795d594fSAndroid Build Coastguard Worker     return getParent().loadClass(className);
65*795d594fSAndroid Build Coastguard Worker   }
66*795d594fSAndroid Build Coastguard Worker }
67*795d594fSAndroid Build Coastguard Worker 
68*795d594fSAndroid Build Coastguard Worker public class Main {
main(String[] args)69*795d594fSAndroid Build Coastguard Worker   public static void main(String[] args) throws Exception {
70*795d594fSAndroid Build Coastguard Worker     MyClassLoader o = new MyClassLoader();
71*795d594fSAndroid Build Coastguard Worker     try {
72*795d594fSAndroid Build Coastguard Worker       Class<?> foo = o.loadClass("Main");
73*795d594fSAndroid Build Coastguard Worker       throw new Error("Unreachable");
74*795d594fSAndroid Build Coastguard Worker     } catch (ClassNotFoundException cnfe) {
75*795d594fSAndroid Build Coastguard Worker       boolean unexpected = false;
76*795d594fSAndroid Build Coastguard Worker       if (!(cnfe.getCause() instanceof InternalError)) {
77*795d594fSAndroid Build Coastguard Worker         unexpected = true;
78*795d594fSAndroid Build Coastguard Worker       } else {
79*795d594fSAndroid Build Coastguard Worker         String message = cnfe.getCause().getMessage();
80*795d594fSAndroid Build Coastguard Worker         unexpected = !message.startsWith("Attempt to register dex file ") ||
81*795d594fSAndroid Build Coastguard Worker                      !message.endsWith(" with multiple class loaders");
82*795d594fSAndroid Build Coastguard Worker       }
83*795d594fSAndroid Build Coastguard Worker       if (unexpected) {
84*795d594fSAndroid Build Coastguard Worker         cnfe.getCause().printStackTrace(System.out);
85*795d594fSAndroid Build Coastguard Worker       }
86*795d594fSAndroid Build Coastguard Worker     }
87*795d594fSAndroid Build Coastguard Worker   }
88*795d594fSAndroid Build Coastguard Worker }
89