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