Path: blob/master/src/java.base/share/classes/jdk/internal/loader/BootLoader.java
41159 views
/*1* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/24package jdk.internal.loader;2526import java.io.IOException;27import java.io.InputStream;28import java.lang.module.ModuleReference;29import java.net.MalformedURLException;30import java.net.URI;31import java.net.URL;32import java.nio.file.Files;33import java.nio.file.Path;34import java.security.AccessController;35import java.security.PrivilegedAction;36import java.util.Arrays;37import java.util.Enumeration;38import java.util.concurrent.ConcurrentHashMap;39import java.util.jar.JarInputStream;40import java.util.jar.Manifest;41import java.util.stream.Stream;4243import jdk.internal.access.JavaLangAccess;44import jdk.internal.access.SharedSecrets;45import jdk.internal.module.Modules;46import jdk.internal.module.ServicesCatalog;47import jdk.internal.util.StaticProperty;4849/**50* Find resources and packages in modules defined to the boot class loader or51* resources and packages on the "boot class path" specified via -Xbootclasspath/a.52*/5354public class BootLoader {55private BootLoader() { }5657private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();5859// The unnamed module for the boot loader60private static final Module UNNAMED_MODULE;61private static final String JAVA_HOME = StaticProperty.javaHome();6263static {64JavaLangAccess jla = SharedSecrets.getJavaLangAccess();65UNNAMED_MODULE = jla.defineUnnamedModule(null);66jla.addEnableNativeAccess(UNNAMED_MODULE);67setBootLoaderUnnamedModule0(UNNAMED_MODULE);68}6970// ClassLoaderValue map for the boot class loader71private static final ConcurrentHashMap<?, ?> CLASS_LOADER_VALUE_MAP72= new ConcurrentHashMap<>();7374// native libraries loaded by the boot class loader75private static final NativeLibraries NATIVE_LIBS76= NativeLibraries.jniNativeLibraries(null);7778/**79* Returns the unnamed module for the boot loader.80*/81public static Module getUnnamedModule() {82return UNNAMED_MODULE;83}8485/**86* Returns the ServiceCatalog for modules defined to the boot class loader.87*/88public static ServicesCatalog getServicesCatalog() {89return ServicesCatalog.getServicesCatalog(ClassLoaders.bootLoader());90}9192/**93* Returns the ClassLoaderValue map for the boot class loader.94*/95public static ConcurrentHashMap<?, ?> getClassLoaderValueMap() {96return CLASS_LOADER_VALUE_MAP;97}9899/**100* Returns NativeLibraries for the boot class loader.101*/102public static NativeLibraries getNativeLibraries() {103return NATIVE_LIBS;104}105106/**107* Returns {@code true} if there is a class path associated with the108* BootLoader.109*/110public static boolean hasClassPath() {111return ClassLoaders.bootLoader().hasClassPath();112}113114/**115* Registers a module with this class loader so that its classes116* (and resources) become visible via this class loader.117*/118public static void loadModule(ModuleReference mref) {119ClassLoaders.bootLoader().loadModule(mref);120}121122/**123* Loads the Class object with the given name defined to the boot loader.124*/125public static Class<?> loadClassOrNull(String name) {126return JLA.findBootstrapClassOrNull(name);127}128129/**130* Loads the Class object with the given name in the given module131* defined to the boot loader. Returns {@code null} if not found.132*/133public static Class<?> loadClass(Module module, String name) {134Class<?> c = loadClassOrNull(name);135if (c != null && c.getModule() == module) {136return c;137} else {138return null;139}140}141142/**143* Loads a native library from the system library path.144*/145@SuppressWarnings("removal")146public static void loadLibrary(String name) {147if (System.getSecurityManager() == null) {148BootLoader.getNativeLibraries().loadLibrary(name);149} else {150AccessController.doPrivileged(new java.security.PrivilegedAction<>() {151public Void run() {152BootLoader.getNativeLibraries().loadLibrary(name);153return null;154}155});156}157}158159/**160* Returns a URL to a resource in a module defined to the boot loader.161*/162public static URL findResource(String mn, String name) throws IOException {163return ClassLoaders.bootLoader().findResource(mn, name);164}165166/**167* Returns an input stream to a resource in a module defined to the168* boot loader.169*/170public static InputStream findResourceAsStream(String mn, String name)171throws IOException172{173return ClassLoaders.bootLoader().findResourceAsStream(mn, name);174}175176/**177* Returns the URL to the given resource in any of the modules178* defined to the boot loader and the boot class path.179*/180public static URL findResource(String name) {181return ClassLoaders.bootLoader().findResource(name);182}183184/**185* Returns an Iterator to iterate over the resources of the given name186* in any of the modules defined to the boot loader.187*/188public static Enumeration<URL> findResources(String name) throws IOException {189return ClassLoaders.bootLoader().findResources(name);190}191192/**193* Define a package for the given class to the boot loader, if not already194* defined.195*/196public static Package definePackage(Class<?> c) {197return getDefinedPackage(c.getPackageName());198}199200/**201* Returns the Package of the given name defined to the boot loader or null202* if the package has not been defined.203*/204public static Package getDefinedPackage(String pn) {205Package pkg = ClassLoaders.bootLoader().getDefinedPackage(pn);206if (pkg == null) {207String location = getSystemPackageLocation(pn.replace('.', '/'));208if (location != null) {209pkg = PackageHelper.definePackage(pn.intern(), location);210}211}212return pkg;213}214215/**216* Returns a stream of the packages defined to the boot loader.217*/218public static Stream<Package> packages() {219return Arrays.stream(getSystemPackageNames())220.map(name -> getDefinedPackage(name.replace('/', '.')));221}222223/**224* Helper class to define {@code Package} objects for packages in modules225* defined to the boot loader.226*/227static class PackageHelper {228private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();229230/**231* Define the {@code Package} with the given name. The specified232* location is a jrt URL to a named module in the run-time image,233* a file URL to a module in an exploded run-time image, or a file234* path to an entry on the boot class path (java agent Boot-Class-Path235* or -Xbootclasspath/a.236*237* <p> If the given location is a JAR file containing a manifest,238* the defined Package contains the versioning information from239* the manifest, if present.240*241* @param name package name242* @param location location where the package is (jrt URL or file URL243* for a named module in the run-time or exploded image;244* a file path for a package from -Xbootclasspath/a)245*/246static Package definePackage(String name, String location) {247Module module = findModule(location);248if (module != null) {249// named module from runtime image or exploded module250if (name.isEmpty())251throw new InternalError("empty package in " + location);252return JLA.definePackage(ClassLoaders.bootLoader(), name, module);253}254255// package in unnamed module (-Xbootclasspath/a)256URL url = toFileURL(location);257Manifest man = url != null ? getManifest(location) : null;258259return ClassLoaders.bootLoader().defineOrCheckPackage(name, man, url);260}261262/**263* Finds the module at the given location defined to the boot loader.264* The module is either in runtime image or exploded image.265* Otherwise this method returns null.266*/267private static Module findModule(String location) {268String mn = null;269if (location.startsWith("jrt:/")) {270// named module in runtime image ("jrt:/".length() == 5)271mn = location.substring(5, location.length());272} else if (location.startsWith("file:/")) {273// named module in exploded image274Path path = Path.of(URI.create(location));275Path modulesDir = Path.of(JAVA_HOME, "modules");276if (path.startsWith(modulesDir)) {277mn = path.getFileName().toString();278}279}280281// return the Module object for the module name. The Module may282// in the boot layer or a child layer for the case that the module283// is loaded into a running VM284if (mn != null) {285String name = mn;286return Modules.findLoadedModule(mn)287.orElseThrow(() -> new InternalError(name + " not loaded"));288} else {289return null;290}291}292293/**294* Returns URL if the given location is a regular file path.295*/296@SuppressWarnings("removal")297private static URL toFileURL(String location) {298return AccessController.doPrivileged(new PrivilegedAction<>() {299public URL run() {300Path path = Path.of(location);301if (Files.isRegularFile(path)) {302try {303return path.toUri().toURL();304} catch (MalformedURLException e) {}305}306return null;307}308});309}310311/**312* Returns the Manifest if the given location is a JAR file313* containing a manifest.314*/315@SuppressWarnings("removal")316private static Manifest getManifest(String location) {317return AccessController.doPrivileged(new PrivilegedAction<>() {318public Manifest run() {319Path jar = Path.of(location);320try (InputStream in = Files.newInputStream(jar);321JarInputStream jis = new JarInputStream(in, false)) {322return jis.getManifest();323} catch (IOException e) {324return null;325}326}327});328}329}330331/**332* Returns an array of the binary name of the packages defined by333* the boot loader, in VM internal form (forward slashes instead of dot).334*/335private static native String[] getSystemPackageNames();336337/**338* Returns the location of the package of the given name, if339* defined by the boot loader; otherwise {@code null} is returned.340*341* The location may be a module from the runtime image or exploded image,342* or from the boot class append path (i.e. -Xbootclasspath/a or343* BOOT-CLASS-PATH attribute specified in java agent).344*/345private static native String getSystemPackageLocation(String name);346private static native void setBootLoaderUnnamedModule0(Module module);347}348349350