1*795d594fSAndroid Build Coastguard Worker /* 2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2015 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.Method; 19*795d594fSAndroid Build Coastguard Worker import java.util.ArrayList; 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 // Need to make a copy of the dex elements since we don't want an app image 35*795d594fSAndroid Build Coastguard Worker // with pre-resolved things. 36*795d594fSAndroid Build Coastguard Worker f = pathList.getClass().getDeclaredField("dexElements"); 37*795d594fSAndroid Build Coastguard Worker f.setAccessible(true); 38*795d594fSAndroid Build Coastguard Worker Object[] dexElements = (Object[]) f.get(pathList); 39*795d594fSAndroid Build Coastguard Worker f = dexElements[0].getClass().getDeclaredField("dexFile"); 40*795d594fSAndroid Build Coastguard Worker f.setAccessible(true); 41*795d594fSAndroid Build Coastguard Worker for (Object element : dexElements) { 42*795d594fSAndroid Build Coastguard Worker Object dexFile = f.get(element); 43*795d594fSAndroid Build Coastguard Worker // Make copy. 44*795d594fSAndroid Build Coastguard Worker Field fileNameField = dexFile.getClass().getDeclaredField("mFileName"); 45*795d594fSAndroid Build Coastguard Worker fileNameField.setAccessible(true); 46*795d594fSAndroid Build Coastguard Worker dexFiles.add(dexFile.getClass().getDeclaredConstructor(String.class).newInstance( 47*795d594fSAndroid Build Coastguard Worker fileNameField.get(dexFile))); 48*795d594fSAndroid Build Coastguard Worker } 49*795d594fSAndroid Build Coastguard Worker } 50*795d594fSAndroid Build Coastguard Worker 51*795d594fSAndroid Build Coastguard Worker ArrayList<Object> dexFiles = new ArrayList<Object>(); 52*795d594fSAndroid Build Coastguard Worker Field dexFileField; 53*795d594fSAndroid Build Coastguard Worker loadClass(String className, boolean resolve)54*795d594fSAndroid Build Coastguard Worker protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException { 55*795d594fSAndroid Build Coastguard Worker // Other classes may also get loaded, ignore those. 56*795d594fSAndroid Build Coastguard Worker if (className.equals("LoadedByMyClassLoader") 57*795d594fSAndroid Build Coastguard Worker || className.equals("FirstSeenByMyClassLoader")) { 58*795d594fSAndroid Build Coastguard Worker System.out.println("Request for " + className); 59*795d594fSAndroid Build Coastguard Worker } 60*795d594fSAndroid Build Coastguard Worker 61*795d594fSAndroid Build Coastguard Worker // We're only going to handle LoadedByMyClassLoader. 62*795d594fSAndroid Build Coastguard Worker if (className != "LoadedByMyClassLoader") { 63*795d594fSAndroid Build Coastguard Worker return getParent().loadClass(className); 64*795d594fSAndroid Build Coastguard Worker } 65*795d594fSAndroid Build Coastguard Worker 66*795d594fSAndroid Build Coastguard Worker // Mimic what DexPathList.findClass is doing. 67*795d594fSAndroid Build Coastguard Worker try { 68*795d594fSAndroid Build Coastguard Worker for (Object dexFile : dexFiles) { 69*795d594fSAndroid Build Coastguard Worker Method method = dexFile.getClass().getDeclaredMethod( 70*795d594fSAndroid Build Coastguard Worker "loadClassBinaryName", String.class, ClassLoader.class, List.class); 71*795d594fSAndroid Build Coastguard Worker 72*795d594fSAndroid Build Coastguard Worker if (dexFile != null) { 73*795d594fSAndroid Build Coastguard Worker Class<?> clazz = (Class<?>) method.invoke(dexFile, className, this, null); 74*795d594fSAndroid Build Coastguard Worker if (clazz != null) { 75*795d594fSAndroid Build Coastguard Worker return clazz; 76*795d594fSAndroid Build Coastguard Worker } 77*795d594fSAndroid Build Coastguard Worker } 78*795d594fSAndroid Build Coastguard Worker } 79*795d594fSAndroid Build Coastguard Worker } catch (Exception e) { /* Ignore */ } 80*795d594fSAndroid Build Coastguard Worker return null; 81*795d594fSAndroid Build Coastguard Worker } 82*795d594fSAndroid Build Coastguard Worker } 83*795d594fSAndroid Build Coastguard Worker 84*795d594fSAndroid Build Coastguard Worker class LoadedByMyClassLoader { 85*795d594fSAndroid Build Coastguard Worker /// CHECK-START: void LoadedByMyClassLoader.bar() inliner (before) 86*795d594fSAndroid Build Coastguard Worker /// CHECK: LoadClass class_name:FirstSeenByMyClassLoader 87*795d594fSAndroid Build Coastguard Worker /// CHECK-NEXT: ClinitCheck 88*795d594fSAndroid Build Coastguard Worker /// CHECK-NEXT: InvokeStaticOrDirect 89*795d594fSAndroid Build Coastguard Worker /// CHECK-NEXT: LoadClass class_name:java.lang.System 90*795d594fSAndroid Build Coastguard Worker /// CHECK-NEXT: ClinitCheck 91*795d594fSAndroid Build Coastguard Worker /// CHECK-NEXT: StaticFieldGet 92*795d594fSAndroid Build Coastguard Worker /// CHECK-NEXT: LoadString 93*795d594fSAndroid Build Coastguard Worker /// CHECK-NEXT: NullCheck 94*795d594fSAndroid Build Coastguard Worker /// CHECK-NEXT: InvokeVirtual 95*795d594fSAndroid Build Coastguard Worker 96*795d594fSAndroid Build Coastguard Worker /// CHECK-START: void LoadedByMyClassLoader.bar() inliner (after) 97*795d594fSAndroid Build Coastguard Worker /// CHECK: LoadClass class_name:FirstSeenByMyClassLoader 98*795d594fSAndroid Build Coastguard Worker /// CHECK-NEXT: ClinitCheck 99*795d594fSAndroid Build Coastguard Worker /* We inlined FirstSeenByMyClassLoader.$inline$bar */ 100*795d594fSAndroid Build Coastguard Worker /// CHECK-NEXT: LoadClass class_name:java.lang.System 101*795d594fSAndroid Build Coastguard Worker /// CHECK-NEXT: ClinitCheck 102*795d594fSAndroid Build Coastguard Worker /// CHECK-NEXT: StaticFieldGet 103*795d594fSAndroid Build Coastguard Worker /// CHECK-NEXT: LoadString 104*795d594fSAndroid Build Coastguard Worker /// CHECK-NEXT: NullCheck 105*795d594fSAndroid Build Coastguard Worker /// CHECK-NEXT: InvokeVirtual 106*795d594fSAndroid Build Coastguard Worker 107*795d594fSAndroid Build Coastguard Worker /// CHECK-START: void LoadedByMyClassLoader.bar() register (before) 108*795d594fSAndroid Build Coastguard Worker /* Load and initialize FirstSeenByMyClassLoader */ 109*795d594fSAndroid Build Coastguard Worker /// CHECK: LoadClass class_name:FirstSeenByMyClassLoader gen_clinit_check:true 110*795d594fSAndroid Build Coastguard Worker /* Load and initialize System */ 111*795d594fSAndroid Build Coastguard Worker // There may be HX86ComputeBaseMethodAddress here. 112*795d594fSAndroid Build Coastguard Worker /// CHECK: LoadClass class_name:java.lang.System 113*795d594fSAndroid Build Coastguard Worker // The ClinitCheck may (PIC) or may not (non-PIC) be merged into the LoadClass. 114*795d594fSAndroid Build Coastguard Worker // (The merging checks for environment match but HLoadClass/kBootImageAddress 115*795d594fSAndroid Build Coastguard Worker // used for non-PIC mode does not have an environment at all.) 116*795d594fSAndroid Build Coastguard Worker /// CHECK: StaticFieldGet 117*795d594fSAndroid Build Coastguard Worker // There may be HX86ComputeBaseMethodAddress here. 118*795d594fSAndroid Build Coastguard Worker /// CHECK: LoadString 119*795d594fSAndroid Build Coastguard Worker /// CHECK-NEXT: NullCheck 120*795d594fSAndroid Build Coastguard Worker /// CHECK-NEXT: InvokeVirtual bar()121*795d594fSAndroid Build Coastguard Worker public static void bar() { 122*795d594fSAndroid Build Coastguard Worker FirstSeenByMyClassLoader.$inline$bar(); 123*795d594fSAndroid Build Coastguard Worker System.out.println("In between the two calls."); 124*795d594fSAndroid Build Coastguard Worker FirstSeenByMyClassLoader.$noinline$bar(); 125*795d594fSAndroid Build Coastguard Worker } 126*795d594fSAndroid Build Coastguard Worker } 127*795d594fSAndroid Build Coastguard Worker 128*795d594fSAndroid Build Coastguard Worker public class Main { main(String[] args)129*795d594fSAndroid Build Coastguard Worker public static void main(String[] args) throws Exception { 130*795d594fSAndroid Build Coastguard Worker MyClassLoader o = new MyClassLoader(); 131*795d594fSAndroid Build Coastguard Worker Class<?> foo = o.loadClass("LoadedByMyClassLoader"); 132*795d594fSAndroid Build Coastguard Worker Method m = foo.getDeclaredMethod("bar"); 133*795d594fSAndroid Build Coastguard Worker m.invoke(null); 134*795d594fSAndroid Build Coastguard Worker } 135*795d594fSAndroid Build Coastguard Worker } 136