1*795d594fSAndroid Build Coastguard Worker /* 2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2010 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.Constructor; 18*795d594fSAndroid Build Coastguard Worker import java.lang.reflect.Method; 19*795d594fSAndroid Build Coastguard Worker import java.lang.reflect.InvocationTargetException; 20*795d594fSAndroid Build Coastguard Worker 21*795d594fSAndroid Build Coastguard Worker /** 22*795d594fSAndroid Build Coastguard Worker * Class loader test. 23*795d594fSAndroid Build Coastguard Worker */ 24*795d594fSAndroid Build Coastguard Worker public class Main { 25*795d594fSAndroid Build Coastguard Worker /** 26*795d594fSAndroid Build Coastguard Worker * Thrown when an unexpected Exception is caught internally. 27*795d594fSAndroid Build Coastguard Worker */ 28*795d594fSAndroid Build Coastguard Worker static class TestFailed extends Exception { TestFailed(Throwable cause)29*795d594fSAndroid Build Coastguard Worker public TestFailed(Throwable cause) { 30*795d594fSAndroid Build Coastguard Worker super(cause); 31*795d594fSAndroid Build Coastguard Worker } 32*795d594fSAndroid Build Coastguard Worker } 33*795d594fSAndroid Build Coastguard Worker 34*795d594fSAndroid Build Coastguard Worker /** 35*795d594fSAndroid Build Coastguard Worker * A class loader which loads classes from the dex file 36*795d594fSAndroid Build Coastguard Worker * "test.jar". However, it will return null when asked to load the 37*795d594fSAndroid Build Coastguard Worker * class InaccessibleSuper. 38*795d594fSAndroid Build Coastguard Worker * 39*795d594fSAndroid Build Coastguard Worker * When testing code calls BrokenDexLoader's findBrokenClass(), 40*795d594fSAndroid Build Coastguard Worker * a BrokenDexLoader will be the defining loader for the class 41*795d594fSAndroid Build Coastguard Worker * Inaccessible. The VM will call the defining loader for 42*795d594fSAndroid Build Coastguard Worker * "InaccessibleSuper", which will return null, which the VM 43*795d594fSAndroid Build Coastguard Worker * should be able to deal with gracefully. 44*795d594fSAndroid Build Coastguard Worker * 45*795d594fSAndroid Build Coastguard Worker * Note that this depends heavily on the Dalvik test harness. 46*795d594fSAndroid Build Coastguard Worker */ 47*795d594fSAndroid Build Coastguard Worker static class BrokenDexLoader extends ClassLoader { 48*795d594fSAndroid Build Coastguard Worker 49*795d594fSAndroid Build Coastguard Worker /** We return null when asked to load InaccessibleSuper. */ 50*795d594fSAndroid Build Coastguard Worker private static class InaccessibleSuper {} 51*795d594fSAndroid Build Coastguard Worker private static class Inaccessible extends InaccessibleSuper {} 52*795d594fSAndroid Build Coastguard Worker 53*795d594fSAndroid Build Coastguard Worker private static final String SUPERCLASS_NAME = 54*795d594fSAndroid Build Coastguard Worker "Main$BrokenDexLoader$InaccessibleSuper"; 55*795d594fSAndroid Build Coastguard Worker private static final String CLASS_NAME = 56*795d594fSAndroid Build Coastguard Worker "Main$BrokenDexLoader$Inaccessible"; 57*795d594fSAndroid Build Coastguard Worker 58*795d594fSAndroid Build Coastguard Worker private static final String DEX_FILE = System.getenv("DEX_LOCATION") + "/086-null-super.jar"; 59*795d594fSAndroid Build Coastguard Worker BrokenDexLoader(ClassLoader parent)60*795d594fSAndroid Build Coastguard Worker public BrokenDexLoader(ClassLoader parent) { 61*795d594fSAndroid Build Coastguard Worker super(parent); 62*795d594fSAndroid Build Coastguard Worker } 63*795d594fSAndroid Build Coastguard Worker 64*795d594fSAndroid Build Coastguard Worker /** 65*795d594fSAndroid Build Coastguard Worker * Finds the class with the specified binary name, from DEX_FILE. 66*795d594fSAndroid Build Coastguard Worker * 67*795d594fSAndroid Build Coastguard Worker * If we don't find a match, we throw an exception. 68*795d594fSAndroid Build Coastguard Worker */ findDexClass(String name)69*795d594fSAndroid Build Coastguard Worker private Class<?> findDexClass(String name) 70*795d594fSAndroid Build Coastguard Worker throws TestFailed, InvocationTargetException 71*795d594fSAndroid Build Coastguard Worker { 72*795d594fSAndroid Build Coastguard Worker 73*795d594fSAndroid Build Coastguard Worker try { 74*795d594fSAndroid Build Coastguard Worker /* 75*795d594fSAndroid Build Coastguard Worker * Find the DexFile class, and construct a DexFile object 76*795d594fSAndroid Build Coastguard Worker * through reflection, then call loadCLass on it. 77*795d594fSAndroid Build Coastguard Worker */ 78*795d594fSAndroid Build Coastguard Worker Class<?> mDexClass = ClassLoader.getSystemClassLoader(). 79*795d594fSAndroid Build Coastguard Worker loadClass("dalvik.system.DexFile"); 80*795d594fSAndroid Build Coastguard Worker Constructor<?> ctor = mDexClass.getConstructor(String.class); 81*795d594fSAndroid Build Coastguard Worker Object mDexFile = ctor.newInstance(DEX_FILE); 82*795d594fSAndroid Build Coastguard Worker Method meth = mDexClass. 83*795d594fSAndroid Build Coastguard Worker getMethod("loadClass", String.class, ClassLoader.class); 84*795d594fSAndroid Build Coastguard Worker /* 85*795d594fSAndroid Build Coastguard Worker * Invoking loadClass on CLASS_NAME is expected to 86*795d594fSAndroid Build Coastguard Worker * throw an InvocationTargetException. Anything else 87*795d594fSAndroid Build Coastguard Worker * is an error we can't recover from. 88*795d594fSAndroid Build Coastguard Worker */ 89*795d594fSAndroid Build Coastguard Worker meth.invoke(mDexFile, name, this); 90*795d594fSAndroid Build Coastguard Worker } catch (NoSuchMethodException nsme) { 91*795d594fSAndroid Build Coastguard Worker throw new TestFailed(nsme); 92*795d594fSAndroid Build Coastguard Worker } catch (InstantiationException ie) { 93*795d594fSAndroid Build Coastguard Worker throw new TestFailed(ie); 94*795d594fSAndroid Build Coastguard Worker } catch (IllegalAccessException iae) { 95*795d594fSAndroid Build Coastguard Worker throw new TestFailed(iae); 96*795d594fSAndroid Build Coastguard Worker } catch (ClassNotFoundException cnfe) { 97*795d594fSAndroid Build Coastguard Worker throw new TestFailed(cnfe); 98*795d594fSAndroid Build Coastguard Worker } 99*795d594fSAndroid Build Coastguard Worker 100*795d594fSAndroid Build Coastguard Worker return null; 101*795d594fSAndroid Build Coastguard Worker } 102*795d594fSAndroid Build Coastguard Worker 103*795d594fSAndroid Build Coastguard Worker /** 104*795d594fSAndroid Build Coastguard Worker * Load a class. 105*795d594fSAndroid Build Coastguard Worker * 106*795d594fSAndroid Build Coastguard Worker * Return null if the class's name is SUPERCLASS_NAME; 107*795d594fSAndroid Build Coastguard Worker * otherwise invoke the super's loadClass method. 108*795d594fSAndroid Build Coastguard Worker */ loadClass(String name, boolean resolve)109*795d594fSAndroid Build Coastguard Worker public Class<?> loadClass(String name, boolean resolve) 110*795d594fSAndroid Build Coastguard Worker throws ClassNotFoundException 111*795d594fSAndroid Build Coastguard Worker { 112*795d594fSAndroid Build Coastguard Worker if (SUPERCLASS_NAME.equals(name)) { 113*795d594fSAndroid Build Coastguard Worker return null; 114*795d594fSAndroid Build Coastguard Worker } 115*795d594fSAndroid Build Coastguard Worker 116*795d594fSAndroid Build Coastguard Worker return super.loadClass(name, resolve); 117*795d594fSAndroid Build Coastguard Worker } 118*795d594fSAndroid Build Coastguard Worker 119*795d594fSAndroid Build Coastguard Worker /** 120*795d594fSAndroid Build Coastguard Worker * Attempt to find the class with the superclass we refuse to 121*795d594fSAndroid Build Coastguard Worker * load. This is expected to throw an 122*795d594fSAndroid Build Coastguard Worker * InvocationTargetException, with a NullPointerException as 123*795d594fSAndroid Build Coastguard Worker * its cause. 124*795d594fSAndroid Build Coastguard Worker */ findBrokenClass()125*795d594fSAndroid Build Coastguard Worker public void findBrokenClass() 126*795d594fSAndroid Build Coastguard Worker throws TestFailed, InvocationTargetException 127*795d594fSAndroid Build Coastguard Worker { 128*795d594fSAndroid Build Coastguard Worker findDexClass(CLASS_NAME); 129*795d594fSAndroid Build Coastguard Worker } 130*795d594fSAndroid Build Coastguard Worker } 131*795d594fSAndroid Build Coastguard Worker 132*795d594fSAndroid Build Coastguard Worker /** 133*795d594fSAndroid Build Coastguard Worker * Main entry point. 134*795d594fSAndroid Build Coastguard Worker */ main(String[] args)135*795d594fSAndroid Build Coastguard Worker public static void main(String[] args) 136*795d594fSAndroid Build Coastguard Worker throws TestFailed, ClassNotFoundException { 137*795d594fSAndroid Build Coastguard Worker /* 138*795d594fSAndroid Build Coastguard Worker * Run test. 139*795d594fSAndroid Build Coastguard Worker */ 140*795d594fSAndroid Build Coastguard Worker testFailLoadAndGc(); 141*795d594fSAndroid Build Coastguard Worker } 142*795d594fSAndroid Build Coastguard Worker 143*795d594fSAndroid Build Coastguard Worker /** 144*795d594fSAndroid Build Coastguard Worker * See if we can GC after a failed load. 145*795d594fSAndroid Build Coastguard Worker */ testFailLoadAndGc()146*795d594fSAndroid Build Coastguard Worker static void testFailLoadAndGc() throws TestFailed { 147*795d594fSAndroid Build Coastguard Worker try { 148*795d594fSAndroid Build Coastguard Worker BrokenDexLoader loader; 149*795d594fSAndroid Build Coastguard Worker 150*795d594fSAndroid Build Coastguard Worker loader = new BrokenDexLoader(ClassLoader.getSystemClassLoader()); 151*795d594fSAndroid Build Coastguard Worker loader.findBrokenClass(); 152*795d594fSAndroid Build Coastguard Worker System.out.println("ERROR: Inaccessible was accessible"); 153*795d594fSAndroid Build Coastguard Worker } catch (InvocationTargetException ite) { 154*795d594fSAndroid Build Coastguard Worker Throwable cause = ite.getCause(); 155*795d594fSAndroid Build Coastguard Worker if (cause instanceof NullPointerException) { 156*795d594fSAndroid Build Coastguard Worker System.out.println("Got expected ITE/NPE"); 157*795d594fSAndroid Build Coastguard Worker } else { 158*795d594fSAndroid Build Coastguard Worker System.out.println("Got unexpected ITE"); 159*795d594fSAndroid Build Coastguard Worker ite.printStackTrace(System.out); 160*795d594fSAndroid Build Coastguard Worker } 161*795d594fSAndroid Build Coastguard Worker } 162*795d594fSAndroid Build Coastguard Worker } 163*795d594fSAndroid Build Coastguard Worker } 164