1581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes/* 2581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * Copyright (C) 2010 The Android Open Source Project 3581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * 4581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * Licensed under the Apache License, Version 2.0 (the "License"); 5581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * you may not use this file except in compliance with the License. 6581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * You may obtain a copy of the License at 7581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * 8581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * http://www.apache.org/licenses/LICENSE-2.0 9581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * 10581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * Unless required by applicable law or agreed to in writing, software 11581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * distributed under the License is distributed on an "AS IS" BASIS, 12581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * See the License for the specific language governing permissions and 14581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * limitations under the License. 15581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes */ 16581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes 17581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayesimport java.lang.reflect.Constructor; 18581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayesimport java.lang.reflect.Method; 19581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayesimport java.lang.reflect.InvocationTargetException; 20581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes 21581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes/** 22581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * Class loader test. 23581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes */ 24581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayespublic class Main { 25581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes /** 26581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * Thrown when an unexpected Exception is caught internally. 27581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes */ 28581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes static class TestFailed extends Exception { 29581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes public TestFailed(Throwable cause) { 30581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes super(cause); 31581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes } 32581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes } 33581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes 34581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes /** 35581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * A class loader which loads classes from the dex file 36581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * "test.jar". However, it will return null when asked to load the 37581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * class InaccessibleSuper. 38581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * 39581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * When testing code calls BrokenDexLoader's findBrokenClass(), 40581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * a BrokenDexLoader will be the defining loader for the class 41581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * Inaccessible. The VM will call the defining loader for 42581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * "InaccessibleSuper", which will return null, which the VM 43581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * should be able to deal with gracefully. 44581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * 45581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * Note that this depends heavily on the Dalvik test harness. 46581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes */ 47581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes static class BrokenDexLoader extends ClassLoader { 48581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes 49581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes /** We return null when asked to load InaccessibleSuper. */ 50581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes private static class InaccessibleSuper {} 51581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes private static class Inaccessible extends InaccessibleSuper {} 52581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes 53581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes private static final String SUPERCLASS_NAME = 54581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes "Main$BrokenDexLoader$InaccessibleSuper"; 55581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes private static final String CLASS_NAME = 56581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes "Main$BrokenDexLoader$Inaccessible"; 57581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes 58581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes private static final String DEX_FILE = "test.jar"; 59581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes 60581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes public BrokenDexLoader(ClassLoader parent) { 61581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes super(parent); 62581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes } 63581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes 64581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes /** 65581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * Finds the class with the specified binary name, from DEX_FILE. 66581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * 67581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * If we don't find a match, we throw an exception. 68581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes */ 69581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes private Class<?> findDexClass(String name) 70581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes throws TestFailed, InvocationTargetException 71581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes { 7232fed2dee7399137908042a37aec28fbbda385caAndy McFadden Object dexFile = null; 7332fed2dee7399137908042a37aec28fbbda385caAndy McFadden Class dexClass = null; 74581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes 75581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes try { 7632fed2dee7399137908042a37aec28fbbda385caAndy McFadden try { 7732fed2dee7399137908042a37aec28fbbda385caAndy McFadden /* 7832fed2dee7399137908042a37aec28fbbda385caAndy McFadden * Find the DexFile class, and construct a DexFile object 7932fed2dee7399137908042a37aec28fbbda385caAndy McFadden * through reflection, then call loadClass on it. 8032fed2dee7399137908042a37aec28fbbda385caAndy McFadden */ 8132fed2dee7399137908042a37aec28fbbda385caAndy McFadden dexClass = ClassLoader.getSystemClassLoader(). 82a5a184892e60a89b564ca7c74e50b2ecb27d9f80Andy McFadden loadClass("dalvik.system.DexFile"); 8332fed2dee7399137908042a37aec28fbbda385caAndy McFadden Constructor ctor = dexClass. 8432fed2dee7399137908042a37aec28fbbda385caAndy McFadden getConstructor(new Class[] {String.class}); 8532fed2dee7399137908042a37aec28fbbda385caAndy McFadden dexFile = ctor.newInstance(DEX_FILE); 8632fed2dee7399137908042a37aec28fbbda385caAndy McFadden Method meth = dexClass.getMethod("loadClass", 87581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes new Class[] { String.class, ClassLoader.class }); 8832fed2dee7399137908042a37aec28fbbda385caAndy McFadden /* 8932fed2dee7399137908042a37aec28fbbda385caAndy McFadden * Invoking loadClass on CLASS_NAME is expected to 9032fed2dee7399137908042a37aec28fbbda385caAndy McFadden * throw an InvocationTargetException. Anything else 9132fed2dee7399137908042a37aec28fbbda385caAndy McFadden * is an error we can't recover from. 9232fed2dee7399137908042a37aec28fbbda385caAndy McFadden */ 9332fed2dee7399137908042a37aec28fbbda385caAndy McFadden meth.invoke(dexFile, name, this); 9432fed2dee7399137908042a37aec28fbbda385caAndy McFadden } finally { 9532fed2dee7399137908042a37aec28fbbda385caAndy McFadden if (dexFile != null) { 9632fed2dee7399137908042a37aec28fbbda385caAndy McFadden /* close the DexFile to make CloseGuard happy */ 9732fed2dee7399137908042a37aec28fbbda385caAndy McFadden Method meth = dexClass.getMethod("close", (Class[]) null); 9832fed2dee7399137908042a37aec28fbbda385caAndy McFadden meth.invoke(dexFile); 9932fed2dee7399137908042a37aec28fbbda385caAndy McFadden } 10032fed2dee7399137908042a37aec28fbbda385caAndy McFadden } 101581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes } catch (NoSuchMethodException nsme) { 102581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes throw new TestFailed(nsme); 103581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes } catch (InstantiationException ie) { 104581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes throw new TestFailed(ie); 105581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes } catch (IllegalAccessException iae) { 106581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes throw new TestFailed(iae); 107581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes } catch (ClassNotFoundException cnfe) { 108581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes throw new TestFailed(cnfe); 109581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes } 110581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes 111581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes return null; 112581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes } 113581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes 114581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes /** 115581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * Load a class. 116581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * 117581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * Return null if the class's name is SUPERCLASS_NAME; 118581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * otherwise invoke the super's loadClass method. 119581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes */ 120581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes public Class<?> loadClass(String name, boolean resolve) 121581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes throws ClassNotFoundException 122581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes { 123581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes if (SUPERCLASS_NAME.equals(name)) { 124581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes return null; 125581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes } 126581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes 127581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes return super.loadClass(name, resolve); 128581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes } 129581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes 130581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes /** 131581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * Attempt to find the class with the superclass we refuse to 132581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * load. This is expected to throw an 133581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * InvocationTargetException, with a NullPointerException as 134581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * its cause. 135581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes */ 136581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes public void findBrokenClass() 137581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes throws TestFailed, InvocationTargetException 138581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes { 139581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes findDexClass(CLASS_NAME); 140581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes } 141581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes } 142581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes 143581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes /** 144581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * Main entry point. 145581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes */ 146581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes public static void main(String[] args) 147581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes throws TestFailed, ClassNotFoundException { 148581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes /* 149581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * Run test. 150581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes */ 151581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes testFailLoadAndGc(); 152581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes } 153581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes 154581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes /** 155581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes * See if we can GC after a failed load. 156581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes */ 157581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes static void testFailLoadAndGc() throws TestFailed { 158581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes try { 159581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes BrokenDexLoader loader; 160581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes 161581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes loader = new BrokenDexLoader(ClassLoader.getSystemClassLoader()); 162581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes loader.findBrokenClass(); 163581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes System.err.println("ERROR: Inaccessible was accessible"); 164581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes } catch (InvocationTargetException ite) { 165581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes Throwable cause = ite.getCause(); 166581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes if (cause instanceof NullPointerException) { 167581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes System.err.println("Got expected ITE/NPE"); 168581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes } else { 169581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes System.err.println("Got unexpected ITE"); 170581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes ite.printStackTrace(); 171581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes } 172581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes } 173581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes System.gc(); 174581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes System.out.println("GC complete."); 175581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes } 176581fae8ab680b214c50d6dbb29dcf7bdb1b1e439Barry Hayes} 177