• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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