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 */ main(String[] args)24 public static void main(String[] args) throws Exception { 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 testSeparation(); 63 64 testClassForName(); 65 } 66 testSeparation()67 static void testSeparation() { 68 FancyLoader loader1 = new FancyLoader(ClassLoader.getSystemClassLoader()); 69 FancyLoader loader2 = new FancyLoader(ClassLoader.getSystemClassLoader()); 70 71 try { 72 Class target1 = loader1.loadClass("MutationTarget"); 73 Class target2 = loader2.loadClass("MutationTarget"); 74 75 if (target1 == target2) { 76 throw new RuntimeException("target1 should not be equal to target2"); 77 } 78 79 Class mutator1 = loader1.loadClass("Mutator"); 80 Class mutator2 = loader2.loadClass("Mutator"); 81 82 if (mutator1 == mutator2) { 83 throw new RuntimeException("mutator1 should not be equal to mutator2"); 84 } 85 86 runMutator(mutator1, 1); 87 88 int value = getMutationTargetValue(target1); 89 if (value != 1) { 90 throw new RuntimeException("target 1 has unexpected value " + value); 91 } 92 value = getMutationTargetValue(target2); 93 if (value != 0) { 94 throw new RuntimeException("target 2 has unexpected value " + value); 95 } 96 97 runMutator(mutator2, 2); 98 99 value = getMutationTargetValue(target1); 100 if (value != 1) { 101 throw new RuntimeException("target 1 has unexpected value " + value); 102 } 103 value = getMutationTargetValue(target2); 104 if (value != 2) { 105 throw new RuntimeException("target 2 has unexpected value " + value); 106 } 107 } catch (Exception ex) { 108 ex.printStackTrace(); 109 } 110 } 111 runMutator(Class c, int v)112 private static void runMutator(Class c, int v) throws Exception { 113 java.lang.reflect.Method m = c.getDeclaredMethod("mutate", int.class); 114 m.invoke(null, v); 115 } 116 getMutationTargetValue(Class c)117 private static int getMutationTargetValue(Class c) throws Exception { 118 java.lang.reflect.Field f = c.getDeclaredField("value"); 119 return f.getInt(null); 120 } 121 122 /** 123 * See if we can load a class that isn't public to us. We should be 124 * able to load it but not instantiate it. 125 */ testAccess1(ClassLoader loader)126 static void testAccess1(ClassLoader loader) { 127 Class altClass; 128 129 try { 130 altClass = loader.loadClass("Inaccessible1"); 131 } catch (ClassNotFoundException cnfe) { 132 System.err.println("loadClass failed"); 133 cnfe.printStackTrace(); 134 return; 135 } 136 137 /* instantiate */ 138 Object obj; 139 try { 140 obj = altClass.newInstance(); 141 System.err.println("ERROR: Inaccessible1 was accessible"); 142 } catch (InstantiationException ie) { 143 System.err.println("newInstance failed: " + ie); 144 return; 145 } catch (IllegalAccessException iae) { 146 System.out.println("Got expected access exception #1"); 147 //System.out.println("+++ " + iae); 148 return; 149 } 150 } 151 152 /** 153 * See if we can load a class whose base class is not accessible to it 154 * (though the base *is* accessible to us). 155 */ testAccess2(ClassLoader loader)156 static void testAccess2(ClassLoader loader) { 157 Class altClass; 158 159 try { 160 altClass = loader.loadClass("Inaccessible2"); 161 System.err.println("ERROR: Inaccessible2 was accessible: " + altClass); 162 } catch (ClassNotFoundException cnfe) { 163 Throwable cause = cnfe.getCause(); 164 if (cause instanceof IllegalAccessError) { 165 System.out.println("Got expected CNFE/IAE #2"); 166 } else { 167 System.err.println("Got unexpected CNFE/IAE #2"); 168 cnfe.printStackTrace(); 169 } 170 } 171 } 172 173 /** 174 * See if we can load a class with an inaccessible interface. 175 */ testAccess3(ClassLoader loader)176 static void testAccess3(ClassLoader loader) { 177 Class altClass; 178 179 try { 180 altClass = loader.loadClass("Inaccessible3"); 181 System.err.println("ERROR: Inaccessible3 was accessible: " + altClass); 182 } catch (ClassNotFoundException cnfe) { 183 Throwable cause = cnfe.getCause(); 184 if (cause instanceof IllegalAccessError) { 185 System.out.println("Got expected CNFE/IAE #3"); 186 } else { 187 System.err.println("Got unexpected CNFE/IAE #3"); 188 cnfe.printStackTrace(); 189 } 190 } 191 } 192 193 /** 194 * Test a doubled class that extends the base class. 195 */ testExtend(ClassLoader loader)196 static void testExtend(ClassLoader loader) { 197 Class doubledExtendClass; 198 Object obj; 199 200 /* get the "alternate" version of DoubledExtend */ 201 try { 202 doubledExtendClass = loader.loadClass("DoubledExtend"); 203 //System.out.println("+++ DoubledExtend is " + doubledExtendClass 204 // + " in " + doubledExtendClass.getClassLoader()); 205 } catch (ClassNotFoundException cnfe) { 206 System.err.println("loadClass failed: " + cnfe); 207 return; 208 } 209 210 /* instantiate */ 211 try { 212 obj = doubledExtendClass.newInstance(); 213 } catch (InstantiationException ie) { 214 System.err.println("newInstance failed: " + ie); 215 return; 216 } catch (IllegalAccessException iae) { 217 System.err.println("newInstance failed: " + iae); 218 return; 219 } catch (LinkageError le) { 220 System.out.println("Got expected LinkageError on DE"); 221 return; 222 } 223 224 /* use the base class reference to get a CL-specific instance */ 225 Base baseRef = (Base) obj; 226 DoubledExtend de = baseRef.getExtended(); 227 228 /* try to call through it */ 229 try { 230 String result; 231 232 result = Base.doStuff(de); 233 System.err.println("ERROR: did not get LinkageError on DE"); 234 System.err.println("(result=" + result + ")"); 235 } catch (LinkageError le) { 236 System.out.println("Got expected LinkageError on DE"); 237 return; 238 } 239 } 240 241 /** 242 * Test a doubled class that extends the base class, but is okay since 243 * it doesn't override the base class method. 244 */ testExtendOkay(ClassLoader loader)245 static void testExtendOkay(ClassLoader loader) { 246 Class doubledExtendOkayClass; 247 Object obj; 248 249 /* get the "alternate" version of DoubledExtendOkay */ 250 try { 251 doubledExtendOkayClass = loader.loadClass("DoubledExtendOkay"); 252 } catch (ClassNotFoundException cnfe) { 253 System.err.println("loadClass failed: " + cnfe); 254 return; 255 } 256 257 /* instantiate */ 258 try { 259 obj = doubledExtendOkayClass.newInstance(); 260 } catch (InstantiationException ie) { 261 System.err.println("newInstance failed: " + ie); 262 return; 263 } catch (IllegalAccessException iae) { 264 System.err.println("newInstance failed: " + iae); 265 return; 266 } catch (LinkageError le) { 267 System.err.println("Got unexpected LinkageError on DEO"); 268 le.printStackTrace(); 269 return; 270 } 271 272 /* use the base class reference to get a CL-specific instance */ 273 BaseOkay baseRef = (BaseOkay) obj; 274 DoubledExtendOkay de = baseRef.getExtended(); 275 276 /* try to call through it */ 277 try { 278 String result; 279 280 result = BaseOkay.doStuff(de); 281 System.out.println("Got DEO result " + result); 282 } catch (LinkageError le) { 283 System.err.println("Got unexpected LinkageError on DEO"); 284 le.printStackTrace(); 285 return; 286 } 287 } 288 289 /** 290 * Try to access a doubled class through a class that implements 291 * an interface declared in a different class. 292 */ testInterface(ClassLoader loader)293 static void testInterface(ClassLoader loader) { 294 Class getDoubledClass; 295 Object obj; 296 297 /* get GetDoubled from the "alternate" class loader */ 298 try { 299 getDoubledClass = loader.loadClass("GetDoubled"); 300 } catch (ClassNotFoundException cnfe) { 301 System.err.println("loadClass failed: " + cnfe); 302 return; 303 } 304 305 /* instantiate */ 306 try { 307 obj = getDoubledClass.newInstance(); 308 } catch (InstantiationException ie) { 309 System.err.println("newInstance failed: " + ie); 310 return; 311 } catch (IllegalAccessException iae) { 312 System.err.println("newInstance failed: " + iae); 313 return; 314 } catch (LinkageError le) { 315 // Dalvik bails here 316 System.out.println("Got LinkageError on GD"); 317 return; 318 } 319 320 /* 321 * Cast the object to the interface, and try to use it. 322 */ 323 IGetDoubled iface = (IGetDoubled) obj; 324 try { 325 /* "de" will be the wrong variety of DoubledExtendOkay */ 326 DoubledExtendOkay de = iface.getDoubled(); 327 // reference impl bails here 328 String str = de.getStr(); 329 } catch (LinkageError le) { 330 System.out.println("Got LinkageError on GD"); 331 return; 332 } 333 System.err.println("Should have failed by now on GetDoubled"); 334 } 335 336 /** 337 * Throw an abstract class into the middle and see what happens. 338 */ testAbstract(ClassLoader loader)339 static void testAbstract(ClassLoader loader) { 340 Class abstractGetClass; 341 Object obj; 342 343 /* get AbstractGet from the "alternate" loader */ 344 try { 345 abstractGetClass = loader.loadClass("AbstractGet"); 346 } catch (ClassNotFoundException cnfe) { 347 System.err.println("loadClass ta failed: " + cnfe); 348 return; 349 } 350 351 /* instantiate */ 352 try { 353 obj = abstractGetClass.newInstance(); 354 } catch (InstantiationException ie) { 355 System.err.println("newInstance failed: " + ie); 356 return; 357 } catch (IllegalAccessException iae) { 358 System.err.println("newInstance failed: " + iae); 359 return; 360 } catch (LinkageError le) { 361 System.out.println("Got LinkageError on TA"); 362 return; 363 } 364 365 /* use the base class reference to get a CL-specific instance */ 366 BaseOkay baseRef = (BaseOkay) obj; 367 DoubledExtendOkay de = baseRef.getExtended(); 368 369 /* try to call through it */ 370 try { 371 String result; 372 373 result = BaseOkay.doStuff(de); 374 } catch (LinkageError le) { 375 System.out.println("Got LinkageError on TA"); 376 return; 377 } 378 System.err.println("Should have failed by now in testAbstract"); 379 } 380 381 /** 382 * Test a doubled class that implements a common interface. 383 */ testImplement(ClassLoader loader)384 static void testImplement(ClassLoader loader) { 385 Class doubledImplementClass; 386 Object obj; 387 388 useImplement(new DoubledImplement(), true); 389 390 /* get the "alternate" version of DoubledImplement */ 391 try { 392 doubledImplementClass = loader.loadClass("DoubledImplement"); 393 } catch (ClassNotFoundException cnfe) { 394 System.err.println("loadClass failed: " + cnfe); 395 return; 396 } 397 398 /* instantiate */ 399 try { 400 obj = doubledImplementClass.newInstance(); 401 } catch (InstantiationException ie) { 402 System.err.println("newInstance failed: " + ie); 403 return; 404 } catch (IllegalAccessException iae) { 405 System.err.println("newInstance failed: " + iae); 406 return; 407 } catch (LinkageError le) { 408 System.out.println("Got LinkageError on DI (early)"); 409 return; 410 } 411 412 /* if we lived this long, try to do something with it */ 413 ICommon icommon = (ICommon) obj; 414 useImplement(icommon.getDoubledInstance(), false); 415 } 416 417 /** 418 * Do something with a DoubledImplement instance. 419 */ useImplement(DoubledImplement di, boolean isOne)420 static void useImplement(DoubledImplement di, boolean isOne) { 421 //System.out.println("useObject: " + di.toString() + " -- " 422 // + di.getClass().getClassLoader()); 423 try { 424 di.one(); 425 if (!isOne) { 426 System.err.println("ERROR: did not get LinkageError on DI"); 427 } 428 } catch (LinkageError le) { 429 if (!isOne) { 430 System.out.println("Got LinkageError on DI (late)"); 431 } else { 432 throw le; 433 } 434 } 435 } 436 437 438 /** 439 * Test a class that implements an interface with a super-interface 440 * that refers to a doubled class. 441 */ testIfaceImplement(ClassLoader loader)442 static void testIfaceImplement(ClassLoader loader) { 443 Class ifaceImplClass; 444 Object obj; 445 446 /* 447 * Create an instance of IfaceImpl. We also pull in 448 * DoubledImplement2 from the other class loader; without this 449 * we don't fail in some implementations. 450 */ 451 try { 452 ifaceImplClass = loader.loadClass("IfaceImpl"); 453 ifaceImplClass = loader.loadClass("DoubledImplement2"); 454 } catch (ClassNotFoundException cnfe) { 455 System.err.println("loadClass failed: " + cnfe); 456 return; 457 } 458 459 /* instantiate */ 460 try { 461 obj = ifaceImplClass.newInstance(); 462 } catch (InstantiationException ie) { 463 System.err.println("newInstance failed: " + ie); 464 return; 465 } catch (IllegalAccessException iae) { 466 System.err.println("newInstance failed: " + iae); 467 return; 468 } catch (LinkageError le) { 469 System.out.println("Got LinkageError on IDI (early)"); 470 //System.out.println(le); 471 return; 472 } 473 474 /* 475 * Without the pre-load of FancyLoader->DoubledImplement2, some 476 * implementations will happily execute through this part. "obj" 477 * comes from FancyLoader, but the di2 returned from ifaceSuper 478 * comes from the application class loader. 479 */ 480 IfaceSuper ifaceSuper = (IfaceSuper) obj; 481 DoubledImplement2 di2 = ifaceSuper.getDoubledInstance2(); 482 di2.one(); 483 } 484 testClassForName()485 static void testClassForName() throws Exception { 486 System.out.println(Class.forName("Main").toString()); 487 try { 488 System.out.println(Class.forName("Main", false, null).toString()); 489 } catch (ClassNotFoundException expected) { 490 System.out.println("Got expected ClassNotFoundException"); 491 } 492 } 493 } 494