Main.java revision fbb80d7f726e551161fccbf0e347624459aefedf
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17import java.lang.reflect.Constructor; 18import java.lang.reflect.Method; 19import java.lang.reflect.InvocationTargetException; 20 21/** 22 * Class loader test. 23 */ 24public class Main { 25 26 /** 27 * A class loader which loads classes from the dex file 28 * "test.jar". However, it will return null when asked to load the 29 * class InaccessibleSuper. 30 * 31 * When testing code calls BrokenDexLoader's findBrokenClass(), 32 * a BrokenDexLoader will be the defining loader for the class 33 * Inaccessible. The VM will call the defining loader for 34 * "InaccessibleSuper", which will return null, which the VM 35 * should be able to deal with gracefully. 36 * 37 * Note that this depends heavily on the Dalvik test harness. 38 */ 39 static class BrokenDexLoader extends ClassLoader { 40 41 /** We return null when asked to load InaccessibleSuper. */ 42 private static class InaccessibleSuper {} 43 private static class Inaccessible extends InaccessibleSuper {} 44 45 private static final String SUPERCLASS_NAME = 46 "Main$BrokenDexLoader$InaccessibleSuper"; 47 private static final String CLASS_NAME = 48 "Main$BrokenDexLoader$Inaccessible"; 49 50 private static final String DEX_FILE = "test.jar"; 51 52 public BrokenDexLoader(ClassLoader parent) { 53 super(parent); 54 } 55 56 /** 57 * Finds the class with the specified binary name, from DEX_FILE. 58 * 59 * If we don't find a match, we throw an exception. 60 */ 61 private Class<?> findDexClass(String name) throws ClassNotFoundException 62 { 63 Class mDexClass; 64 Object mDexFile; 65 66 /* 67 * Find the DexFile class, and construct a DexFile object 68 * through reflection. 69 */ 70 71 mDexClass = ClassLoader.getSystemClassLoader(). 72 loadClass("dalvik/system/DexFile"); 73 74 Constructor ctor; 75 try { 76 ctor = mDexClass.getConstructor(new Class[] {String.class}); 77 } catch (NoSuchMethodException nsme) { 78 throw new ClassNotFoundException("getConstructor failed", 79 nsme); 80 } 81 82 try { 83 mDexFile = ctor.newInstance(DEX_FILE); 84 } catch (InstantiationException ie) { 85 throw new ClassNotFoundException("newInstance failed", ie); 86 } catch (IllegalAccessException iae) { 87 throw new ClassNotFoundException("newInstance failed", iae); 88 } catch (InvocationTargetException ite) { 89 throw new ClassNotFoundException("newInstance failed", ite); 90 } 91 92 /* 93 * Call DexFile.loadClass(String, ClassLoader). 94 */ 95 Method meth; 96 97 try { 98 meth = mDexClass.getMethod("loadClass", 99 new Class[] { String.class, ClassLoader.class }); 100 } catch (NoSuchMethodException nsme) { 101 throw new ClassNotFoundException("getMethod failed", nsme); 102 } 103 104 try { 105 meth.invoke(mDexFile, name, this); 106 } catch (IllegalAccessException iae) { 107 throw new ClassNotFoundException("loadClass failed", iae); 108 } catch (InvocationTargetException ite) { 109 throw new ClassNotFoundException("loadClass failed", 110 ite.getCause()); 111 } 112 113 return null; 114 } 115 116 /** 117 * Load a class. 118 * 119 * Return null if the class's name is SUPERCLASS_NAME; 120 * otherwise invoke the super's loadClass method. 121 */ 122 public Class<?> loadClass(String name, boolean resolve) 123 throws ClassNotFoundException 124 { 125 if (SUPERCLASS_NAME.equals(name)) { 126 return null; 127 } 128 129 return super.loadClass(name, resolve); 130 } 131 132 /** 133 * Attempt to find the class with the superclass we refuse to 134 * load. 135 */ 136 public void findBrokenClass() throws ClassNotFoundException 137 { 138 findDexClass(CLASS_NAME); 139 } 140 } 141 142 /** 143 * Main entry point. 144 */ 145 public static void main(String[] args) throws ClassNotFoundException { 146 /* 147 * Run tests. 148 */ 149 testAccess(); 150 } 151 152 /** 153 * See if we can load a class when the loader returns null for the 154 * superclass. 155 */ 156 static void testAccess() { 157 try { 158 BrokenDexLoader loader; 159 160 loader = new BrokenDexLoader(ClassLoader.getSystemClassLoader()); 161 loader.findBrokenClass(); 162 System.err.println("ERROR: Inaccessible was accessible"); 163 } catch (ClassNotFoundException cnfe) { 164 Throwable cause = cnfe.getCause(); 165 if (cause instanceof NullPointerException) { 166 System.out.println("Got expected CNFE/NPE"); 167 } else { 168 System.err.println("Got unexpected CNFE"); 169 cnfe.printStackTrace(); 170 } 171 } 172 } 173} 174