1 /* 2 * Copyright (c) 2015, 2016, 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.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.Collections; 36 import java.util.HashMap; 37 import java.util.HashSet; 38 import java.util.Map; 39 import java.util.Objects; 40 import java.util.Optional; 41 import java.util.Set; 42 import java.util.function.Supplier; 43 44 import jdk.internal.jimage.ImageLocation; 45 import jdk.internal.jimage.ImageReader; 46 import jdk.internal.jimage.ImageReaderFactory; 47 import jdk.internal.misc.JavaNetAccess; 48 import jdk.internal.misc.SharedSecrets; 49 import jdk.internal.module.ModuleHashes; 50 import jdk.internal.module.ModuleHashes.HashSupplier; 51 import jdk.internal.module.SystemModules; 52 import jdk.internal.module.ModulePatcher; 53 import jdk.internal.perf.PerfCounter; 54 55 /** 56 * A {@code ModuleFinder} that finds modules that are linked into the 57 * run-time image. 58 * 59 * The modules linked into the run-time image are assumed to have the 60 * ConcealedPackages attribute. 61 */ 62 63 class SystemModuleFinder implements ModuleFinder { 64 65 private static final PerfCounter initTime 66 = PerfCounter.newPerfCounter("jdk.module.finder.jimage.initTime"); 67 private static final PerfCounter moduleCount 68 = PerfCounter.newPerfCounter("jdk.module.finder.jimage.modules"); 69 private static final PerfCounter packageCount 70 = PerfCounter.newPerfCounter("jdk.module.finder.jimage.packages"); 71 private static final PerfCounter exportsCount 72 = PerfCounter.newPerfCounter("jdk.module.finder.jimage.exports"); 73 // ImageReader used to access all modules in the image 74 private static final ImageReader imageReader; 75 76 private static final JavaNetAccess jna = SharedSecrets.getJavaNetAccess(); 77 78 // the set of modules in the run-time image 79 private static final Set<ModuleReference> modules; 80 81 // maps module name to module reference 82 private static final Map<String, ModuleReference> nameToModule; 83 84 /** 85 * For now, the module references are created eagerly on the assumption 86 * that service binding will require all modules to be located. 87 */ 88 static { 89 long t0 = System.nanoTime(); 90 imageReader = ImageReaderFactory.getImageReader(); 91 92 String[] names = moduleNames(); 93 ModuleDescriptor[] descriptors = descriptors(names); 94 95 int n = names.length; 96 moduleCount.add(n); 97 98 Set<ModuleReference> mods = new HashSet<>(n); 99 Map<String, ModuleReference> map = new HashMap<>(n); 100 101 for (int i = 0; i < n; i++) { 102 ModuleDescriptor md = descriptors[i]; 103 104 // create the ModuleReference 105 ModuleReference mref = toModuleReference(md, hashSupplier(i, names[i])); 106 107 mods.add(mref); 108 map.put(names[i], mref); 109 110 // counters 111 packageCount.add(md.packages().size()); 112 exportsCount.add(md.exports().size()); 113 } 114 115 modules = Collections.unmodifiableSet(mods); 116 nameToModule = map; 117 118 initTime.addElapsedTimeFrom(t0); 119 } 120 121 /* 122 * Returns an array of ModuleDescriptor of the given module names. 123 * 124 * This obtains ModuleDescriptors from SystemModules class that is generated 125 * from the jlink system-modules plugin. ModuleDescriptors have already 126 * been validated at link time. 127 * 128 * If java.base is patched, or fastpath is disabled for troubleshooting 129 * purpose, it will fall back to find system modules via jrt file system. 130 */ 131 private static ModuleDescriptor[] descriptors(String[] names) { 132 // fastpath is enabled by default. 133 // It can be disabled for troubleshooting purpose. 134 boolean disabled = 135 System.getProperty("jdk.system.module.finder.disabledFastPath") != null; 136 137 // fast loading of ModuleDescriptor of system modules 138 if (isFastPathSupported() && !disabled) 139 return SystemModules.modules(); 140 141 // if fast loading of ModuleDescriptors is disabled 142 // fallback to read module-info.class 143 ModuleDescriptor[] descriptors = new ModuleDescriptor[names.length]; 144 for (int i = 0; i < names.length; i++) { 145 String mn = names[i]; 146 ImageLocation loc = imageReader.findLocation(mn, "module-info.class"); 147 descriptors[i] = ModuleDescriptor.read(imageReader.getResourceBuffer(loc)); 148 149 // add the recorded hashes of tied modules 150 Hashes.add(descriptors[i]); 151 } 152 return descriptors; 153 } 154 155 private static boolean isFastPathSupported() { 156 return SystemModules.MODULE_NAMES.length > 0; 157 } 158 159 private static String[] moduleNames() { 160 if (isFastPathSupported()) 161 // module names recorded at link time 162 return SystemModules.MODULE_NAMES; 163 164 // this happens when java.base is patched with java.base 165 // from an exploded image 166 return imageReader.getModuleNames(); 167 } 168 169 private static ModuleReference toModuleReference(ModuleDescriptor md, 170 HashSupplier hash) 171 { 172 String mn = md.name(); 173 174 URI uri = jna.createURI("jrt", "/".concat(mn)); 175 176 Supplier<ModuleReader> readerSupplier = new Supplier<>() { 177 @Override 178 public ModuleReader get() { 179 return new ImageModuleReader(mn, uri); 180 } 181 }; 182 183 ModuleReference mref = 184 new ModuleReference(md, uri, readerSupplier, hash); 185 186 // may need a reference to a patched module if --patch-module specified 187 mref = ModulePatcher.interposeIfNeeded(mref); 188 189 return mref; 190 } 191 192 private static HashSupplier hashSupplier(int index, String name) { 193 if (isFastPathSupported()) { 194 return new HashSupplier() { 195 @Override 196 public String generate(String algorithm) { 197 return SystemModules.MODULES_TO_HASH[index]; 198 } 199 }; 200 } else { 201 return Hashes.hashFor(name); 202 } 203 } 204 205 /* 206 * This helper class is only used when SystemModules is patched. 207 * It will get the recorded hashes from module-info.class. 208 */ 209 private static class Hashes { 210 static Map<String, String> hashes = new HashMap<>(); 211 212 static void add(ModuleDescriptor descriptor) { 213 Optional<ModuleHashes> ohashes = descriptor.hashes(); 214 if (ohashes.isPresent()) { 215 hashes.putAll(ohashes.get().hashes()); 216 } 217 } 218 219 static HashSupplier hashFor(String name) { 220 if (!hashes.containsKey(name)) 221 return null; 222 223 return new HashSupplier() { 224 @Override 225 public String generate(String algorithm) { 226 return hashes.get(name); 227 } 228 }; 229 } 230 } 231 232 SystemModuleFinder() { } 233 234 @Override 235 public Optional<ModuleReference> find(String name) { 236 Objects.requireNonNull(name); 237 return Optional.ofNullable(nameToModule.get(name)); 238 } 239 240 @Override 241 public Set<ModuleReference> findAll() { 242 return modules; 243 } 244 245 246 /** 247 * A ModuleReader for reading resources from a module linked into the 248 * run-time image. 249 */ 250 static class ImageModuleReader implements ModuleReader { 251 private final String module; 252 private volatile boolean closed; 253 254 /** 255 * If there is a security manager set then check permission to 256 * connect to the run-time image. 257 */ 258 private static void checkPermissionToConnect(URI uri) { 259 SecurityManager sm = System.getSecurityManager(); 260 if (sm != null) { 261 try { 262 URLConnection uc = uri.toURL().openConnection(); 263 sm.checkPermission(uc.getPermission()); 264 } catch (IOException ioe) { 265 throw new UncheckedIOException(ioe); 266 } 267 } 268 } 269 270 ImageModuleReader(String module, URI uri) { 271 checkPermissionToConnect(uri); 272 this.module = module; 273 } 274 275 /** 276 * Returns the ImageLocation for the given resource, {@code null} 277 * if not found. 278 */ 279 private ImageLocation findImageLocation(String name) throws IOException { 280 Objects.requireNonNull(name); 281 if (closed) 282 throw new IOException("ModuleReader is closed"); 283 if (imageReader != null) { 284 return imageReader.findLocation(module, name); 285 } else { 286 // not an images build 287 return null; 288 } 289 } 290 291 @Override 292 public Optional<URI> find(String name) throws IOException { 293 ImageLocation location = findImageLocation(name); 294 if (location != null) { 295 URI u = URI.create("jrt:/" + module + "/" + name); 296 return Optional.of(u); 297 } else { 298 return Optional.empty(); 299 } 300 } 301 302 @Override 303 public Optional<InputStream> open(String name) throws IOException { 304 return read(name).map(this::toInputStream); 305 } 306 307 private InputStream toInputStream(ByteBuffer bb) { // ## -> ByteBuffer? 308 try { 309 int rem = bb.remaining(); 310 byte[] bytes = new byte[rem]; 311 bb.get(bytes); 312 return new ByteArrayInputStream(bytes); 313 } finally { 314 release(bb); 315 } 316 } 317 318 @Override 319 public Optional<ByteBuffer> read(String name) throws IOException { 320 ImageLocation location = findImageLocation(name); 321 if (location != null) { 322 return Optional.of(imageReader.getResourceBuffer(location)); 323 } else { 324 return Optional.empty(); 325 } 326 } 327 328 @Override 329 public void release(ByteBuffer bb) { 330 Objects.requireNonNull(bb); 331 ImageReader.releaseByteBuffer(bb); 332 } 333 334 @Override 335 public void close() { 336 // nothing else to do 337 closed = true; 338 } 339 } 340 341 }