Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.instrument/share/classes/sun/instrument/InstrumentationImpl.java
41153 views
1
/*
2
* Copyright (c) 2003, 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
26
package sun.instrument;
27
28
import java.lang.instrument.UnmodifiableModuleException;
29
import java.lang.reflect.Method;
30
import java.lang.reflect.Modifier;
31
import java.lang.reflect.AccessibleObject;
32
import java.lang.instrument.ClassFileTransformer;
33
import java.lang.instrument.ClassDefinition;
34
import java.lang.instrument.Instrumentation;
35
import java.security.AccessController;
36
import java.security.PrivilegedAction;
37
import java.security.ProtectionDomain;
38
import java.util.Collections;
39
import java.util.ArrayList;
40
import java.util.HashMap;
41
import java.util.HashSet;
42
import java.util.List;
43
import java.util.Map;
44
import java.util.Set;
45
import java.util.jar.JarFile;
46
47
import jdk.internal.module.Modules;
48
import jdk.internal.vm.annotation.IntrinsicCandidate;
49
50
/*
51
* Copyright 2003 Wily Technology, Inc.
52
*/
53
54
/**
55
* The Java side of the JPLIS implementation. Works in concert with a native JVMTI agent
56
* to implement the JPLIS API set. Provides both the Java API implementation of
57
* the Instrumentation interface and utility Java routines to support the native code.
58
* Keeps a pointer to the native data structure in a scalar field to allow native
59
* processing behind native methods.
60
*/
61
public class InstrumentationImpl implements Instrumentation {
62
private final TransformerManager mTransformerManager;
63
private TransformerManager mRetransfomableTransformerManager;
64
// needs to store a native pointer, so use 64 bits
65
private final long mNativeAgent;
66
private final boolean mEnvironmentSupportsRedefineClasses;
67
private volatile boolean mEnvironmentSupportsRetransformClassesKnown;
68
private volatile boolean mEnvironmentSupportsRetransformClasses;
69
private final boolean mEnvironmentSupportsNativeMethodPrefix;
70
71
private
72
InstrumentationImpl(long nativeAgent,
73
boolean environmentSupportsRedefineClasses,
74
boolean environmentSupportsNativeMethodPrefix) {
75
mTransformerManager = new TransformerManager(false);
76
mRetransfomableTransformerManager = null;
77
mNativeAgent = nativeAgent;
78
mEnvironmentSupportsRedefineClasses = environmentSupportsRedefineClasses;
79
mEnvironmentSupportsRetransformClassesKnown = false; // false = need to ask
80
mEnvironmentSupportsRetransformClasses = false; // don't know yet
81
mEnvironmentSupportsNativeMethodPrefix = environmentSupportsNativeMethodPrefix;
82
}
83
84
public void
85
addTransformer(ClassFileTransformer transformer) {
86
addTransformer(transformer, false);
87
}
88
89
public synchronized void
90
addTransformer(ClassFileTransformer transformer, boolean canRetransform) {
91
if (transformer == null) {
92
throw new NullPointerException("null passed as 'transformer' in addTransformer");
93
}
94
if (canRetransform) {
95
if (!isRetransformClassesSupported()) {
96
throw new UnsupportedOperationException(
97
"adding retransformable transformers is not supported in this environment");
98
}
99
if (mRetransfomableTransformerManager == null) {
100
mRetransfomableTransformerManager = new TransformerManager(true);
101
}
102
mRetransfomableTransformerManager.addTransformer(transformer);
103
if (mRetransfomableTransformerManager.getTransformerCount() == 1) {
104
setHasRetransformableTransformers(mNativeAgent, true);
105
}
106
} else {
107
mTransformerManager.addTransformer(transformer);
108
if (mTransformerManager.getTransformerCount() == 1) {
109
setHasTransformers(mNativeAgent, true);
110
}
111
}
112
}
113
114
public synchronized boolean
115
removeTransformer(ClassFileTransformer transformer) {
116
if (transformer == null) {
117
throw new NullPointerException("null passed as 'transformer' in removeTransformer");
118
}
119
TransformerManager mgr = findTransformerManager(transformer);
120
if (mgr != null) {
121
mgr.removeTransformer(transformer);
122
if (mgr.getTransformerCount() == 0) {
123
if (mgr.isRetransformable()) {
124
setHasRetransformableTransformers(mNativeAgent, false);
125
} else {
126
setHasTransformers(mNativeAgent, false);
127
}
128
}
129
return true;
130
}
131
return false;
132
}
133
134
public boolean
135
isModifiableClass(Class<?> theClass) {
136
if (theClass == null) {
137
throw new NullPointerException(
138
"null passed as 'theClass' in isModifiableClass");
139
}
140
return isModifiableClass0(mNativeAgent, theClass);
141
}
142
143
public boolean isModifiableModule(Module module) {
144
if (module == null) {
145
throw new NullPointerException("'module' is null");
146
}
147
return true;
148
}
149
150
public boolean
151
isRetransformClassesSupported() {
152
// ask lazily since there is some overhead
153
if (!mEnvironmentSupportsRetransformClassesKnown) {
154
mEnvironmentSupportsRetransformClasses = isRetransformClassesSupported0(mNativeAgent);
155
mEnvironmentSupportsRetransformClassesKnown = true;
156
}
157
return mEnvironmentSupportsRetransformClasses;
158
}
159
160
public void
161
retransformClasses(Class<?>... classes) {
162
if (!isRetransformClassesSupported()) {
163
throw new UnsupportedOperationException(
164
"retransformClasses is not supported in this environment");
165
}
166
if (classes.length == 0) {
167
return; // no-op
168
}
169
retransformClasses0(mNativeAgent, classes);
170
}
171
172
public boolean
173
isRedefineClassesSupported() {
174
return mEnvironmentSupportsRedefineClasses;
175
}
176
177
public void
178
redefineClasses(ClassDefinition... definitions)
179
throws ClassNotFoundException {
180
if (!isRedefineClassesSupported()) {
181
throw new UnsupportedOperationException("redefineClasses is not supported in this environment");
182
}
183
if (definitions == null) {
184
throw new NullPointerException("null passed as 'definitions' in redefineClasses");
185
}
186
for (int i = 0; i < definitions.length; ++i) {
187
if (definitions[i] == null) {
188
throw new NullPointerException("element of 'definitions' is null in redefineClasses");
189
}
190
}
191
if (definitions.length == 0) {
192
return; // short-circuit if there are no changes requested
193
}
194
195
redefineClasses0(mNativeAgent, definitions);
196
}
197
198
@SuppressWarnings("rawtypes")
199
public Class[]
200
getAllLoadedClasses() {
201
return getAllLoadedClasses0(mNativeAgent);
202
}
203
204
@SuppressWarnings("rawtypes")
205
public Class[]
206
getInitiatedClasses(ClassLoader loader) {
207
return getInitiatedClasses0(mNativeAgent, loader);
208
}
209
210
public long
211
getObjectSize(Object objectToSize) {
212
if (objectToSize == null) {
213
throw new NullPointerException("null passed as 'objectToSize' in getObjectSize");
214
}
215
return getObjectSize0(mNativeAgent, objectToSize);
216
}
217
218
public void
219
appendToBootstrapClassLoaderSearch(JarFile jarfile) {
220
appendToClassLoaderSearch0(mNativeAgent, jarfile.getName(), true);
221
}
222
223
public void
224
appendToSystemClassLoaderSearch(JarFile jarfile) {
225
appendToClassLoaderSearch0(mNativeAgent, jarfile.getName(), false);
226
}
227
228
public boolean
229
isNativeMethodPrefixSupported() {
230
return mEnvironmentSupportsNativeMethodPrefix;
231
}
232
233
public synchronized void
234
setNativeMethodPrefix(ClassFileTransformer transformer, String prefix) {
235
if (!isNativeMethodPrefixSupported()) {
236
throw new UnsupportedOperationException(
237
"setNativeMethodPrefix is not supported in this environment");
238
}
239
if (transformer == null) {
240
throw new NullPointerException(
241
"null passed as 'transformer' in setNativeMethodPrefix");
242
}
243
TransformerManager mgr = findTransformerManager(transformer);
244
if (mgr == null) {
245
throw new IllegalArgumentException(
246
"transformer not registered in setNativeMethodPrefix");
247
}
248
mgr.setNativeMethodPrefix(transformer, prefix);
249
String[] prefixes = mgr.getNativeMethodPrefixes();
250
setNativeMethodPrefixes(mNativeAgent, prefixes, mgr.isRetransformable());
251
}
252
253
@Override
254
public void redefineModule(Module module,
255
Set<Module> extraReads,
256
Map<String, Set<Module>> extraExports,
257
Map<String, Set<Module>> extraOpens,
258
Set<Class<?>> extraUses,
259
Map<Class<?>, List<Class<?>>> extraProvides)
260
{
261
if (!module.isNamed())
262
return;
263
264
if (!isModifiableModule(module))
265
throw new UnmodifiableModuleException(module.getName());
266
267
// copy and check reads
268
extraReads = new HashSet<>(extraReads);
269
if (extraReads.contains(null))
270
throw new NullPointerException("'extraReads' contains null");
271
272
// copy and check exports and opens
273
extraExports = cloneAndCheckMap(module, extraExports);
274
extraOpens = cloneAndCheckMap(module, extraOpens);
275
276
// copy and check uses
277
extraUses = new HashSet<>(extraUses);
278
if (extraUses.contains(null))
279
throw new NullPointerException("'extraUses' contains null");
280
281
// copy and check provides
282
Map<Class<?>, List<Class<?>>> tmpProvides = new HashMap<>();
283
for (Map.Entry<Class<?>, List<Class<?>>> e : extraProvides.entrySet()) {
284
Class<?> service = e.getKey();
285
if (service == null)
286
throw new NullPointerException("'extraProvides' contains null");
287
List<Class<?>> providers = new ArrayList<>(e.getValue());
288
if (providers.isEmpty())
289
throw new IllegalArgumentException("list of providers is empty");
290
providers.forEach(p -> {
291
if (p.getModule() != module)
292
throw new IllegalArgumentException(p + " not in " + module);
293
if (!service.isAssignableFrom(p))
294
throw new IllegalArgumentException(p + " is not a " + service);
295
});
296
tmpProvides.put(service, providers);
297
}
298
extraProvides = tmpProvides;
299
300
301
// update reads
302
extraReads.forEach(m -> Modules.addReads(module, m));
303
304
// update exports
305
for (Map.Entry<String, Set<Module>> e : extraExports.entrySet()) {
306
String pkg = e.getKey();
307
Set<Module> targets = e.getValue();
308
targets.forEach(m -> Modules.addExports(module, pkg, m));
309
}
310
311
// update opens
312
for (Map.Entry<String, Set<Module>> e : extraOpens.entrySet()) {
313
String pkg = e.getKey();
314
Set<Module> targets = e.getValue();
315
targets.forEach(m -> Modules.addOpens(module, pkg, m));
316
}
317
318
// update uses
319
extraUses.forEach(service -> Modules.addUses(module, service));
320
321
// update provides
322
for (Map.Entry<Class<?>, List<Class<?>>> e : extraProvides.entrySet()) {
323
Class<?> service = e.getKey();
324
List<Class<?>> providers = e.getValue();
325
providers.forEach(p -> Modules.addProvides(module, service, p));
326
}
327
}
328
329
private Map<String, Set<Module>>
330
cloneAndCheckMap(Module module, Map<String, Set<Module>> map)
331
{
332
if (map.isEmpty())
333
return Collections.emptyMap();
334
335
Map<String, Set<Module>> result = new HashMap<>();
336
Set<String> packages = module.getPackages();
337
for (Map.Entry<String, Set<Module>> e : map.entrySet()) {
338
String pkg = e.getKey();
339
if (pkg == null)
340
throw new NullPointerException("package cannot be null");
341
if (!packages.contains(pkg))
342
throw new IllegalArgumentException(pkg + " not in module");
343
Set<Module> targets = new HashSet<>(e.getValue());
344
if (targets.isEmpty())
345
throw new IllegalArgumentException("set of targets is empty");
346
if (targets.contains(null))
347
throw new NullPointerException("set of targets cannot include null");
348
result.put(pkg, targets);
349
}
350
return result;
351
}
352
353
354
private TransformerManager
355
findTransformerManager(ClassFileTransformer transformer) {
356
if (mTransformerManager.includesTransformer(transformer)) {
357
return mTransformerManager;
358
}
359
if (mRetransfomableTransformerManager != null &&
360
mRetransfomableTransformerManager.includesTransformer(transformer)) {
361
return mRetransfomableTransformerManager;
362
}
363
return null;
364
}
365
366
367
/*
368
* Natives
369
*/
370
private native boolean
371
isModifiableClass0(long nativeAgent, Class<?> theClass);
372
373
private native boolean
374
isRetransformClassesSupported0(long nativeAgent);
375
376
private native void
377
setHasTransformers(long nativeAgent, boolean has);
378
379
private native void
380
setHasRetransformableTransformers(long nativeAgent, boolean has);
381
382
private native void
383
retransformClasses0(long nativeAgent, Class<?>[] classes);
384
385
private native void
386
redefineClasses0(long nativeAgent, ClassDefinition[] definitions)
387
throws ClassNotFoundException;
388
389
@SuppressWarnings("rawtypes")
390
private native Class[]
391
getAllLoadedClasses0(long nativeAgent);
392
393
@SuppressWarnings("rawtypes")
394
private native Class[]
395
getInitiatedClasses0(long nativeAgent, ClassLoader loader);
396
397
@IntrinsicCandidate
398
private native long
399
getObjectSize0(long nativeAgent, Object objectToSize);
400
401
private native void
402
appendToClassLoaderSearch0(long nativeAgent, String jarfile, boolean bootLoader);
403
404
private native void
405
setNativeMethodPrefixes(long nativeAgent, String[] prefixes, boolean isRetransformable);
406
407
static {
408
System.loadLibrary("instrument");
409
}
410
411
/*
412
* Internals
413
*/
414
415
416
// Enable or disable Java programming language access checks on a
417
// reflected object (for example, a method)
418
@SuppressWarnings("removal")
419
private static void setAccessible(final AccessibleObject ao, final boolean accessible) {
420
AccessController.doPrivileged(new PrivilegedAction<Object>() {
421
public Object run() {
422
ao.setAccessible(accessible);
423
return null;
424
}});
425
}
426
427
// Attempt to load and start an agent
428
private void
429
loadClassAndStartAgent( String classname,
430
String methodname,
431
String optionsString)
432
throws Throwable {
433
434
ClassLoader mainAppLoader = ClassLoader.getSystemClassLoader();
435
Class<?> javaAgentClass = mainAppLoader.loadClass(classname);
436
437
Method m = null;
438
NoSuchMethodException firstExc = null;
439
boolean twoArgAgent = false;
440
441
// The agent class must have a premain or agentmain method that
442
// has 1 or 2 arguments. We check in the following order:
443
//
444
// 1) declared with a signature of (String, Instrumentation)
445
// 2) declared with a signature of (String)
446
//
447
// If no method is found then we throw the NoSuchMethodException
448
// from the first attempt so that the exception text indicates
449
// the lookup failed for the 2-arg method (same as JDK5.0).
450
451
try {
452
m = javaAgentClass.getDeclaredMethod( methodname,
453
new Class<?>[] {
454
String.class,
455
java.lang.instrument.Instrumentation.class
456
}
457
);
458
twoArgAgent = true;
459
} catch (NoSuchMethodException x) {
460
// remember the NoSuchMethodException
461
firstExc = x;
462
}
463
464
if (m == null) {
465
// now try the declared 1-arg method
466
try {
467
m = javaAgentClass.getDeclaredMethod(methodname,
468
new Class<?>[] { String.class });
469
} catch (NoSuchMethodException x) {
470
// none of the methods exists so we throw the
471
// first NoSuchMethodException as per 5.0
472
throw firstExc;
473
}
474
}
475
476
// reject non-public premain or agentmain method
477
if (!Modifier.isPublic(m.getModifiers())) {
478
String msg = "method " + classname + "." + methodname + " must be declared public";
479
throw new IllegalAccessException(msg);
480
}
481
482
if (!Modifier.isPublic(javaAgentClass.getModifiers()) &&
483
!javaAgentClass.getModule().isNamed()) {
484
// If the java agent class is in an unnamed module, the java agent class can be non-public.
485
// Suppress access check upon the invocation of the premain/agentmain method.
486
setAccessible(m, true);
487
}
488
489
// invoke the 1 or 2-arg method
490
if (twoArgAgent) {
491
m.invoke(null, new Object[] { optionsString, this });
492
} else {
493
m.invoke(null, new Object[] { optionsString });
494
}
495
}
496
497
// WARNING: the native code knows the name & signature of this method
498
private void
499
loadClassAndCallPremain( String classname,
500
String optionsString)
501
throws Throwable {
502
503
loadClassAndStartAgent( classname, "premain", optionsString );
504
}
505
506
507
// WARNING: the native code knows the name & signature of this method
508
private void
509
loadClassAndCallAgentmain( String classname,
510
String optionsString)
511
throws Throwable {
512
513
loadClassAndStartAgent( classname, "agentmain", optionsString );
514
}
515
516
// WARNING: the native code knows the name & signature of this method
517
private byte[]
518
transform( Module module,
519
ClassLoader loader,
520
String classname,
521
Class<?> classBeingRedefined,
522
ProtectionDomain protectionDomain,
523
byte[] classfileBuffer,
524
boolean isRetransformer) {
525
TransformerManager mgr = isRetransformer?
526
mRetransfomableTransformerManager :
527
mTransformerManager;
528
// module is null when not a class load or when loading a class in an
529
// unnamed module and this is the first type to be loaded in the package.
530
if (module == null) {
531
if (classBeingRedefined != null) {
532
module = classBeingRedefined.getModule();
533
} else {
534
module = (loader == null) ? jdk.internal.loader.BootLoader.getUnnamedModule()
535
: loader.getUnnamedModule();
536
}
537
}
538
if (mgr == null) {
539
return null; // no manager, no transform
540
} else {
541
return mgr.transform( module,
542
loader,
543
classname,
544
classBeingRedefined,
545
protectionDomain,
546
classfileBuffer);
547
}
548
}
549
550
551
/**
552
* Invoked by the java launcher to load a java agent that is packaged with
553
* the main application in an executable JAR file.
554
*/
555
public static void loadAgent(String path) {
556
loadAgent0(path);
557
}
558
559
private static native void loadAgent0(String path);
560
}
561
562