1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 /* 18 * Copyright (C) 2008 The Android Open Source Project 19 * 20 * Licensed under the Apache License, Version 2.0 (the "License"); 21 * you may not use this file except in compliance with the License. 22 * You may obtain a copy of the License at 23 * 24 * http://www.apache.org/licenses/LICENSE-2.0 25 * 26 * Unless required by applicable law or agreed to in writing, software 27 * distributed under the License is distributed on an "AS IS" BASIS, 28 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 29 * See the License for the specific language governing permissions and 30 * limitations under the License. 31 */ 32 33 package java.lang; 34 35 import dalvik.system.PathClassLoader; 36 import java.io.IOException; 37 import java.io.InputStream; 38 import java.net.URL; 39 import java.nio.ByteBuffer; 40 import java.security.ProtectionDomain; 41 import java.util.Collection; 42 import java.util.Collections; 43 import java.util.Enumeration; 44 import java.util.HashMap; 45 import java.util.List; 46 import java.util.Map; 47 48 /** 49 * Loads classes and resources from a repository. One or more class loaders are 50 * installed at runtime. These are consulted whenever the runtime system needs a 51 * specific class that is not yet available in-memory. Typically, class loaders 52 * are grouped into a tree where child class loaders delegate all requests to 53 * parent class loaders. Only if the parent class loader cannot satisfy the 54 * request, the child class loader itself tries to handle it. 55 * <p> 56 * {@code ClassLoader} is an abstract class that implements the common 57 * infrastructure required by all class loaders. Android provides several 58 * concrete implementations of the class, with 59 * {@link dalvik.system.PathClassLoader} being the one typically used. Other 60 * applications may implement subclasses of {@code ClassLoader} to provide 61 * special ways for loading classes. 62 * </p> 63 * @see Class 64 */ 65 public abstract class ClassLoader { 66 67 /** 68 * The 'System' ClassLoader - the one that is responsible for loading 69 * classes from the classpath. It is not equal to the bootstrap class loader - 70 * that one handles the built-in classes. 71 * 72 * Because of a potential class initialization race between ClassLoader and 73 * java.lang.System, reproducible when using JDWP with "suspend=y", we defer 74 * creation of the system class loader until first use. We use a static 75 * inner class to get synchronization at init time without having to sync on 76 * every access. 77 * 78 * @see #getSystemClassLoader() 79 */ 80 static private class SystemClassLoader { 81 public static ClassLoader loader = ClassLoader.createSystemClassLoader(); 82 } 83 84 /** 85 * The parent ClassLoader. 86 */ 87 private ClassLoader parent; 88 89 /** 90 * The packages known to the class loader. 91 */ 92 private Map<String, Package> packages = new HashMap<String, Package>(); 93 94 /** 95 * To avoid unloading individual classes, {@link java.lang.reflect.Proxy} 96 * only generates one class for each set of interfaces. This maps sets of 97 * interfaces to the proxy class that implements all of them. It is declared 98 * here so that these generated classes can be unloaded with their class 99 * loader. 100 * 101 * @hide 102 */ 103 public final Map<List<Class<?>>, Class<?>> proxyCache = 104 new HashMap<List<Class<?>>, Class<?>>(); 105 106 /** 107 * Create the system class loader. Note this is NOT the bootstrap class 108 * loader (which is managed by the VM). We use a null value for the parent 109 * to indicate that the bootstrap loader is our parent. 110 */ createSystemClassLoader()111 private static ClassLoader createSystemClassLoader() { 112 String classPath = System.getProperty("java.class.path", "."); 113 114 // String[] paths = classPath.split(":"); 115 // URL[] urls = new URL[paths.length]; 116 // for (int i = 0; i < paths.length; i++) { 117 // try { 118 // urls[i] = new URL("file://" + paths[i]); 119 // } 120 // catch (Exception ex) { 121 // ex.printStackTrace(); 122 // } 123 // } 124 // 125 // return new java.net.URLClassLoader(urls, null); 126 127 // TODO Make this a java.net.URLClassLoader once we have those? 128 return new PathClassLoader(classPath, BootClassLoader.getInstance()); 129 } 130 131 /** 132 * Returns the system class loader. This is the parent for new 133 * {@code ClassLoader} instances and is typically the class loader used to 134 * start the application. 135 */ getSystemClassLoader()136 public static ClassLoader getSystemClassLoader() { 137 return SystemClassLoader.loader; 138 } 139 140 /** 141 * Finds the URL of the resource with the specified name. The system class 142 * loader's resource lookup algorithm is used to find the resource. 143 * 144 * @return the {@code URL} object for the requested resource or {@code null} 145 * if the resource can not be found. 146 * @param resName 147 * the name of the resource to find. 148 * @see Class#getResource 149 */ getSystemResource(String resName)150 public static URL getSystemResource(String resName) { 151 return SystemClassLoader.loader.getResource(resName); 152 } 153 154 /** 155 * Returns an enumeration of URLs for the resource with the specified name. 156 * The system class loader's resource lookup algorithm is used to find the 157 * resource. 158 * 159 * @return an enumeration of {@code URL} objects containing the requested 160 * resources. 161 * @param resName 162 * the name of the resource to find. 163 * @throws IOException 164 * if an I/O error occurs. 165 */ getSystemResources(String resName)166 public static Enumeration<URL> getSystemResources(String resName) throws IOException { 167 return SystemClassLoader.loader.getResources(resName); 168 } 169 170 /** 171 * Returns a stream for the resource with the specified name. The system 172 * class loader's resource lookup algorithm is used to find the resource. 173 * Basically, the contents of the java.class.path are searched in order, 174 * looking for a path which matches the specified resource. 175 * 176 * @return a stream for the resource or {@code null}. 177 * @param resName 178 * the name of the resource to find. 179 * @see Class#getResourceAsStream 180 */ getSystemResourceAsStream(String resName)181 public static InputStream getSystemResourceAsStream(String resName) { 182 return SystemClassLoader.loader.getResourceAsStream(resName); 183 } 184 185 /** 186 * Constructs a new instance of this class with the system class loader as 187 * its parent. 188 */ ClassLoader()189 protected ClassLoader() { 190 this(getSystemClassLoader(), false); 191 } 192 193 /** 194 * Constructs a new instance of this class with the specified class loader 195 * as its parent. 196 * 197 * @param parentLoader 198 * The {@code ClassLoader} to use as the new class loader's 199 * parent. 200 */ ClassLoader(ClassLoader parentLoader)201 protected ClassLoader(ClassLoader parentLoader) { 202 this(parentLoader, false); 203 } 204 205 /* 206 * constructor for the BootClassLoader which needs parent to be null. 207 */ ClassLoader(ClassLoader parentLoader, boolean nullAllowed)208 ClassLoader(ClassLoader parentLoader, boolean nullAllowed) { 209 if (parentLoader == null && !nullAllowed) { 210 throw new NullPointerException("parentLoader == null && !nullAllowed"); 211 } 212 parent = parentLoader; 213 } 214 215 /** 216 * Constructs a new class from an array of bytes containing a class 217 * definition in class file format. 218 * 219 * @param classRep 220 * the memory image of a class file. 221 * @param offset 222 * the offset into {@code classRep}. 223 * @param length 224 * the length of the class file. 225 * @return the {@code Class} object created from the specified subset of 226 * data in {@code classRep}. 227 * @throws ClassFormatError 228 * if {@code classRep} does not contain a valid class. 229 * @throws IndexOutOfBoundsException 230 * if {@code offset < 0}, {@code length < 0} or if 231 * {@code offset + length} is greater than the length of 232 * {@code classRep}. 233 * @deprecated Use {@link #defineClass(String, byte[], int, int)} 234 */ 235 @Deprecated defineClass(byte[] classRep, int offset, int length)236 protected final Class<?> defineClass(byte[] classRep, int offset, int length) 237 throws ClassFormatError { 238 throw new UnsupportedOperationException("can't load this type of class file"); 239 } 240 241 /** 242 * Constructs a new class from an array of bytes containing a class 243 * definition in class file format. 244 * 245 * @param className 246 * the expected name of the new class, may be {@code null} if not 247 * known. 248 * @param classRep 249 * the memory image of a class file. 250 * @param offset 251 * the offset into {@code classRep}. 252 * @param length 253 * the length of the class file. 254 * @return the {@code Class} object created from the specified subset of 255 * data in {@code classRep}. 256 * @throws ClassFormatError 257 * if {@code classRep} does not contain a valid class. 258 * @throws IndexOutOfBoundsException 259 * if {@code offset < 0}, {@code length < 0} or if 260 * {@code offset + length} is greater than the length of 261 * {@code classRep}. 262 */ defineClass(String className, byte[] classRep, int offset, int length)263 protected final Class<?> defineClass(String className, byte[] classRep, int offset, int length) 264 throws ClassFormatError { 265 throw new UnsupportedOperationException("can't load this type of class file"); 266 } 267 268 /** 269 * Constructs a new class from an array of bytes containing a class 270 * definition in class file format and assigns the specified protection 271 * domain to the new class. If the provided protection domain is 272 * {@code null} then a default protection domain is assigned to the class. 273 * 274 * @param className 275 * the expected name of the new class, may be {@code null} if not 276 * known. 277 * @param classRep 278 * the memory image of a class file. 279 * @param offset 280 * the offset into {@code classRep}. 281 * @param length 282 * the length of the class file. 283 * @param protectionDomain 284 * the protection domain to assign to the loaded class, may be 285 * {@code null}. 286 * @return the {@code Class} object created from the specified subset of 287 * data in {@code classRep}. 288 * @throws ClassFormatError 289 * if {@code classRep} does not contain a valid class. 290 * @throws IndexOutOfBoundsException 291 * if {@code offset < 0}, {@code length < 0} or if 292 * {@code offset + length} is greater than the length of 293 * {@code classRep}. 294 * @throws NoClassDefFoundError 295 * if {@code className} is not equal to the name of the class 296 * contained in {@code classRep}. 297 */ defineClass(String className, byte[] classRep, int offset, int length, ProtectionDomain protectionDomain)298 protected final Class<?> defineClass(String className, byte[] classRep, int offset, int length, 299 ProtectionDomain protectionDomain) throws java.lang.ClassFormatError { 300 throw new UnsupportedOperationException("can't load this type of class file"); 301 } 302 303 /** 304 * Defines a new class with the specified name, byte code from the byte 305 * buffer and the optional protection domain. If the provided protection 306 * domain is {@code null} then a default protection domain is assigned to 307 * the class. 308 * 309 * @param name 310 * the expected name of the new class, may be {@code null} if not 311 * known. 312 * @param b 313 * the byte buffer containing the byte code of the new class. 314 * @param protectionDomain 315 * the protection domain to assign to the loaded class, may be 316 * {@code null}. 317 * @return the {@code Class} object created from the data in {@code b}. 318 * @throws ClassFormatError 319 * if {@code b} does not contain a valid class. 320 * @throws NoClassDefFoundError 321 * if {@code className} is not equal to the name of the class 322 * contained in {@code b}. 323 */ defineClass(String name, ByteBuffer b, ProtectionDomain protectionDomain)324 protected final Class<?> defineClass(String name, ByteBuffer b, 325 ProtectionDomain protectionDomain) throws ClassFormatError { 326 327 byte[] temp = new byte[b.remaining()]; 328 b.get(temp); 329 return defineClass(name, temp, 0, temp.length, protectionDomain); 330 } 331 332 /** 333 * Overridden by subclasses, throws a {@code ClassNotFoundException} by 334 * default. This method is called by {@code loadClass} after the parent 335 * {@code ClassLoader} has failed to find a loaded class of the same name. 336 * 337 * @param className 338 * the name of the class to look for. 339 * @return the {@code Class} object that is found. 340 * @throws ClassNotFoundException 341 * if the class cannot be found. 342 */ findClass(String className)343 protected Class<?> findClass(String className) throws ClassNotFoundException { 344 throw new ClassNotFoundException(className); 345 } 346 347 /** 348 * Returns the class with the specified name if it has already been loaded 349 * by the VM or {@code null} if it has not yet been loaded. 350 * 351 * @param className 352 * the name of the class to look for. 353 * @return the {@code Class} object or {@code null} if the requested class 354 * has not been loaded. 355 */ findLoadedClass(String className)356 protected final Class<?> findLoadedClass(String className) { 357 ClassLoader loader; 358 if (this == BootClassLoader.getInstance()) 359 loader = null; 360 else 361 loader = this; 362 return VMClassLoader.findLoadedClass(loader, className); 363 } 364 365 /** 366 * Finds the class with the specified name, loading it using the system 367 * class loader if necessary. 368 * 369 * @param className 370 * the name of the class to look for. 371 * @return the {@code Class} object with the requested {@code className}. 372 * @throws ClassNotFoundException 373 * if the class can not be found. 374 */ findSystemClass(String className)375 protected final Class<?> findSystemClass(String className) throws ClassNotFoundException { 376 return Class.forName(className, false, getSystemClassLoader()); 377 } 378 379 /** 380 * Returns this class loader's parent. 381 * 382 * @return this class loader's parent or {@code null}. 383 */ getParent()384 public final ClassLoader getParent() { 385 return parent; 386 } 387 388 /** 389 * Returns the URL of the resource with the specified name. This 390 * implementation first tries to use the parent class loader to find the 391 * resource; if this fails then {@link #findResource(String)} is called to 392 * find the requested resource. 393 * 394 * @param resName 395 * the name of the resource to find. 396 * @return the {@code URL} object for the requested resource or {@code null} 397 * if the resource can not be found 398 * @see Class#getResource 399 */ getResource(String resName)400 public URL getResource(String resName) { 401 URL resource = parent.getResource(resName); 402 if (resource == null) { 403 resource = findResource(resName); 404 } 405 return resource; 406 } 407 408 /** 409 * Returns an enumeration of URLs for the resource with the specified name. 410 * This implementation first uses this class loader's parent to find the 411 * resource, then it calls {@link #findResources(String)} to get additional 412 * URLs. The returned enumeration contains the {@code URL} objects of both 413 * find operations. 414 * 415 * @return an enumeration of {@code URL} objects for the requested resource. 416 * @param resName 417 * the name of the resource to find. 418 * @throws IOException 419 * if an I/O error occurs. 420 */ 421 @SuppressWarnings("unchecked") getResources(String resName)422 public Enumeration<URL> getResources(String resName) throws IOException { 423 424 Enumeration<URL> first = parent.getResources(resName); 425 Enumeration<URL> second = findResources(resName); 426 427 return new TwoEnumerationsInOne(first, second); 428 } 429 430 /** 431 * Returns a stream for the resource with the specified name. See 432 * {@link #getResource(String)} for a description of the lookup algorithm 433 * used to find the resource. 434 * 435 * @return a stream for the resource or {@code null} if the resource can not be found 436 * @param resName 437 * the name of the resource to find. 438 * @see Class#getResourceAsStream 439 */ getResourceAsStream(String resName)440 public InputStream getResourceAsStream(String resName) { 441 try { 442 URL url = getResource(resName); 443 if (url != null) { 444 return url.openStream(); 445 } 446 } catch (IOException ex) { 447 // Don't want to see the exception. 448 } 449 450 return null; 451 } 452 453 /** 454 * Loads the class with the specified name. Invoking this method is 455 * equivalent to calling {@code loadClass(className, false)}. 456 * <p> 457 * <strong>Note:</strong> In the Android reference implementation, the 458 * second parameter of {@link #loadClass(String, boolean)} is ignored 459 * anyway. 460 * </p> 461 * 462 * @return the {@code Class} object. 463 * @param className 464 * the name of the class to look for. 465 * @throws ClassNotFoundException 466 * if the class can not be found. 467 */ loadClass(String className)468 public Class<?> loadClass(String className) throws ClassNotFoundException { 469 return loadClass(className, false); 470 } 471 472 /** 473 * Loads the class with the specified name, optionally linking it after 474 * loading. The following steps are performed: 475 * <ol> 476 * <li> Call {@link #findLoadedClass(String)} to determine if the requested 477 * class has already been loaded.</li> 478 * <li>If the class has not yet been loaded: Invoke this method on the 479 * parent class loader.</li> 480 * <li>If the class has still not been loaded: Call 481 * {@link #findClass(String)} to find the class.</li> 482 * </ol> 483 * <p> 484 * <strong>Note:</strong> In the Android reference implementation, the 485 * {@code resolve} parameter is ignored; classes are never linked. 486 * </p> 487 * 488 * @return the {@code Class} object. 489 * @param className 490 * the name of the class to look for. 491 * @param resolve 492 * Indicates if the class should be resolved after loading. This 493 * parameter is ignored on the Android reference implementation; 494 * classes are not resolved. 495 * @throws ClassNotFoundException 496 * if the class can not be found. 497 */ loadClass(String className, boolean resolve)498 protected Class<?> loadClass(String className, boolean resolve) throws ClassNotFoundException { 499 Class<?> clazz = findLoadedClass(className); 500 501 if (clazz == null) { 502 ClassNotFoundException suppressed = null; 503 try { 504 clazz = parent.loadClass(className, false); 505 } catch (ClassNotFoundException e) { 506 suppressed = e; 507 } 508 509 if (clazz == null) { 510 try { 511 clazz = findClass(className); 512 } catch (ClassNotFoundException e) { 513 e.addSuppressed(suppressed); 514 throw e; 515 } 516 } 517 } 518 519 return clazz; 520 } 521 522 /** 523 * Forces a class to be linked (initialized). If the class has already been 524 * linked this operation has no effect. 525 * <p> 526 * <strong>Note:</strong> In the Android reference implementation, this 527 * method has no effect. 528 * </p> 529 * 530 * @param clazz 531 * the class to link. 532 */ resolveClass(Class<?> clazz)533 protected final void resolveClass(Class<?> clazz) { 534 // no-op, doesn't make sense on android. 535 } 536 537 /** 538 * Finds the URL of the resource with the specified name. This 539 * implementation just returns {@code null}; it should be overridden in 540 * subclasses. 541 * 542 * @param resName 543 * the name of the resource to find. 544 * @return the {@code URL} object for the requested resource. 545 */ findResource(String resName)546 protected URL findResource(String resName) { 547 return null; 548 } 549 550 /** 551 * Finds an enumeration of URLs for the resource with the specified name. 552 * This implementation just returns an empty {@code Enumeration}; it should 553 * be overridden in subclasses. 554 * 555 * @param resName 556 * the name of the resource to find. 557 * @return an enumeration of {@code URL} objects for the requested resource. 558 * @throws IOException 559 * if an I/O error occurs. 560 */ 561 @SuppressWarnings( { 562 "unchecked", "unused" 563 }) findResources(String resName)564 protected Enumeration<URL> findResources(String resName) throws IOException { 565 return Collections.emptyEnumeration(); 566 } 567 568 /** 569 * Returns the absolute path of the native library with the specified name, 570 * or {@code null}. If this method returns {@code null} then the virtual 571 * machine searches the directories specified by the system property 572 * "java.library.path". 573 * <p> 574 * This implementation always returns {@code null}. 575 * </p> 576 * 577 * @param libName 578 * the name of the library to find. 579 * @return the absolute path of the library. 580 */ findLibrary(String libName)581 protected String findLibrary(String libName) { 582 return null; 583 } 584 585 /** 586 * Returns the package with the specified name. Package information is 587 * searched in this class loader. 588 * 589 * @param name 590 * the name of the package to find. 591 * @return the package with the requested name; {@code null} if the package 592 * can not be found. 593 */ getPackage(String name)594 protected Package getPackage(String name) { 595 synchronized (packages) { 596 return packages.get(name); 597 } 598 } 599 600 /** 601 * Returns all the packages known to this class loader. 602 * 603 * @return an array with all packages known to this class loader. 604 */ getPackages()605 protected Package[] getPackages() { 606 synchronized (packages) { 607 Collection<Package> col = packages.values(); 608 Package[] result = new Package[col.size()]; 609 col.toArray(result); 610 return result; 611 } 612 } 613 614 /** 615 * Defines and returns a new {@code Package} using the specified 616 * information. If {@code sealBase} is {@code null}, the package is left 617 * unsealed. Otherwise, the package is sealed using this URL. 618 * 619 * @param name 620 * the name of the package. 621 * @param specTitle 622 * the title of the specification. 623 * @param specVersion 624 * the version of the specification. 625 * @param specVendor 626 * the vendor of the specification. 627 * @param implTitle 628 * the implementation title. 629 * @param implVersion 630 * the implementation version. 631 * @param implVendor 632 * the specification vendor. 633 * @param sealBase 634 * the URL used to seal this package or {@code null} to leave the 635 * package unsealed. 636 * @return the {@code Package} object that has been created. 637 * @throws IllegalArgumentException 638 * if a package with the specified name already exists. 639 */ definePackage(String name, String specTitle, String specVersion, String specVendor, String implTitle, String implVersion, String implVendor, URL sealBase)640 protected Package definePackage(String name, String specTitle, String specVersion, 641 String specVendor, String implTitle, String implVersion, String implVendor, URL sealBase) 642 throws IllegalArgumentException { 643 644 synchronized (packages) { 645 if (packages.containsKey(name)) { 646 throw new IllegalArgumentException("Package " + name + " already defined"); 647 } 648 649 Package newPackage = new Package(name, specTitle, specVersion, specVendor, implTitle, 650 implVersion, implVendor, sealBase); 651 652 packages.put(name, newPackage); 653 654 return newPackage; 655 } 656 } 657 658 /** 659 * Sets the signers of the specified class. This implementation does 660 * nothing. 661 * 662 * @param c 663 * the {@code Class} object for which to set the signers. 664 * @param signers 665 * the signers for {@code c}. 666 */ setSigners(Class<?> c, Object[] signers)667 protected final void setSigners(Class<?> c, Object[] signers) { 668 } 669 670 /** 671 * Sets the assertion status of the class with the specified name. 672 * <p> 673 * <strong>Note: </strong>This method does nothing in the Android reference 674 * implementation. 675 * </p> 676 * 677 * @param cname 678 * the name of the class for which to set the assertion status. 679 * @param enable 680 * the new assertion status. 681 */ setClassAssertionStatus(String cname, boolean enable)682 public void setClassAssertionStatus(String cname, boolean enable) { 683 } 684 685 /** 686 * Sets the assertion status of the package with the specified name. 687 * <p> 688 * <strong>Note: </strong>This method does nothing in the Android reference 689 * implementation. 690 * </p> 691 * 692 * @param pname 693 * the name of the package for which to set the assertion status. 694 * @param enable 695 * the new assertion status. 696 */ setPackageAssertionStatus(String pname, boolean enable)697 public void setPackageAssertionStatus(String pname, boolean enable) { 698 } 699 700 /** 701 * Sets the default assertion status for this class loader. 702 * <p> 703 * <strong>Note: </strong>This method does nothing in the Android reference 704 * implementation. 705 * </p> 706 * 707 * @param enable 708 * the new assertion status. 709 */ setDefaultAssertionStatus(boolean enable)710 public void setDefaultAssertionStatus(boolean enable) { 711 } 712 713 /** 714 * Sets the default assertion status for this class loader to {@code false} 715 * and removes any package default and class assertion status settings. 716 * <p> 717 * <strong>Note:</strong> This method does nothing in the Android reference 718 * implementation. 719 * </p> 720 */ clearAssertionStatus()721 public void clearAssertionStatus() { 722 } 723 } 724 725 /* 726 * Provides a helper class that combines two existing URL enumerations into one. 727 * It is required for the getResources() methods. Items are fetched from the 728 * first enumeration until it's empty, then from the second one. 729 */ 730 class TwoEnumerationsInOne implements Enumeration<URL> { 731 732 private final Enumeration<URL> first; 733 734 private final Enumeration<URL> second; 735 TwoEnumerationsInOne(Enumeration<URL> first, Enumeration<URL> second)736 public TwoEnumerationsInOne(Enumeration<URL> first, Enumeration<URL> second) { 737 this.first = first; 738 this.second = second; 739 } 740 741 @Override hasMoreElements()742 public boolean hasMoreElements() { 743 return first.hasMoreElements() || second.hasMoreElements(); 744 } 745 746 @Override nextElement()747 public URL nextElement() { 748 if (first.hasMoreElements()) { 749 return first.nextElement(); 750 } else { 751 return second.nextElement(); 752 } 753 } 754 755 } 756 757 /** 758 * Provides an explicit representation of the boot class loader. It sits at the 759 * head of the class loader chain and delegates requests to the VM's internal 760 * class loading mechanism. 761 */ 762 class BootClassLoader extends ClassLoader { 763 764 private static BootClassLoader instance; 765 766 @FindBugsSuppressWarnings("DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED") getInstance()767 public static synchronized BootClassLoader getInstance() { 768 if (instance == null) { 769 instance = new BootClassLoader(); 770 } 771 772 return instance; 773 } 774 BootClassLoader()775 public BootClassLoader() { 776 super(null, true); 777 } 778 779 @Override findClass(String name)780 protected Class<?> findClass(String name) throws ClassNotFoundException { 781 return Class.classForName(name, false, null); 782 } 783 784 @Override findResource(String name)785 protected URL findResource(String name) { 786 return VMClassLoader.getResource(name); 787 } 788 789 @SuppressWarnings("unused") 790 @Override findResources(String resName)791 protected Enumeration<URL> findResources(String resName) throws IOException { 792 return Collections.enumeration(VMClassLoader.getResources(resName)); 793 } 794 795 /** 796 * Returns package information for the given package. Unfortunately, the 797 * Android BootClassLoader doesn't really have this information, and as a 798 * non-secure ClassLoader, it isn't even required to, according to the spec. 799 * Yet, we want to provide it, in order to make all those hopeful callers of 800 * {@code myClass.getPackage().getName()} happy. Thus we construct a Package 801 * object the first time it is being requested and fill most of the fields 802 * with dummy values. The Package object is then put into the ClassLoader's 803 * Package cache, so we see the same one next time. We don't create Package 804 * objects for null arguments or for the default package. 805 * <p> 806 * There a limited chance that we end up with multiple Package objects 807 * representing the same package: It can happen when when a package is 808 * scattered across different JAR files being loaded by different 809 * ClassLoaders. Rather unlikely, and given that this whole thing is more or 810 * less a workaround, probably not worth the effort. 811 */ 812 @Override getPackage(String name)813 protected Package getPackage(String name) { 814 if (name != null && !name.isEmpty()) { 815 synchronized (this) { 816 Package pack = super.getPackage(name); 817 818 if (pack == null) { 819 pack = definePackage(name, "Unknown", "0.0", "Unknown", "Unknown", "0.0", 820 "Unknown", null); 821 } 822 823 return pack; 824 } 825 } 826 827 return null; 828 } 829 830 @Override getResource(String resName)831 public URL getResource(String resName) { 832 return findResource(resName); 833 } 834 835 @Override loadClass(String className, boolean resolve)836 protected Class<?> loadClass(String className, boolean resolve) 837 throws ClassNotFoundException { 838 Class<?> clazz = findLoadedClass(className); 839 840 if (clazz == null) { 841 clazz = findClass(className); 842 } 843 844 return clazz; 845 } 846 847 @Override getResources(String resName)848 public Enumeration<URL> getResources(String resName) throws IOException { 849 return findResources(resName); 850 } 851 } 852 853 /** 854 * TODO Open issues - Missing / empty methods - Signer stuff - Protection 855 * domains - Assertions 856 */ 857