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