Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/jdk/internal/module/SystemModuleFinders.java
41159 views
1
/*
2
* Copyright (c) 2015, 2021, 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
package jdk.internal.module;
26
27
import java.io.ByteArrayInputStream;
28
import java.io.IOException;
29
import java.io.InputStream;
30
import java.io.UncheckedIOException;
31
import java.lang.module.ModuleDescriptor;
32
import java.lang.module.ModuleFinder;
33
import java.lang.module.ModuleReader;
34
import java.lang.module.ModuleReference;
35
import java.lang.reflect.Constructor;
36
import java.net.URI;
37
import java.net.URLConnection;
38
import java.nio.ByteBuffer;
39
import java.nio.file.Files;
40
import java.nio.file.Path;
41
import java.security.AccessController;
42
import java.security.PrivilegedAction;
43
import java.util.ArrayDeque;
44
import java.util.Collections;
45
import java.util.Deque;
46
import java.util.HashMap;
47
import java.util.HashSet;
48
import java.util.Iterator;
49
import java.util.Map;
50
import java.util.Objects;
51
import java.util.Optional;
52
import java.util.Set;
53
import java.util.Spliterator;
54
import java.util.function.Consumer;
55
import java.util.function.Supplier;
56
import java.util.stream.Stream;
57
import java.util.stream.StreamSupport;
58
59
import jdk.internal.jimage.ImageLocation;
60
import jdk.internal.jimage.ImageReader;
61
import jdk.internal.jimage.ImageReaderFactory;
62
import jdk.internal.access.JavaNetUriAccess;
63
import jdk.internal.access.SharedSecrets;
64
import jdk.internal.util.StaticProperty;
65
import jdk.internal.module.ModuleHashes.HashSupplier;
66
67
/**
68
* The factory for SystemModules objects and for creating ModuleFinder objects
69
* that find modules in the runtime image.
70
*
71
* This class supports initializing the module system when the runtime is an
72
* images build, an exploded build, or an images build with java.base patched
73
* by an exploded java.base. It also supports a testing mode that re-parses
74
* the module-info.class resources in the run-time image.
75
*/
76
77
public final class SystemModuleFinders {
78
private static final JavaNetUriAccess JNUA = SharedSecrets.getJavaNetUriAccess();
79
80
private static final boolean USE_FAST_PATH;
81
static {
82
String value = System.getProperty("jdk.system.module.finder.disableFastPath");
83
if (value == null) {
84
USE_FAST_PATH = true;
85
} else {
86
USE_FAST_PATH = !value.isEmpty() && !Boolean.parseBoolean(value);
87
}
88
}
89
90
// cached ModuleFinder returned from ofSystem
91
private static volatile ModuleFinder cachedSystemModuleFinder;
92
93
private SystemModuleFinders() { }
94
95
/**
96
* Returns the SystemModules object to reconstitute all modules. Returns
97
* null if this is an exploded build or java.base is patched by an exploded
98
* build.
99
*/
100
static SystemModules allSystemModules() {
101
if (USE_FAST_PATH) {
102
return SystemModulesMap.allSystemModules();
103
} else {
104
return null;
105
}
106
}
107
108
/**
109
* Returns a SystemModules object to reconstitute the modules for the
110
* given initial module. If the initial module is null then return the
111
* SystemModules object to reconstitute the default modules.
112
*
113
* Return null if there is no SystemModules class for the initial module,
114
* this is an exploded build, or java.base is patched by an exploded build.
115
*/
116
static SystemModules systemModules(String initialModule) {
117
if (USE_FAST_PATH) {
118
if (initialModule == null) {
119
return SystemModulesMap.defaultSystemModules();
120
}
121
122
String[] initialModules = SystemModulesMap.moduleNames();
123
for (int i = 0; i < initialModules.length; i++) {
124
String moduleName = initialModules[i];
125
if (initialModule.equals(moduleName)) {
126
String cn = SystemModulesMap.classNames()[i];
127
try {
128
// one-arg Class.forName as java.base may not be defined
129
Constructor<?> ctor = Class.forName(cn).getConstructor();
130
return (SystemModules) ctor.newInstance();
131
} catch (Exception e) {
132
throw new InternalError(e);
133
}
134
}
135
}
136
}
137
return null;
138
}
139
140
/**
141
* Returns a ModuleFinder that is backed by the given SystemModules object.
142
*
143
* @apiNote The returned ModuleFinder is thread safe.
144
*/
145
static ModuleFinder of(SystemModules systemModules) {
146
ModuleDescriptor[] descriptors = systemModules.moduleDescriptors();
147
ModuleTarget[] targets = systemModules.moduleTargets();
148
ModuleHashes[] recordedHashes = systemModules.moduleHashes();
149
ModuleResolution[] moduleResolutions = systemModules.moduleResolutions();
150
151
int moduleCount = descriptors.length;
152
ModuleReference[] mrefs = new ModuleReference[moduleCount];
153
@SuppressWarnings(value = {"rawtypes", "unchecked"})
154
Map.Entry<String, ModuleReference>[] map
155
= (Map.Entry<String, ModuleReference>[])new Map.Entry[moduleCount];
156
157
Map<String, byte[]> nameToHash = generateNameToHash(recordedHashes);
158
159
for (int i = 0; i < moduleCount; i++) {
160
String name = descriptors[i].name();
161
HashSupplier hashSupplier = hashSupplier(nameToHash, name);
162
ModuleReference mref = toModuleReference(descriptors[i],
163
targets[i],
164
recordedHashes[i],
165
hashSupplier,
166
moduleResolutions[i]);
167
mrefs[i] = mref;
168
map[i] = Map.entry(name, mref);
169
}
170
171
return new SystemModuleFinder(mrefs, map);
172
}
173
174
/**
175
* Returns the ModuleFinder to find all system modules. Supports both
176
* images and exploded builds.
177
*
178
* @apiNote Used by ModuleFinder.ofSystem()
179
*/
180
public static ModuleFinder ofSystem() {
181
ModuleFinder finder = cachedSystemModuleFinder;
182
if (finder != null) {
183
return finder;
184
}
185
186
// probe to see if this is an images build
187
String home = StaticProperty.javaHome();
188
Path modules = Path.of(home, "lib", "modules");
189
if (Files.isRegularFile(modules)) {
190
if (USE_FAST_PATH) {
191
SystemModules systemModules = allSystemModules();
192
if (systemModules != null) {
193
finder = of(systemModules);
194
}
195
}
196
197
// fall back to parsing the module-info.class files in image
198
if (finder == null) {
199
finder = ofModuleInfos();
200
}
201
202
cachedSystemModuleFinder = finder;
203
return finder;
204
205
}
206
207
// exploded build (do not cache module finder)
208
Path dir = Path.of(home, "modules");
209
if (!Files.isDirectory(dir))
210
throw new InternalError("Unable to detect the run-time image");
211
ModuleFinder f = ModulePath.of(ModuleBootstrap.patcher(), dir);
212
return new ModuleFinder() {
213
@SuppressWarnings("removal")
214
@Override
215
public Optional<ModuleReference> find(String name) {
216
PrivilegedAction<Optional<ModuleReference>> pa = () -> f.find(name);
217
return AccessController.doPrivileged(pa);
218
}
219
@SuppressWarnings("removal")
220
@Override
221
public Set<ModuleReference> findAll() {
222
PrivilegedAction<Set<ModuleReference>> pa = f::findAll;
223
return AccessController.doPrivileged(pa);
224
}
225
};
226
}
227
228
/**
229
* Parses the module-info.class of all module in the runtime image and
230
* returns a ModuleFinder to find the modules.
231
*
232
* @apiNote The returned ModuleFinder is thread safe.
233
*/
234
private static ModuleFinder ofModuleInfos() {
235
// parse the module-info.class in every module
236
Map<String, ModuleInfo.Attributes> nameToAttributes = new HashMap<>();
237
Map<String, byte[]> nameToHash = new HashMap<>();
238
ImageReader reader = SystemImage.reader();
239
for (String mn : reader.getModuleNames()) {
240
ImageLocation loc = reader.findLocation(mn, "module-info.class");
241
ModuleInfo.Attributes attrs
242
= ModuleInfo.read(reader.getResourceBuffer(loc), null);
243
244
nameToAttributes.put(mn, attrs);
245
ModuleHashes hashes = attrs.recordedHashes();
246
if (hashes != null) {
247
for (String name : hashes.names()) {
248
nameToHash.computeIfAbsent(name, k -> hashes.hashFor(name));
249
}
250
}
251
}
252
253
// create a ModuleReference for each module
254
Set<ModuleReference> mrefs = new HashSet<>();
255
Map<String, ModuleReference> nameToModule = new HashMap<>();
256
for (Map.Entry<String, ModuleInfo.Attributes> e : nameToAttributes.entrySet()) {
257
String mn = e.getKey();
258
ModuleInfo.Attributes attrs = e.getValue();
259
HashSupplier hashSupplier = hashSupplier(nameToHash, mn);
260
ModuleReference mref = toModuleReference(attrs.descriptor(),
261
attrs.target(),
262
attrs.recordedHashes(),
263
hashSupplier,
264
attrs.moduleResolution());
265
mrefs.add(mref);
266
nameToModule.put(mn, mref);
267
}
268
269
return new SystemModuleFinder(mrefs, nameToModule);
270
}
271
272
/**
273
* A ModuleFinder that finds module in an array or set of modules.
274
*/
275
private static class SystemModuleFinder implements ModuleFinder {
276
final Set<ModuleReference> mrefs;
277
final Map<String, ModuleReference> nameToModule;
278
279
SystemModuleFinder(ModuleReference[] array,
280
Map.Entry<String, ModuleReference>[] map) {
281
this.mrefs = Set.of(array);
282
this.nameToModule = Map.ofEntries(map);
283
}
284
285
SystemModuleFinder(Set<ModuleReference> mrefs,
286
Map<String, ModuleReference> nameToModule) {
287
this.mrefs = Set.copyOf(mrefs);
288
this.nameToModule = Map.copyOf(nameToModule);
289
}
290
291
@Override
292
public Optional<ModuleReference> find(String name) {
293
Objects.requireNonNull(name);
294
return Optional.ofNullable(nameToModule.get(name));
295
}
296
297
@Override
298
public Set<ModuleReference> findAll() {
299
return mrefs;
300
}
301
}
302
303
/**
304
* Creates a ModuleReference to the system module.
305
*/
306
static ModuleReference toModuleReference(ModuleDescriptor descriptor,
307
ModuleTarget target,
308
ModuleHashes recordedHashes,
309
HashSupplier hasher,
310
ModuleResolution mres) {
311
String mn = descriptor.name();
312
URI uri = JNUA.create("jrt", "/".concat(mn));
313
314
Supplier<ModuleReader> readerSupplier = new Supplier<>() {
315
@Override
316
public ModuleReader get() {
317
return new SystemModuleReader(mn, uri);
318
}
319
};
320
321
ModuleReference mref = new ModuleReferenceImpl(descriptor,
322
uri,
323
readerSupplier,
324
null,
325
target,
326
recordedHashes,
327
hasher,
328
mres);
329
330
// may need a reference to a patched module if --patch-module specified
331
mref = ModuleBootstrap.patcher().patchIfNeeded(mref);
332
333
return mref;
334
}
335
336
/**
337
* Generates a map of module name to hash value.
338
*/
339
static Map<String, byte[]> generateNameToHash(ModuleHashes[] recordedHashes) {
340
Map<String, byte[]> nameToHash = null;
341
342
boolean secondSeen = false;
343
// record the hashes to build HashSupplier
344
for (ModuleHashes mh : recordedHashes) {
345
if (mh != null) {
346
// if only one module contain ModuleHashes, use it
347
if (nameToHash == null) {
348
nameToHash = mh.hashes();
349
} else {
350
if (!secondSeen) {
351
nameToHash = new HashMap<>(nameToHash);
352
secondSeen = true;
353
}
354
nameToHash.putAll(mh.hashes());
355
}
356
}
357
}
358
return (nameToHash != null) ? nameToHash : Map.of();
359
}
360
361
/**
362
* Returns a HashSupplier that returns the hash of the given module.
363
*/
364
static HashSupplier hashSupplier(Map<String, byte[]> nameToHash, String name) {
365
byte[] hash = nameToHash.get(name);
366
if (hash != null) {
367
// avoid lambda here
368
return new HashSupplier() {
369
@Override
370
public byte[] generate(String algorithm) {
371
return hash;
372
}
373
};
374
} else {
375
return null;
376
}
377
}
378
379
/**
380
* Holder class for the ImageReader
381
*
382
* @apiNote This class must be loaded before a security manager is set.
383
*/
384
private static class SystemImage {
385
static final ImageReader READER = ImageReaderFactory.getImageReader();
386
static ImageReader reader() {
387
return READER;
388
}
389
}
390
391
/**
392
* A ModuleReader for reading resources from a module linked into the
393
* run-time image.
394
*/
395
private static class SystemModuleReader implements ModuleReader {
396
private final String module;
397
private volatile boolean closed;
398
399
/**
400
* If there is a security manager set then check permission to
401
* connect to the run-time image.
402
*/
403
private static void checkPermissionToConnect(URI uri) {
404
@SuppressWarnings("removal")
405
SecurityManager sm = System.getSecurityManager();
406
if (sm != null) {
407
try {
408
URLConnection uc = uri.toURL().openConnection();
409
sm.checkPermission(uc.getPermission());
410
} catch (IOException ioe) {
411
throw new UncheckedIOException(ioe);
412
}
413
}
414
}
415
416
SystemModuleReader(String module, URI uri) {
417
checkPermissionToConnect(uri);
418
this.module = module;
419
}
420
421
/**
422
* Returns the ImageLocation for the given resource, {@code null}
423
* if not found.
424
*/
425
private ImageLocation findImageLocation(String name) throws IOException {
426
Objects.requireNonNull(name);
427
if (closed)
428
throw new IOException("ModuleReader is closed");
429
ImageReader imageReader = SystemImage.reader();
430
if (imageReader != null) {
431
return imageReader.findLocation(module, name);
432
} else {
433
// not an images build
434
return null;
435
}
436
}
437
438
/**
439
* Returns {@code true} if the given resource exists, {@code false}
440
* if not found.
441
*/
442
private boolean containsImageLocation(String name) throws IOException {
443
Objects.requireNonNull(name);
444
if (closed)
445
throw new IOException("ModuleReader is closed");
446
ImageReader imageReader = SystemImage.reader();
447
if (imageReader != null) {
448
return imageReader.verifyLocation(module, name);
449
} else {
450
// not an images build
451
return false;
452
}
453
}
454
455
@Override
456
public Optional<URI> find(String name) throws IOException {
457
if (containsImageLocation(name)) {
458
URI u = JNUA.create("jrt", "/" + module + "/" + name);
459
return Optional.of(u);
460
} else {
461
return Optional.empty();
462
}
463
}
464
465
@Override
466
public Optional<InputStream> open(String name) throws IOException {
467
return read(name).map(this::toInputStream);
468
}
469
470
private InputStream toInputStream(ByteBuffer bb) { // ## -> ByteBuffer?
471
try {
472
int rem = bb.remaining();
473
byte[] bytes = new byte[rem];
474
bb.get(bytes);
475
return new ByteArrayInputStream(bytes);
476
} finally {
477
release(bb);
478
}
479
}
480
481
@Override
482
public Optional<ByteBuffer> read(String name) throws IOException {
483
ImageLocation location = findImageLocation(name);
484
if (location != null) {
485
return Optional.of(SystemImage.reader().getResourceBuffer(location));
486
} else {
487
return Optional.empty();
488
}
489
}
490
491
@Override
492
public void release(ByteBuffer bb) {
493
Objects.requireNonNull(bb);
494
ImageReader.releaseByteBuffer(bb);
495
}
496
497
@Override
498
public Stream<String> list() throws IOException {
499
if (closed)
500
throw new IOException("ModuleReader is closed");
501
502
Spliterator<String> s = new ModuleContentSpliterator(module);
503
return StreamSupport.stream(s, false);
504
}
505
506
@Override
507
public void close() {
508
// nothing else to do
509
closed = true;
510
}
511
}
512
513
/**
514
* A Spliterator for traversing the resources of a module linked into the
515
* run-time image.
516
*/
517
private static class ModuleContentSpliterator implements Spliterator<String> {
518
final String moduleRoot;
519
final Deque<ImageReader.Node> stack;
520
Iterator<ImageReader.Node> iterator;
521
522
ModuleContentSpliterator(String module) throws IOException {
523
moduleRoot = "/modules/" + module;
524
stack = new ArrayDeque<>();
525
526
// push the root node to the stack to get started
527
ImageReader.Node dir = SystemImage.reader().findNode(moduleRoot);
528
if (dir == null || !dir.isDirectory())
529
throw new IOException(moduleRoot + " not a directory");
530
stack.push(dir);
531
iterator = Collections.emptyIterator();
532
}
533
534
/**
535
* Returns the name of the next non-directory node or {@code null} if
536
* there are no remaining nodes to visit.
537
*/
538
private String next() throws IOException {
539
for (;;) {
540
while (iterator.hasNext()) {
541
ImageReader.Node node = iterator.next();
542
String name = node.getName();
543
if (node.isDirectory()) {
544
// build node
545
ImageReader.Node dir = SystemImage.reader().findNode(name);
546
assert dir.isDirectory();
547
stack.push(dir);
548
} else {
549
// strip /modules/$MODULE/ prefix
550
return name.substring(moduleRoot.length() + 1);
551
}
552
}
553
554
if (stack.isEmpty()) {
555
return null;
556
} else {
557
ImageReader.Node dir = stack.poll();
558
assert dir.isDirectory();
559
iterator = dir.getChildren().iterator();
560
}
561
}
562
}
563
564
@Override
565
public boolean tryAdvance(Consumer<? super String> action) {
566
String next;
567
try {
568
next = next();
569
} catch (IOException ioe) {
570
throw new UncheckedIOException(ioe);
571
}
572
if (next != null) {
573
action.accept(next);
574
return true;
575
} else {
576
return false;
577
}
578
}
579
580
@Override
581
public Spliterator<String> trySplit() {
582
return null;
583
}
584
585
@Override
586
public int characteristics() {
587
return Spliterator.DISTINCT + Spliterator.NONNULL + Spliterator.IMMUTABLE;
588
}
589
590
@Override
591
public long estimateSize() {
592
return Long.MAX_VALUE;
593
}
594
}
595
}
596
597