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
33package java.lang;
34
35import dalvik.system.PathClassLoader;
36import java.io.IOException;
37import java.io.InputStream;
38import java.net.URL;
39import java.nio.ByteBuffer;
40import java.security.ProtectionDomain;
41import java.util.Collection;
42import java.util.Collections;
43import java.util.Enumeration;
44import java.util.HashMap;
45import java.util.Map;
46import java.util.Set;
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 */
65public 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<Set<Class<?>>, Class<?>> proxyCache
104            = Collections.synchronizedMap(new HashMap<Set<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     */
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     */
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     */
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     */
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     */
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     */
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     */
201    protected ClassLoader(ClassLoader parentLoader) {
202        this(parentLoader, false);
203    }
204
205    /*
206     * constructor for the BootClassLoader which needs parent to be null.
207     */
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
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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")
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     */
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     */
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     */
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     */
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     */
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    })
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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 */
730class TwoEnumerationsInOne implements Enumeration<URL> {
731
732    private final Enumeration<URL> first;
733
734    private final Enumeration<URL> second;
735
736    public TwoEnumerationsInOne(Enumeration<URL> first, Enumeration<URL> second) {
737        this.first = first;
738        this.second = second;
739    }
740
741    @Override
742    public boolean hasMoreElements() {
743        return first.hasMoreElements() || second.hasMoreElements();
744    }
745
746    @Override
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 */
762class BootClassLoader extends ClassLoader {
763
764    private static BootClassLoader instance;
765
766    @FindBugsSuppressWarnings("DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED")
767    public static synchronized BootClassLoader getInstance() {
768        if (instance == null) {
769            instance = new BootClassLoader();
770        }
771
772        return instance;
773    }
774
775    public BootClassLoader() {
776        super(null, true);
777    }
778
779    @Override
780    protected Class<?> findClass(String name) throws ClassNotFoundException {
781        return Class.classForName(name, false, null);
782    }
783
784    @Override
785    protected URL findResource(String name) {
786        return VMClassLoader.getResource(name);
787    }
788
789    @SuppressWarnings("unused")
790    @Override
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
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
831    public URL getResource(String resName) {
832        return findResource(resName);
833    }
834
835    @Override
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
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