1 /* 2 * Copyright (C) 2008 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 17 /** 18 * Class loader test. 19 */ 20 public class Main { 21 /** 22 * Main entry point. 23 */ 24 public static void main(String[] args) { 25 FancyLoader loader; 26 27 loader = new FancyLoader(ClassLoader.getSystemClassLoader()); 28 //System.out.println("SYSTEM: " + ClassLoader.getSystemClassLoader()); 29 //System.out.println("ALTERN: " + loader); 30 31 /* 32 * This statement has no effect on this program, but it can 33 * change the point where a LinkageException is thrown in 34 * testImplement(). When this is present the "reference 35 * implementation" throws an exception from Class.newInstance(), 36 * when it's absent the exception is deferred until the first time 37 * we call a method that isn't actually implemented. 38 * 39 * This isn't the class that fails -- it's a class with the same 40 * name in the "fancy" class loader -- but the VM thinks it has a 41 * reference to one of these; presumably the difference is that 42 * without this the VM finds itself holding a reference to an 43 * instance of an uninitialized class. 44 */ 45 System.out.println("base: " + DoubledImplement.class); 46 System.out.println("base2: " + DoubledImplement2.class); 47 48 /* 49 * Run tests. 50 */ 51 testAccess1(loader); 52 testAccess2(loader); 53 testAccess3(loader); 54 55 testExtend(loader); 56 testExtendOkay(loader); 57 testInterface(loader); 58 testAbstract(loader); 59 testImplement(loader); 60 testIfaceImplement(loader); 61 } 62 63 /** 64 * See if we can load a class that isn't public to us. We should be 65 * able to load it but not instantiate it. 66 */ 67 static void testAccess1(ClassLoader loader) { 68 Class altClass; 69 70 try { 71 altClass = loader.loadClass("Inaccessible1"); 72 } catch (ClassNotFoundException cnfe) { 73 System.err.println("loadClass failed"); 74 cnfe.printStackTrace(); 75 return; 76 } 77 78 /* instantiate */ 79 Object obj; 80 try { 81 obj = altClass.newInstance(); 82 System.err.println("ERROR: Inaccessible1 was accessible"); 83 } catch (InstantiationException ie) { 84 System.err.println("newInstance failed: " + ie); 85 return; 86 } catch (IllegalAccessException iae) { 87 System.out.println("Got expected access exception #1"); 88 //System.out.println("+++ " + iae); 89 return; 90 } 91 } 92 93 /** 94 * See if we can load a class whose base class is not accessible to it 95 * (though the base *is* accessible to us). 96 */ 97 static void testAccess2(ClassLoader loader) { 98 Class altClass; 99 100 try { 101 altClass = loader.loadClass("Inaccessible2"); 102 System.err.println("ERROR: Inaccessible2 was accessible"); 103 } catch (ClassNotFoundException cnfe) { 104 Throwable cause = cnfe.getCause(); 105 if (cause instanceof IllegalAccessError) { 106 System.out.println("Got expected CNFE/IAE #2"); 107 } else { 108 System.err.println("Got unexpected CNFE/IAE #2"); 109 cnfe.printStackTrace(); 110 } 111 } 112 } 113 114 /** 115 * See if we can load a class with an inaccessible interface. 116 */ 117 static void testAccess3(ClassLoader loader) { 118 Class altClass; 119 120 try { 121 altClass = loader.loadClass("Inaccessible3"); 122 System.err.println("ERROR: Inaccessible3 was accessible"); 123 } catch (ClassNotFoundException cnfe) { 124 Throwable cause = cnfe.getCause(); 125 if (cause instanceof IllegalAccessError) { 126 System.out.println("Got expected CNFE/IAE #3"); 127 } else { 128 System.err.println("Got unexpected CNFE/IAE #3"); 129 cnfe.printStackTrace(); 130 } 131 } 132 } 133 134 /** 135 * Test a doubled class that extends the base class. 136 */ 137 static void testExtend(ClassLoader loader) { 138 Class doubledExtendClass; 139 Object obj; 140 141 /* get the "alternate" version of DoubledExtend */ 142 try { 143 doubledExtendClass = loader.loadClass("DoubledExtend"); 144 //System.out.println("+++ DoubledExtend is " + doubledExtendClass 145 // + " in " + doubledExtendClass.getClassLoader()); 146 } catch (ClassNotFoundException cnfe) { 147 System.err.println("loadClass failed: " + cnfe); 148 return; 149 } 150 151 /* instantiate */ 152 try { 153 obj = doubledExtendClass.newInstance(); 154 } catch (InstantiationException ie) { 155 System.err.println("newInstance failed: " + ie); 156 return; 157 } catch (IllegalAccessException iae) { 158 System.err.println("newInstance failed: " + iae); 159 return; 160 } catch (LinkageError le) { 161 System.out.println("Got expected LinkageError on DE"); 162 return; 163 } 164 165 /* use the base class reference to get a CL-specific instance */ 166 Base baseRef = (Base) obj; 167 DoubledExtend de = baseRef.getExtended(); 168 169 /* try to call through it */ 170 try { 171 String result; 172 173 result = Base.doStuff(de); 174 System.err.println("ERROR: did not get LinkageError on DE"); 175 System.err.println("(result=" + result + ")"); 176 } catch (LinkageError le) { 177 System.out.println("Got expected LinkageError on DE"); 178 return; 179 } 180 } 181 182 /** 183 * Test a doubled class that extends the base class, but is okay since 184 * it doesn't override the base class method. 185 */ 186 static void testExtendOkay(ClassLoader loader) { 187 Class doubledExtendOkayClass; 188 Object obj; 189 190 /* get the "alternate" version of DoubledExtendOkay */ 191 try { 192 doubledExtendOkayClass = loader.loadClass("DoubledExtendOkay"); 193 } catch (ClassNotFoundException cnfe) { 194 System.err.println("loadClass failed: " + cnfe); 195 return; 196 } 197 198 /* instantiate */ 199 try { 200 obj = doubledExtendOkayClass.newInstance(); 201 } catch (InstantiationException ie) { 202 System.err.println("newInstance failed: " + ie); 203 return; 204 } catch (IllegalAccessException iae) { 205 System.err.println("newInstance failed: " + iae); 206 return; 207 } catch (LinkageError le) { 208 System.err.println("Got unexpected LinkageError on DEO"); 209 le.printStackTrace(); 210 return; 211 } 212 213 /* use the base class reference to get a CL-specific instance */ 214 BaseOkay baseRef = (BaseOkay) obj; 215 DoubledExtendOkay de = baseRef.getExtended(); 216 217 /* try to call through it */ 218 try { 219 String result; 220 221 result = BaseOkay.doStuff(de); 222 System.out.println("Got DEO result " + result); 223 } catch (LinkageError le) { 224 System.err.println("Got unexpected LinkageError on DEO"); 225 le.printStackTrace(); 226 return; 227 } 228 } 229 230 /** 231 * Try to access a doubled class through a class that implements 232 * an interface declared in a different class. 233 */ 234 static void testInterface(ClassLoader loader) { 235 Class getDoubledClass; 236 Object obj; 237 238 /* get GetDoubled from the "alternate" class loader */ 239 try { 240 getDoubledClass = loader.loadClass("GetDoubled"); 241 } catch (ClassNotFoundException cnfe) { 242 System.err.println("loadClass failed: " + cnfe); 243 return; 244 } 245 246 /* instantiate */ 247 try { 248 obj = getDoubledClass.newInstance(); 249 } catch (InstantiationException ie) { 250 System.err.println("newInstance failed: " + ie); 251 return; 252 } catch (IllegalAccessException iae) { 253 System.err.println("newInstance failed: " + iae); 254 return; 255 } catch (LinkageError le) { 256 // Dalvik bails here 257 System.out.println("Got LinkageError on GD"); 258 return; 259 } 260 261 /* 262 * Cast the object to the interface, and try to use it. 263 */ 264 IGetDoubled iface = (IGetDoubled) obj; 265 try { 266 /* "de" will be the wrong variety of DoubledExtendOkay */ 267 DoubledExtendOkay de = iface.getDoubled(); 268 // reference impl bails here 269 String str = de.getStr(); 270 } catch (LinkageError le) { 271 System.out.println("Got LinkageError on GD"); 272 return; 273 } 274 System.err.println("Should have failed by now on GetDoubled"); 275 } 276 277 /** 278 * Throw an abstract class into the middle and see what happens. 279 */ 280 static void testAbstract(ClassLoader loader) { 281 Class abstractGetClass; 282 Object obj; 283 284 /* get AbstractGet from the "alternate" loader */ 285 try { 286 abstractGetClass = loader.loadClass("AbstractGet"); 287 } catch (ClassNotFoundException cnfe) { 288 System.err.println("loadClass ta failed: " + cnfe); 289 return; 290 } 291 292 /* instantiate */ 293 try { 294 obj = abstractGetClass.newInstance(); 295 } catch (InstantiationException ie) { 296 System.err.println("newInstance failed: " + ie); 297 return; 298 } catch (IllegalAccessException iae) { 299 System.err.println("newInstance failed: " + iae); 300 return; 301 } catch (LinkageError le) { 302 System.out.println("Got LinkageError on TA"); 303 return; 304 } 305 306 /* use the base class reference to get a CL-specific instance */ 307 BaseOkay baseRef = (BaseOkay) obj; 308 DoubledExtendOkay de = baseRef.getExtended(); 309 310 /* try to call through it */ 311 try { 312 String result; 313 314 result = BaseOkay.doStuff(de); 315 } catch (LinkageError le) { 316 System.out.println("Got LinkageError on TA"); 317 return; 318 } 319 System.err.println("Should have failed by now in testAbstract"); 320 } 321 322 /** 323 * Test a doubled class that implements a common interface. 324 */ 325 static void testImplement(ClassLoader loader) { 326 Class doubledImplementClass; 327 Object obj; 328 329 useImplement(new DoubledImplement(), true); 330 331 /* get the "alternate" version of DoubledImplement */ 332 try { 333 doubledImplementClass = loader.loadClass("DoubledImplement"); 334 } catch (ClassNotFoundException cnfe) { 335 System.err.println("loadClass failed: " + cnfe); 336 return; 337 } 338 339 /* instantiate */ 340 try { 341 obj = doubledImplementClass.newInstance(); 342 } catch (InstantiationException ie) { 343 System.err.println("newInstance failed: " + ie); 344 return; 345 } catch (IllegalAccessException iae) { 346 System.err.println("newInstance failed: " + iae); 347 return; 348 } catch (LinkageError le) { 349 System.out.println("Got LinkageError on DI (early)"); 350 return; 351 } 352 353 /* if we lived this long, try to do something with it */ 354 ICommon icommon = (ICommon) obj; 355 useImplement(icommon.getDoubledInstance(), false); 356 } 357 358 /** 359 * Do something with a DoubledImplement instance. 360 */ 361 static void useImplement(DoubledImplement di, boolean isOne) { 362 //System.out.println("useObject: " + di.toString() + " -- " 363 // + di.getClass().getClassLoader()); 364 try { 365 di.one(); 366 if (!isOne) { 367 System.err.println("ERROR: did not get LinkageError on DI"); 368 } 369 } catch (LinkageError le) { 370 if (!isOne) { 371 System.out.println("Got LinkageError on DI (late)"); 372 } else { 373 throw le; 374 } 375 } 376 } 377 378 379 /** 380 * Test a class that implements an interface with a super-interface 381 * that refers to a doubled class. 382 */ 383 static void testIfaceImplement(ClassLoader loader) { 384 Class ifaceImplClass; 385 Object obj; 386 387 /* 388 * Create an instance of IfaceImpl. We also pull in 389 * DoubledImplement2 from the other class loader; without this 390 * we don't fail in some implementations. 391 */ 392 try { 393 ifaceImplClass = loader.loadClass("IfaceImpl"); 394 ifaceImplClass = loader.loadClass("DoubledImplement2"); 395 } catch (ClassNotFoundException cnfe) { 396 System.err.println("loadClass failed: " + cnfe); 397 return; 398 } 399 400 /* instantiate */ 401 try { 402 obj = ifaceImplClass.newInstance(); 403 } catch (InstantiationException ie) { 404 System.err.println("newInstance failed: " + ie); 405 return; 406 } catch (IllegalAccessException iae) { 407 System.err.println("newInstance failed: " + iae); 408 return; 409 } catch (LinkageError le) { 410 System.out.println("Got LinkageError on IDI (early)"); 411 //System.out.println(le); 412 return; 413 } 414 415 /* 416 * Without the pre-load of FancyLoader->DoubledImplement2, some 417 * implementations will happily execute through this part. "obj" 418 * comes from FancyLoader, but the di2 returned from ifaceSuper 419 * comes from the application class loader. 420 */ 421 IfaceSuper ifaceSuper = (IfaceSuper) obj; 422 DoubledImplement2 di2 = ifaceSuper.getDoubledInstance2(); 423 di2.one(); 424 } 425 } 426