1 /*
2  * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package java.net;
27 
28 import java.io.Closeable;
29 import java.io.File;
30 import java.io.FilePermission;
31 import java.io.IOException;
32 import java.io.InputStream;
33 import java.security.AccessControlContext;
34 import java.security.AccessController;
35 import java.security.CodeSigner;
36 import java.security.CodeSource;
37 import java.security.Permission;
38 import java.security.PermissionCollection;
39 import java.security.PrivilegedAction;
40 import java.security.PrivilegedExceptionAction;
41 import java.security.SecureClassLoader;
42 import java.util.Enumeration;
43 import java.util.List;
44 import java.util.NoSuchElementException;
45 import java.util.Objects;
46 import java.util.Set;
47 import java.util.WeakHashMap;
48 import java.util.jar.Attributes;
49 import java.util.jar.Attributes.Name;
50 import java.util.jar.JarFile;
51 import java.util.jar.Manifest;
52 import sun.misc.Resource;
53 import sun.misc.URLClassPath;
54 import sun.net.www.ParseUtil;
55 import sun.security.util.SecurityConstants;
56 
57 /**
58  * This class loader is used to load classes and resources from a search
59  * path of URLs referring to both JAR files and directories. Any URL that
60  * ends with a '/' is assumed to refer to a directory. Otherwise, the URL
61  * is assumed to refer to a JAR file which will be opened as needed.
62  * <p>
63  * The AccessControlContext of the thread that created the instance of
64  * URLClassLoader will be used when subsequently loading classes and
65  * resources.
66  * <p>
67  * The classes that are loaded are by default granted permission only to
68  * access the URLs specified when the URLClassLoader was created.
69  *
70  * @author  David Connelly
71  * @since   1.2
72  */
73 public class URLClassLoader extends SecureClassLoader implements Closeable {
74     /* The search path for classes and resources */
75     private final URLClassPath ucp;
76 
77     /* The context to be used when loading classes and resources */
78     private final AccessControlContext acc;
79 
80     /**
81      * Constructs a new URLClassLoader for the given URLs. The URLs will be
82      * searched in the order specified for classes and resources after first
83      * searching in the specified parent class loader. Any URL that ends with
84      * a '/' is assumed to refer to a directory. Otherwise, the URL is assumed
85      * to refer to a JAR file which will be downloaded and opened as needed.
86      *
87      * <p>If there is a security manager, this method first
88      * calls the security manager's {@code checkCreateClassLoader} method
89      * to ensure creation of a class loader is allowed.
90      *
91      * @param urls the URLs from which to load classes and resources
92      * @param parent the parent class loader for delegation
93      * @exception  SecurityException  if a security manager exists and its
94      *             {@code checkCreateClassLoader} method doesn't allow
95      *             creation of a class loader.
96      * @exception  NullPointerException if {@code urls} is {@code null}.
97      * @see SecurityManager#checkCreateClassLoader
98      */
URLClassLoader(URL[] urls, ClassLoader parent)99     public URLClassLoader(URL[] urls, ClassLoader parent) {
100         super(parent);
101         // this is to make the stack depth consistent with 1.1
102         SecurityManager security = System.getSecurityManager();
103         if (security != null) {
104             security.checkCreateClassLoader();
105         }
106         this.acc = AccessController.getContext();
107         ucp = new URLClassPath(urls, acc);
108     }
109 
URLClassLoader(URL[] urls, ClassLoader parent, AccessControlContext acc)110     URLClassLoader(URL[] urls, ClassLoader parent,
111                    AccessControlContext acc) {
112         super(parent);
113         // this is to make the stack depth consistent with 1.1
114         SecurityManager security = System.getSecurityManager();
115         if (security != null) {
116             security.checkCreateClassLoader();
117         }
118         this.acc = acc;
119         ucp = new URLClassPath(urls, acc);
120     }
121 
122     /**
123      * Constructs a new URLClassLoader for the specified URLs using the
124      * default delegation parent {@code ClassLoader}. The URLs will
125      * be searched in the order specified for classes and resources after
126      * first searching in the parent class loader. Any URL that ends with
127      * a '/' is assumed to refer to a directory. Otherwise, the URL is
128      * assumed to refer to a JAR file which will be downloaded and opened
129      * as needed.
130      *
131      * <p>If there is a security manager, this method first
132      * calls the security manager's {@code checkCreateClassLoader} method
133      * to ensure creation of a class loader is allowed.
134      *
135      * @param urls the URLs from which to load classes and resources
136      *
137      * @exception  SecurityException  if a security manager exists and its
138      *             {@code checkCreateClassLoader} method doesn't allow
139      *             creation of a class loader.
140      * @exception  NullPointerException if {@code urls} is {@code null}.
141      * @see SecurityManager#checkCreateClassLoader
142      */
URLClassLoader(URL[] urls)143     public URLClassLoader(URL[] urls) {
144         super();
145         // this is to make the stack depth consistent with 1.1
146         SecurityManager security = System.getSecurityManager();
147         if (security != null) {
148             security.checkCreateClassLoader();
149         }
150         this.acc = AccessController.getContext();
151         ucp = new URLClassPath(urls, acc);
152     }
153 
URLClassLoader(URL[] urls, AccessControlContext acc)154     URLClassLoader(URL[] urls, AccessControlContext acc) {
155         super();
156         // this is to make the stack depth consistent with 1.1
157         SecurityManager security = System.getSecurityManager();
158         if (security != null) {
159             security.checkCreateClassLoader();
160         }
161         this.acc = acc;
162         ucp = new URLClassPath(urls, acc);
163     }
164 
165     /**
166      * Constructs a new URLClassLoader for the specified URLs, parent
167      * class loader, and URLStreamHandlerFactory. The parent argument
168      * will be used as the parent class loader for delegation. The
169      * factory argument will be used as the stream handler factory to
170      * obtain protocol handlers when creating new jar URLs.
171      *
172      * <p>If there is a security manager, this method first
173      * calls the security manager's {@code checkCreateClassLoader} method
174      * to ensure creation of a class loader is allowed.
175      *
176      * @param urls the URLs from which to load classes and resources
177      * @param parent the parent class loader for delegation
178      * @param factory the URLStreamHandlerFactory to use when creating URLs
179      *
180      * @exception  SecurityException  if a security manager exists and its
181      *             {@code checkCreateClassLoader} method doesn't allow
182      *             creation of a class loader.
183      * @exception  NullPointerException if {@code urls} is {@code null}.
184      * @see SecurityManager#checkCreateClassLoader
185      */
URLClassLoader(URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory)186     public URLClassLoader(URL[] urls, ClassLoader parent,
187                           URLStreamHandlerFactory factory) {
188         super(parent);
189         // this is to make the stack depth consistent with 1.1
190         SecurityManager security = System.getSecurityManager();
191         if (security != null) {
192             security.checkCreateClassLoader();
193         }
194         acc = AccessController.getContext();
195         ucp = new URLClassPath(urls, factory, acc);
196     }
197 
198     /* A map (used as a set) to keep track of closeable local resources
199      * (either JarFiles or FileInputStreams). We don't care about
200      * Http resources since they don't need to be closed.
201      *
202      * If the resource is coming from a jar file
203      * we keep a (weak) reference to the JarFile object which can
204      * be closed if URLClassLoader.close() called. Due to jar file
205      * caching there will typically be only one JarFile object
206      * per underlying jar file.
207      *
208      * For file resources, which is probably a less common situation
209      * we have to keep a weak reference to each stream.
210      */
211 
212     private WeakHashMap<Closeable,Void>
213         closeables = new WeakHashMap<>();
214 
215     /**
216      * Returns an input stream for reading the specified resource.
217      * If this loader is closed, then any resources opened by this method
218      * will be closed.
219      *
220      * <p> The search order is described in the documentation for {@link
221      * #getResource(String)}.  </p>
222      *
223      * @param  name
224      *         The resource name
225      *
226      * @return  An input stream for reading the resource, or {@code null}
227      *          if the resource could not be found
228      *
229      * @since  1.7
230      */
getResourceAsStream(String name)231     public InputStream getResourceAsStream(String name) {
232         URL url = getResource(name);
233         try {
234             if (url == null) {
235                 return null;
236             }
237             URLConnection urlc = url.openConnection();
238             InputStream is = urlc.getInputStream();
239             if (urlc instanceof JarURLConnection) {
240                 JarURLConnection juc = (JarURLConnection)urlc;
241                 JarFile jar = juc.getJarFile();
242                 synchronized (closeables) {
243                     if (!closeables.containsKey(jar)) {
244                         closeables.put(jar, null);
245                     }
246                 }
247             } else if (urlc instanceof sun.net.www.protocol.file.FileURLConnection) {
248                 synchronized (closeables) {
249                     closeables.put(is, null);
250                 }
251             }
252             return is;
253         } catch (IOException e) {
254             return null;
255         }
256     }
257 
258    /**
259     * Closes this URLClassLoader, so that it can no longer be used to load
260     * new classes or resources that are defined by this loader.
261     * Classes and resources defined by any of this loader's parents in the
262     * delegation hierarchy are still accessible. Also, any classes or resources
263     * that are already loaded, are still accessible.
264     * <p>
265     * In the case of jar: and file: URLs, it also closes any files
266     * that were opened by it. If another thread is loading a
267     * class when the {@code close} method is invoked, then the result of
268     * that load is undefined.
269     * <p>
270     * The method makes a best effort attempt to close all opened files,
271     * by catching {@link IOException}s internally. Unchecked exceptions
272     * and errors are not caught. Calling close on an already closed
273     * loader has no effect.
274     * <p>
275     * @exception IOException if closing any file opened by this class loader
276     * resulted in an IOException. Any such exceptions are caught internally.
277     * If only one is caught, then it is re-thrown. If more than one exception
278     * is caught, then the second and following exceptions are added
279     * as suppressed exceptions of the first one caught, which is then re-thrown.
280     *
281     * @exception SecurityException if a security manager is set, and it denies
282     *   {@link RuntimePermission}{@code ("closeClassLoader")}
283     *
284     * @since 1.7
285     */
close()286     public void close() throws IOException {
287         SecurityManager security = System.getSecurityManager();
288         if (security != null) {
289             security.checkPermission(new RuntimePermission("closeClassLoader"));
290         }
291         List<IOException> errors = ucp.closeLoaders();
292 
293         // now close any remaining streams.
294 
295         synchronized (closeables) {
296             Set<Closeable> keys = closeables.keySet();
297             for (Closeable c : keys) {
298                 try {
299                     c.close();
300                 } catch (IOException ioex) {
301                     errors.add(ioex);
302                 }
303             }
304             closeables.clear();
305         }
306 
307         if (errors.isEmpty()) {
308             return;
309         }
310 
311         IOException firstex = errors.remove(0);
312 
313         // Suppress any remaining exceptions
314 
315         for (IOException error: errors) {
316             firstex.addSuppressed(error);
317         }
318         throw firstex;
319     }
320 
321     /**
322      * Appends the specified URL to the list of URLs to search for
323      * classes and resources.
324      * <p>
325      * If the URL specified is {@code null} or is already in the
326      * list of URLs, or if this loader is closed, then invoking this
327      * method has no effect.
328      *
329      * @param url the URL to be added to the search path of URLs
330      */
addURL(URL url)331     protected void addURL(URL url) {
332         ucp.addURL(url);
333     }
334 
335     /**
336      * Returns the search path of URLs for loading classes and resources.
337      * This includes the original list of URLs specified to the constructor,
338      * along with any URLs subsequently appended by the addURL() method.
339      * @return the search path of URLs for loading classes and resources.
340      */
getURLs()341     public URL[] getURLs() {
342         return ucp.getURLs();
343     }
344 
345     /**
346      * Finds and loads the class with the specified name from the URL search
347      * path. Any URLs referring to JAR files are loaded and opened as needed
348      * until the class is found.
349      *
350      * @param name the name of the class
351      * @return the resulting class
352      * @exception ClassNotFoundException if the class could not be found,
353      *            or if the loader is closed.
354      * @exception NullPointerException if {@code name} is {@code null}.
355      */
findClass(final String name)356     protected Class<?> findClass(final String name)
357         throws ClassNotFoundException
358     {
359         final Class<?> result;
360         try {
361             result = AccessController.doPrivileged(
362                 new PrivilegedExceptionAction<Class<?>>() {
363                     public Class<?> run() throws ClassNotFoundException {
364                         String path = name.replace('.', '/').concat(".class");
365                         Resource res = ucp.getResource(path, false);
366                         if (res != null) {
367                             try {
368                                 return defineClass(name, res);
369                             } catch (IOException e) {
370                                 throw new ClassNotFoundException(name, e);
371                             }
372                         } else {
373                             return null;
374                         }
375                     }
376                 }, acc);
377         } catch (java.security.PrivilegedActionException pae) {
378             throw (ClassNotFoundException) pae.getException();
379         }
380         if (result == null) {
381             throw new ClassNotFoundException(name);
382         }
383         return result;
384     }
385 
386     /*
387      * Retrieve the package using the specified package name.
388      * If non-null, verify the package using the specified code
389      * source and manifest.
390      */
getAndVerifyPackage(String pkgname, Manifest man, URL url)391     private Package getAndVerifyPackage(String pkgname,
392                                         Manifest man, URL url) {
393         Package pkg = getPackage(pkgname);
394         if (pkg != null) {
395             // Package found, so check package sealing.
396             if (pkg.isSealed()) {
397                 // Verify that code source URL is the same.
398                 if (!pkg.isSealed(url)) {
399                     throw new SecurityException(
400                         "sealing violation: package " + pkgname + " is sealed");
401                 }
402             } else {
403                 // Make sure we are not attempting to seal the package
404                 // at this code source URL.
405                 if ((man != null) && isSealed(pkgname, man)) {
406                     throw new SecurityException(
407                         "sealing violation: can't seal package " + pkgname +
408                         ": already loaded");
409                 }
410             }
411         }
412         return pkg;
413     }
414 
415     // Also called by VM to define Package for classes loaded from the CDS
416     // archive
definePackageInternal(String pkgname, Manifest man, URL url)417     private void definePackageInternal(String pkgname, Manifest man, URL url)
418     {
419         if (getAndVerifyPackage(pkgname, man, url) == null) {
420             try {
421                 if (man != null) {
422                     definePackage(pkgname, man, url);
423                 } else {
424                     definePackage(pkgname, null, null, null, null, null, null, null);
425                 }
426             } catch (IllegalArgumentException iae) {
427                 // parallel-capable class loaders: re-verify in case of a
428                 // race condition
429                 if (getAndVerifyPackage(pkgname, man, url) == null) {
430                     // Should never happen
431                     throw new AssertionError("Cannot find package " +
432                                              pkgname);
433                 }
434             }
435         }
436     }
437 
438     /*
439      * Defines a Class using the class bytes obtained from the specified
440      * Resource. The resulting Class must be resolved before it can be
441      * used.
442      */
defineClass(String name, Resource res)443     private Class<?> defineClass(String name, Resource res) throws IOException {
444         long t0 = System.nanoTime();
445         int i = name.lastIndexOf('.');
446         URL url = res.getCodeSourceURL();
447         if (i != -1) {
448             String pkgname = name.substring(0, i);
449             // Check if package already loaded.
450             Manifest man = res.getManifest();
451             definePackageInternal(pkgname, man, url);
452         }
453         // Now read the class bytes and define the class
454         java.nio.ByteBuffer bb = res.getByteBuffer();
455         if (bb != null) {
456             // Use (direct) ByteBuffer:
457             CodeSigner[] signers = res.getCodeSigners();
458             CodeSource cs = new CodeSource(url, signers);
459             // Android-removed: Android doesn't use sun.misc.PerfCounter.
460             // sun.misc.PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0);
461             return defineClass(name, bb, cs);
462         } else {
463             byte[] b = res.getBytes();
464             // must read certificates AFTER reading bytes.
465             CodeSigner[] signers = res.getCodeSigners();
466             CodeSource cs = new CodeSource(url, signers);
467             // Android-removed: Android doesn't use sun.misc.PerfCounter.
468             // sun.misc.PerfCounter.getReadClassBytesTime().addElapsedTimeFrom(t0);
469             return defineClass(name, b, 0, b.length, cs);
470         }
471     }
472 
473     /**
474      * Defines a new package by name in this ClassLoader. The attributes
475      * contained in the specified Manifest will be used to obtain package
476      * version and sealing information. For sealed packages, the additional
477      * URL specifies the code source URL from which the package was loaded.
478      *
479      * @param name  the package name
480      * @param man   the Manifest containing package version and sealing
481      *              information
482      * @param url   the code source url for the package, or null if none
483      * @exception   IllegalArgumentException if the package name duplicates
484      *              an existing package either in this class loader or one
485      *              of its ancestors
486      * @return the newly defined Package object
487      */
definePackage(String name, Manifest man, URL url)488     protected Package definePackage(String name, Manifest man, URL url)
489         throws IllegalArgumentException
490     {
491         String path = name.replace('.', '/').concat("/");
492         String specTitle = null, specVersion = null, specVendor = null;
493         String implTitle = null, implVersion = null, implVendor = null;
494         String sealed = null;
495         URL sealBase = null;
496 
497         Attributes attr = man.getAttributes(path);
498         if (attr != null) {
499             specTitle   = attr.getValue(Name.SPECIFICATION_TITLE);
500             specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
501             specVendor  = attr.getValue(Name.SPECIFICATION_VENDOR);
502             implTitle   = attr.getValue(Name.IMPLEMENTATION_TITLE);
503             implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
504             implVendor  = attr.getValue(Name.IMPLEMENTATION_VENDOR);
505             sealed      = attr.getValue(Name.SEALED);
506         }
507         attr = man.getMainAttributes();
508         if (attr != null) {
509             if (specTitle == null) {
510                 specTitle = attr.getValue(Name.SPECIFICATION_TITLE);
511             }
512             if (specVersion == null) {
513                 specVersion = attr.getValue(Name.SPECIFICATION_VERSION);
514             }
515             if (specVendor == null) {
516                 specVendor = attr.getValue(Name.SPECIFICATION_VENDOR);
517             }
518             if (implTitle == null) {
519                 implTitle = attr.getValue(Name.IMPLEMENTATION_TITLE);
520             }
521             if (implVersion == null) {
522                 implVersion = attr.getValue(Name.IMPLEMENTATION_VERSION);
523             }
524             if (implVendor == null) {
525                 implVendor = attr.getValue(Name.IMPLEMENTATION_VENDOR);
526             }
527             if (sealed == null) {
528                 sealed = attr.getValue(Name.SEALED);
529             }
530         }
531         if ("true".equalsIgnoreCase(sealed)) {
532             sealBase = url;
533         }
534         return definePackage(name, specTitle, specVersion, specVendor,
535                              implTitle, implVersion, implVendor, sealBase);
536     }
537 
538     /*
539      * Returns true if the specified package name is sealed according to the
540      * given manifest.
541      */
isSealed(String name, Manifest man)542     private boolean isSealed(String name, Manifest man) {
543         String path = name.replace('.', '/').concat("/");
544         Attributes attr = man.getAttributes(path);
545         String sealed = null;
546         if (attr != null) {
547             sealed = attr.getValue(Name.SEALED);
548         }
549         if (sealed == null) {
550             if ((attr = man.getMainAttributes()) != null) {
551                 sealed = attr.getValue(Name.SEALED);
552             }
553         }
554         return "true".equalsIgnoreCase(sealed);
555     }
556 
557     /**
558      * Finds the resource with the specified name on the URL search path.
559      *
560      * @param name the name of the resource
561      * @return a {@code URL} for the resource, or {@code null}
562      * if the resource could not be found, or if the loader is closed.
563      */
findResource(final String name)564     public URL findResource(final String name) {
565         /*
566          * The same restriction to finding classes applies to resources
567          */
568         URL url = AccessController.doPrivileged(
569             new PrivilegedAction<URL>() {
570                 public URL run() {
571                     return ucp.findResource(name, true);
572                 }
573             }, acc);
574 
575         return url != null ? ucp.checkURL(url) : null;
576     }
577 
578     /**
579      * Returns an Enumeration of URLs representing all of the resources
580      * on the URL search path having the specified name.
581      *
582      * @param name the resource name
583      * @exception IOException if an I/O exception occurs
584      * @return an {@code Enumeration} of {@code URL}s
585      *         If the loader is closed, the Enumeration will be empty.
586      */
findResources(final String name)587     public Enumeration<URL> findResources(final String name)
588         throws IOException
589     {
590         final Enumeration<URL> e = ucp.findResources(name, true);
591 
592         return new Enumeration<URL>() {
593             private URL url = null;
594 
595             private boolean next() {
596                 if (url != null) {
597                     return true;
598                 }
599                 do {
600                     URL u = AccessController.doPrivileged(
601                         new PrivilegedAction<URL>() {
602                             public URL run() {
603                                 if (!e.hasMoreElements())
604                                     return null;
605                                 return e.nextElement();
606                             }
607                         }, acc);
608                     if (u == null)
609                         break;
610                     url = ucp.checkURL(u);
611                 } while (url == null);
612                 return url != null;
613             }
614 
615             public URL nextElement() {
616                 if (!next()) {
617                     throw new NoSuchElementException();
618                 }
619                 URL u = url;
620                 url = null;
621                 return u;
622             }
623 
624             public boolean hasMoreElements() {
625                 return next();
626             }
627         };
628     }
629 
630     /**
631      * Returns the permissions for the given codesource object.
632      * The implementation of this method first calls super.getPermissions
633      * and then adds permissions based on the URL of the codesource.
634      * <p>
635      * If the protocol of this URL is "jar", then the permission granted
636      * is based on the permission that is required by the URL of the Jar
637      * file.
638      * <p>
639      * If the protocol is "file" and there is an authority component, then
640      * permission to connect to and accept connections from that authority
641      * may be granted. If the protocol is "file"
642      * and the path specifies a file, then permission to read that
643      * file is granted. If protocol is "file" and the path is
644      * a directory, permission is granted to read all files
645      * and (recursively) all files and subdirectories contained in
646      * that directory.
647      * <p>
648      * If the protocol is not "file", then permission
649      * to connect to and accept connections from the URL's host is granted.
650      * @param codesource the codesource
651      * @exception NullPointerException if {@code codesource} is {@code null}.
652      * @return the permissions granted to the codesource
653      */
getPermissions(CodeSource codesource)654     protected PermissionCollection getPermissions(CodeSource codesource)
655     {
656         PermissionCollection perms = super.getPermissions(codesource);
657 
658         URL url = codesource.getLocation();
659 
660         Permission p;
661         URLConnection urlConnection;
662 
663         try {
664             urlConnection = url.openConnection();
665             p = urlConnection.getPermission();
666         } catch (java.io.IOException ioe) {
667             p = null;
668             urlConnection = null;
669         }
670 
671         if (p instanceof FilePermission) {
672             // if the permission has a separator char on the end,
673             // it means the codebase is a directory, and we need
674             // to add an additional permission to read recursively
675             String path = p.getName();
676             if (path.endsWith(File.separator)) {
677                 path += "-";
678                 p = new FilePermission(path, SecurityConstants.FILE_READ_ACTION);
679             }
680         } else if ((p == null) && (url.getProtocol().equals("file"))) {
681             String path = url.getFile().replace('/', File.separatorChar);
682             path = ParseUtil.decode(path);
683             if (path.endsWith(File.separator))
684                 path += "-";
685             p =  new FilePermission(path, SecurityConstants.FILE_READ_ACTION);
686         } else {
687             /**
688              * Not loading from a 'file:' URL so we want to give the class
689              * permission to connect to and accept from the remote host
690              * after we've made sure the host is the correct one and is valid.
691              */
692             URL locUrl = url;
693             if (urlConnection instanceof JarURLConnection) {
694                 locUrl = ((JarURLConnection)urlConnection).getJarFileURL();
695             }
696             String host = locUrl.getHost();
697             if (host != null && (host.length() > 0))
698                 p = new SocketPermission(host,
699                                          SecurityConstants.SOCKET_CONNECT_ACCEPT_ACTION);
700         }
701 
702         // make sure the person that created this class loader
703         // would have this permission
704 
705         if (p != null) {
706             final SecurityManager sm = System.getSecurityManager();
707             if (sm != null) {
708                 final Permission fp = p;
709                 AccessController.doPrivileged(new PrivilegedAction<Void>() {
710                     public Void run() throws SecurityException {
711                         sm.checkPermission(fp);
712                         return null;
713                     }
714                 }, acc);
715             }
716             perms.add(p);
717         }
718         return perms;
719     }
720 
721     /**
722      * Creates a new instance of URLClassLoader for the specified
723      * URLs and parent class loader. If a security manager is
724      * installed, the {@code loadClass} method of the URLClassLoader
725      * returned by this method will invoke the
726      * {@code SecurityManager.checkPackageAccess} method before
727      * loading the class.
728      *
729      * @param urls the URLs to search for classes and resources
730      * @param parent the parent class loader for delegation
731      * @exception  NullPointerException if {@code urls} is {@code null}.
732      * @return the resulting class loader
733      */
newInstance(final URL[] urls, final ClassLoader parent)734     public static URLClassLoader newInstance(final URL[] urls,
735                                              final ClassLoader parent) {
736         // Save the caller's context
737         final AccessControlContext acc = AccessController.getContext();
738         // Need a privileged block to create the class loader
739         URLClassLoader ucl = AccessController.doPrivileged(
740             new PrivilegedAction<URLClassLoader>() {
741                 public URLClassLoader run() {
742                     return new FactoryURLClassLoader(urls, parent, acc);
743                 }
744             });
745         return ucl;
746     }
747 
748     /**
749      * Creates a new instance of URLClassLoader for the specified
750      * URLs and default parent class loader. If a security manager is
751      * installed, the {@code loadClass} method of the URLClassLoader
752      * returned by this method will invoke the
753      * {@code SecurityManager.checkPackageAccess} before
754      * loading the class.
755      *
756      * @param urls the URLs to search for classes and resources
757      * @exception  NullPointerException if {@code urls} is {@code null}.
758      * @return the resulting class loader
759      */
newInstance(final URL[] urls)760     public static URLClassLoader newInstance(final URL[] urls) {
761         // Save the caller's context
762         final AccessControlContext acc = AccessController.getContext();
763         // Need a privileged block to create the class loader
764         URLClassLoader ucl = AccessController.doPrivileged(
765             new PrivilegedAction<URLClassLoader>() {
766                 public URLClassLoader run() {
767                     return new FactoryURLClassLoader(urls, acc);
768                 }
769             });
770         return ucl;
771     }
772 
773     static {
774         // Android-removed: SharedSecrets.setJavaNetAccess call. Android doesn't use it.
775         /*sun.misc.SharedSecrets.setJavaNetAccess (
776             new sun.misc.JavaNetAccess() {
777                 public URLClassPath getURLClassPath (URLClassLoader u) {
778                     return u.ucp;
779                 }
780 
781                 public String getOriginalHostName(InetAddress ia) {
782                     return ia.holder.getOriginalHostName();
783                 }
784             }
785         );*/
ClassLoader.registerAsParallelCapable()786         ClassLoader.registerAsParallelCapable();
787     }
788 }
789 
790 final class FactoryURLClassLoader extends URLClassLoader {
791 
792     static {
793         ClassLoader.registerAsParallelCapable();
794     }
795 
796     FactoryURLClassLoader(URL[] urls, ClassLoader parent,
797                           AccessControlContext acc) {
798         super(urls, parent, acc);
799     }
800 
801     FactoryURLClassLoader(URL[] urls, AccessControlContext acc) {
802         super(urls, acc);
803     }
804 
805     public final Class<?> loadClass(String name, boolean resolve)
806         throws ClassNotFoundException
807     {
808         // First check if we have permission to access the package. This
809         // should go away once we've added support for exported packages.
810         SecurityManager sm = System.getSecurityManager();
811         if (sm != null) {
812             int i = name.lastIndexOf('.');
813             if (i != -1) {
814                 sm.checkPackageAccess(name.substring(0, i));
815             }
816         }
817         return super.loadClass(name, resolve);
818     }
819 }
820