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.lang.module; 27 28 import java.io.ByteArrayInputStream; 29 import java.io.IOException; 30 import java.io.InputStream; 31 import java.io.UncheckedIOException; 32 import java.net.URI; 33 import java.net.URLConnection; 34 import java.nio.ByteBuffer; 35 import java.util.ArrayDeque; 36 import java.util.Collections; 37 import java.util.Deque; 38 import java.util.HashMap; 39 import java.util.HashSet; 40 import java.util.Iterator; 41 import java.util.Map; 42 import java.util.Map.Entry; 43 import java.util.Objects; 44 import java.util.Optional; 45 import java.util.Set; 46 import java.util.Spliterator; 47 import java.util.function.Consumer; 48 import java.util.function.Supplier; 49 import java.util.stream.Stream; 50 import java.util.stream.StreamSupport; 51 52 import jdk.internal.jimage.ImageLocation; 53 import jdk.internal.jimage.ImageReader; 54 import jdk.internal.jimage.ImageReaderFactory; 55 import jdk.internal.misc.JavaNetUriAccess; 56 import jdk.internal.misc.SharedSecrets; 57 import jdk.internal.module.ModuleBootstrap; 58 import jdk.internal.module.ModuleHashes; 59 import jdk.internal.module.ModuleHashes.HashSupplier; 60 import jdk.internal.module.SystemModules; 61 import jdk.internal.module.ModulePatcher; 62 import jdk.internal.perf.PerfCounter; 63 64 /** 65 * A {@code ModuleFinder} that finds modules that are linked into the 66 * run-time image. 67 * 68 * The modules linked into the run-time image are assumed to have the 69 * Packages attribute. 70 */ 71 72 class SystemModuleFinder implements ModuleFinder { 73 74 private static final JavaNetUriAccess JNUA = SharedSecrets.getJavaNetUriAccess(); 75 76 private static final PerfCounter initTime 77 = PerfCounter.newPerfCounter("jdk.module.finder.jimage.initTime"); 78 private static final PerfCounter moduleCount 79 = PerfCounter.newPerfCounter("jdk.module.finder.jimage.modules"); 80 private static final PerfCounter packageCount 81 = PerfCounter.newPerfCounter("jdk.module.finder.jimage.packages"); 82 private static final PerfCounter exportsCount 83 = PerfCounter.newPerfCounter("jdk.module.finder.jimage.exports"); 84 // ImageReader used to access all modules in the image 85 private static final ImageReader imageReader; 86 87 // the set of modules in the run-time image 88 private static final Set<ModuleReference> modules; 89 90 // maps module name to module reference 91 private static final Map<String, ModuleReference> nameToModule; 92 93 /** 94 * For now, the module references are created eagerly on the assumption 95 * that service binding will require all modules to be located. 96 */ 97 static { 98 long t0 = System.nanoTime(); 99 imageReader = ImageReaderFactory.getImageReader(); 100 101 String[] names = moduleNames(); 102 ModuleDescriptor[] descriptors = descriptors(names); 103 104 int n = names.length; 105 moduleCount.add(n); 106 107 ModuleReference[] mods = new ModuleReference[n]; 108 109 @SuppressWarnings(value = {"rawtypes", "unchecked"}) 110 Entry<String, ModuleReference>[] map 111 = (Entry<String, ModuleReference>[])new Entry[n]; 112 113 for (int i = 0; i < n; i++) { 114 ModuleDescriptor md = descriptors[i]; 115 116 // create the ModuleReference 117 ModuleReference mref = toModuleReference(md, hashSupplier(i, names[i])); 118 119 mods[i] = mref; 120 map[i] = Map.entry(names[i], mref); 121 122 // counters 123 packageCount.add(md.packages().size()); 124 exportsCount.add(md.exports().size()); 125 } 126 127 modules = Set.of(mods); 128 nameToModule = Map.ofEntries(map); 129 130 initTime.addElapsedTimeFrom(t0); 131 } 132 133 /* 134 * Returns an array of ModuleDescriptor of the given module names. 135 * 136 * This obtains ModuleDescriptors from SystemModules class that is generated 137 * from the jlink system-modules plugin. ModuleDescriptors have already 138 * been validated at link time. 139 * 140 * If java.base is patched, or fastpath is disabled for troubleshooting 141 * purpose, it will fall back to find system modules via jrt file system. 142 */ 143 private static ModuleDescriptor[] descriptors(String[] names) { 144 // fastpath is enabled by default. 145 // It can be disabled for troubleshooting purpose. 146 boolean disabled = 147 System.getProperty("jdk.system.module.finder.disabledFastPath") != null; 148 149 // fast loading of ModuleDescriptor of system modules 150 if (isFastPathSupported() && !disabled) 151 return SystemModules.modules(); 152 153 // if fast loading of ModuleDescriptors is disabled 154 // fallback to read module-info.class 155 ModuleDescriptor[] descriptors = new ModuleDescriptor[names.length]; 156 for (int i = 0; i < names.length; i++) { 157 String mn = names[i]; 158 ImageLocation loc = imageReader.findLocation(mn, "module-info.class"); 159 descriptors[i] = ModuleDescriptor.read(imageReader.getResourceBuffer(loc)); 160 161 // add the recorded hashes of tied modules 162 Hashes.add(descriptors[i]); 163 } 164 return descriptors; 165 } 166 167 private static boolean isFastPathSupported() { 168 return SystemModules.MODULE_NAMES.length > 0; 169 } 170 171 private static String[] moduleNames() { 172 if (isFastPathSupported()) 173 // module names recorded at link time 174 return SystemModules.MODULE_NAMES; 175 176 // this happens when java.base is patched with java.base 177 // from an exploded image 178 return imageReader.getModuleNames(); 179 } 180 181 private static ModuleReference toModuleReference(ModuleDescriptor md, 182 HashSupplier hash) 183 { 184 String mn = md.name(); 185 URI uri = JNUA.create("jrt", "/".concat(mn)); 186 187 Supplier<ModuleReader> readerSupplier = new Supplier<>() { 188 @Override 189 public ModuleReader get() { 190 return new ImageModuleReader(mn, uri); 191 } 192 }; 193 194 ModuleReference mref = 195 new ModuleReference(md, uri, readerSupplier, hash); 196 197 // may need a reference to a patched module if --patch-module specified 198 mref = ModuleBootstrap.patcher().patchIfNeeded(mref); 199 200 return mref; 201 } 202 203 private static HashSupplier hashSupplier(int index, String name) { 204 if (isFastPathSupported()) { 205 return new HashSupplier() { 206 @Override 207 public byte[] generate(String algorithm) { 208 return SystemModules.MODULES_TO_HASH[index]; 209 } 210 }; 211 } else { 212 return Hashes.hashFor(name); 213 } 214 } 215 216 /* 217 * This helper class is only used when SystemModules is patched. 218 * It will get the recorded hashes from module-info.class. 219 */ 220 private static class Hashes { 221 static Map<String, byte[]> hashes = new HashMap<>(); 222 223 static void add(ModuleDescriptor descriptor) { 224 Optional<ModuleHashes> ohashes = descriptor.hashes(); 225 if (ohashes.isPresent()) { 226 hashes.putAll(ohashes.get().hashes()); 227 } 228 } 229 230 static HashSupplier hashFor(String name) { 231 if (!hashes.containsKey(name)) 232 return null; 233 234 return new HashSupplier() { 235 @Override 236 public byte[] generate(String algorithm) { 237 return hashes.get(name); 238 } 239 }; 240 } 241 } 242 243 SystemModuleFinder() { } 244 245 @Override 246 public Optional<ModuleReference> find(String name) { 247 Objects.requireNonNull(name); 248 return Optional.ofNullable(nameToModule.get(name)); 249 } 250 251 @Override 252 public Set<ModuleReference> findAll() { 253 return modules; 254 } 255 256 257 /** 258 * A ModuleReader for reading resources from a module linked into the 259 * run-time image. 260 */ 261 static class ImageModuleReader implements ModuleReader { 262 private final String module; 263 private volatile boolean closed; 264 265 /** 266 * If there is a security manager set then check permission to 267 * connect to the run-time image. 268 */ 269 private static void checkPermissionToConnect(URI uri) { 270 SecurityManager sm = System.getSecurityManager(); 271 if (sm != null) { 272 try { 273 URLConnection uc = uri.toURL().openConnection(); 274 sm.checkPermission(uc.getPermission()); 275 } catch (IOException ioe) { | 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 jdk.internal.module; 27 28 import java.io.ByteArrayInputStream; 29 import java.io.IOException; 30 import java.io.InputStream; 31 import java.io.UncheckedIOException; 32 import java.lang.module.ModuleDescriptor; 33 import java.lang.module.ModuleFinder; 34 import java.lang.module.ModuleReader; 35 import java.lang.module.ModuleReference; 36 import java.net.URI; 37 import java.net.URLConnection; 38 import java.nio.ByteBuffer; 39 import java.util.ArrayDeque; 40 import java.util.Collections; 41 import java.util.Deque; 42 import java.util.HashMap; 43 import java.util.Iterator; 44 import java.util.Map; 45 import java.util.Map.Entry; 46 import java.util.Objects; 47 import java.util.Optional; 48 import java.util.Set; 49 import java.util.Spliterator; 50 import java.util.function.Consumer; 51 import java.util.function.Supplier; 52 import java.util.stream.Stream; 53 import java.util.stream.StreamSupport; 54 55 import jdk.internal.jimage.ImageLocation; 56 import jdk.internal.jimage.ImageReader; 57 import jdk.internal.jimage.ImageReaderFactory; 58 import jdk.internal.misc.JavaNetUriAccess; 59 import jdk.internal.misc.SharedSecrets; 60 import jdk.internal.module.ModuleHashes.HashSupplier; 61 import jdk.internal.perf.PerfCounter; 62 63 /** 64 * A {@code ModuleFinder} that finds modules that are linked into the 65 * run-time image. 66 * 67 * The modules linked into the run-time image are assumed to have the 68 * Packages attribute. 69 */ 70 71 public class SystemModuleFinder implements ModuleFinder { 72 73 private static final JavaNetUriAccess JNUA = SharedSecrets.getJavaNetUriAccess(); 74 75 private static final PerfCounter initTime 76 = PerfCounter.newPerfCounter("jdk.module.finder.jimage.initTime"); 77 private static final PerfCounter moduleCount 78 = PerfCounter.newPerfCounter("jdk.module.finder.jimage.modules"); 79 private static final PerfCounter packageCount 80 = PerfCounter.newPerfCounter("jdk.module.finder.jimage.packages"); 81 private static final PerfCounter exportsCount 82 = PerfCounter.newPerfCounter("jdk.module.finder.jimage.exports"); 83 // ImageReader used to access all modules in the image 84 private static final ImageReader imageReader; 85 86 // singleton finder to find modules in the run-time images 87 private static final SystemModuleFinder INSTANCE; 88 89 public static SystemModuleFinder getInstance() { 90 return INSTANCE; 91 } 92 93 /** 94 * For now, the module references are created eagerly on the assumption 95 * that service binding will require all modules to be located. 96 */ 97 static { 98 long t0 = System.nanoTime(); 99 imageReader = ImageReaderFactory.getImageReader(); 100 101 INSTANCE = new SystemModuleFinder(); 102 103 initTime.addElapsedTimeFrom(t0); 104 } 105 106 private static boolean isFastPathSupported() { 107 return SystemModules.MODULE_NAMES.length > 0; 108 } 109 110 private static String[] moduleNames() { 111 if (isFastPathSupported()) 112 // module names recorded at link time 113 return SystemModules.MODULE_NAMES; 114 115 // this happens when java.base is patched with java.base 116 // from an exploded image 117 return imageReader.getModuleNames(); 118 } 119 120 121 /** 122 * Helper class to use the recorded hashes to create a HashSupplier 123 */ 124 private static class Hashes { 125 static Map<String, byte[]> hashes = new HashMap<>(); 126 127 static void add(ModuleHashes recordedHashes) { 128 if (recordedHashes != null) { 129 hashes.putAll(recordedHashes.hashes()); 130 } 131 } 132 133 static HashSupplier hashSupplierFor(String name) { 134 if (!hashes.containsKey(name)) 135 return null; 136 137 return new HashSupplier() { 138 @Override 139 public byte[] generate(String algorithm) { 140 return hashes.get(name); 141 } 142 }; 143 } 144 } 145 146 // the set of modules in the run-time image 147 private final Set<ModuleReference> modules; 148 149 // maps module name to module reference 150 private final Map<String, ModuleReference> nameToModule; 151 152 private SystemModuleFinder() { 153 String[] names = moduleNames(); 154 int n = names.length; 155 moduleCount.add(n); 156 157 // fastpath is enabled by default. 158 // It can be disabled for troubleshooting purpose. 159 boolean disabled = 160 System.getProperty("jdk.system.module.finder.disabledFastPath") != null; 161 162 ModuleDescriptor[] descriptors; 163 ModuleHashes[] recordedHashes; 164 ModuleResolution[] moduleResolutions; 165 166 // fast loading of ModuleDescriptor of system modules 167 if (isFastPathSupported() && !disabled) { 168 descriptors = SystemModules.descriptors(); 169 recordedHashes = SystemModules.hashes(); 170 moduleResolutions = SystemModules.moduleResolutions(); 171 } else { 172 // if fast loading of ModuleDescriptors is disabled 173 // fallback to read module-info.class 174 descriptors = new ModuleDescriptor[n]; 175 recordedHashes = new ModuleHashes[n]; 176 moduleResolutions = new ModuleResolution[n]; 177 for (int i = 0; i < names.length; i++) { 178 String mn = names[i]; 179 ImageLocation loc = imageReader.findLocation(mn, "module-info.class"); 180 ModuleInfo.Attributes attrs = 181 ModuleInfo.read(imageReader.getResourceBuffer(loc), null); 182 descriptors[i] = attrs.descriptor(); 183 recordedHashes[i] = attrs.recordedHashes(); 184 moduleResolutions[i] = attrs.moduleResolution(); 185 } 186 } 187 188 // record the hashes to build HashSupplier 189 for (ModuleHashes mh : recordedHashes) { 190 Hashes.add(mh); 191 } 192 193 ModuleReference[] mods = new ModuleReference[n]; 194 195 @SuppressWarnings(value = {"rawtypes", "unchecked"}) 196 Entry<String, ModuleReference>[] map 197 = (Entry<String, ModuleReference>[])new Entry[n]; 198 199 for (int i = 0; i < n; i++) { 200 ModuleDescriptor md = descriptors[i]; 201 202 // create the ModuleReference 203 ModuleReference mref = toModuleReference(md, 204 recordedHashes[i], 205 Hashes.hashSupplierFor(names[i]), 206 moduleResolutions[i]); 207 mods[i] = mref; 208 map[i] = Map.entry(names[i], mref); 209 210 // counters 211 packageCount.add(md.packages().size()); 212 exportsCount.add(md.exports().size()); 213 } 214 215 modules = Set.of(mods); 216 nameToModule = Map.ofEntries(map); 217 } 218 219 @Override 220 public Optional<ModuleReference> find(String name) { 221 Objects.requireNonNull(name); 222 return Optional.ofNullable(nameToModule.get(name)); 223 } 224 225 @Override 226 public Set<ModuleReference> findAll() { 227 return modules; 228 } 229 230 private ModuleReference toModuleReference(ModuleDescriptor md, 231 ModuleHashes recordedHashes, 232 HashSupplier hasher, 233 ModuleResolution mres) { 234 String mn = md.name(); 235 URI uri = JNUA.create("jrt", "/".concat(mn)); 236 237 Supplier<ModuleReader> readerSupplier = new Supplier<>() { 238 @Override 239 public ModuleReader get() { 240 return new ImageModuleReader(mn, uri); 241 } 242 }; 243 244 ModuleReference mref = 245 new ModuleReferenceImpl(md, uri, readerSupplier, null, 246 recordedHashes, hasher, mres); 247 248 // may need a reference to a patched module if --patch-module specified 249 mref = ModuleBootstrap.patcher().patchIfNeeded(mref); 250 251 return mref; 252 } 253 254 255 /** 256 * A ModuleReader for reading resources from a module linked into the 257 * run-time image. 258 */ 259 static class ImageModuleReader implements ModuleReader { 260 private final String module; 261 private volatile boolean closed; 262 263 /** 264 * If there is a security manager set then check permission to 265 * connect to the run-time image. 266 */ 267 private static void checkPermissionToConnect(URI uri) { 268 SecurityManager sm = System.getSecurityManager(); 269 if (sm != null) { 270 try { 271 URLConnection uc = uri.toURL().openConnection(); 272 sm.checkPermission(uc.getPermission()); 273 } catch (IOException ioe) { |