Skip to content

Commit 2a19264

Browse files
committed
解决问题 #250 增加SandboxProtector机制,让Sandbox核心类在工作时候所产生的事件尽可能不被自己所感知。这样可以解决在增强来自BootstrapClassLoader的类时不必要的性能开销。
1 parent 400c0f7 commit 2a19264

12 files changed

+390
-173
lines changed

sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/JvmSandbox.java

+5-4
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22

33
import com.alibaba.jvm.sandbox.core.enhance.weaver.EventListenerHandler;
44
import com.alibaba.jvm.sandbox.core.manager.CoreModuleManager;
5+
import com.alibaba.jvm.sandbox.core.manager.impl.DefaultCoreLoadedClassDataSource;
56
import com.alibaba.jvm.sandbox.core.manager.impl.DefaultCoreModuleManager;
6-
import com.alibaba.jvm.sandbox.core.manager.impl.DefaultLoadedClassDataSource;
77
import com.alibaba.jvm.sandbox.core.manager.impl.DefaultProviderManager;
8+
import com.alibaba.jvm.sandbox.core.util.SandboxProtector;
89
import com.alibaba.jvm.sandbox.core.util.SpyUtils;
910

1011
import java.lang.instrument.Instrumentation;
@@ -21,12 +22,12 @@ public JvmSandbox(final CoreConfigure cfg,
2122
final Instrumentation inst) {
2223
EventListenerHandler.getSingleton();
2324
this.cfg = cfg;
24-
this.coreModuleManager = new DefaultCoreModuleManager(
25+
this.coreModuleManager = SandboxProtector.instance.protectProxy(CoreModuleManager.class, new DefaultCoreModuleManager(
2526
cfg,
2627
inst,
27-
new DefaultLoadedClassDataSource(inst, cfg.isEnableUnsafe()),
28+
new DefaultCoreLoadedClassDataSource(inst, cfg.isEnableUnsafe()),
2829
new DefaultProviderManager(cfg)
29-
);
30+
));
3031

3132
init();
3233
}

sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/enhance/weaver/EventListenerHandler.java

+37
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import com.alibaba.jvm.sandbox.api.event.InvokeEvent;
77
import com.alibaba.jvm.sandbox.api.listener.EventListener;
88
import com.alibaba.jvm.sandbox.core.util.ObjectIDs;
9+
import com.alibaba.jvm.sandbox.core.util.SandboxProtector;
910
import org.slf4j.Logger;
1011
import org.slf4j.LoggerFactory;
1112

@@ -303,6 +304,12 @@ private boolean checkProcessStack(final int processId,
303304
@Override
304305
public Spy.Ret handleOnBefore(int listenerId, int targetClassLoaderObjectID, Object[] argumentArray, String javaClassName, String javaMethodName, String javaMethodDesc, Object target) throws Throwable {
305306

307+
// 在守护区内产生的事件不需要响应
308+
if (SandboxProtector.instance.isInProtecting()) {
309+
logger.debug("listener={} is in protecting, ignore processing before-event", listenerId);
310+
return newInstanceForNone();
311+
}
312+
306313
// 获取事件处理器
307314
final EventProcessor processor = mappingOfEventProcessor.get(listenerId);
308315

@@ -361,6 +368,12 @@ private Spy.Ret handleOnEnd(final int listenerId,
361368
final Object object,
362369
final boolean isReturn) throws Throwable {
363370

371+
// 在守护区内产生的事件不需要响应
372+
if (SandboxProtector.instance.isInProtecting()) {
373+
logger.debug("listener={} is in protecting, ignore processing {}-event", listenerId, isReturn ? "return" : "throws");
374+
return newInstanceForNone();
375+
}
376+
364377
final EventProcessor wrap = mappingOfEventProcessor.get(listenerId);
365378

366379
// 如果尚未注册,则直接返回,不做任何处理
@@ -420,6 +433,12 @@ private Spy.Ret handleOnEnd(final int listenerId,
420433

421434
@Override
422435
public void handleOnCallBefore(int listenerId, int lineNumber, String owner, String name, String desc) throws Throwable {
436+
437+
// 在守护区内产生的事件不需要响应
438+
if (SandboxProtector.instance.isInProtecting()) {
439+
logger.debug("listener={} is in protecting, ignore processing call-before-event", listenerId);
440+
}
441+
423442
final EventProcessor wrap = mappingOfEventProcessor.get(listenerId);
424443
if (null == wrap) {
425444
logger.debug("listener={} is not activated, ignore processing call-before-event.", listenerId);
@@ -457,6 +476,12 @@ public void handleOnCallBefore(int listenerId, int lineNumber, String owner, Str
457476

458477
@Override
459478
public void handleOnCallReturn(int listenerId) throws Throwable {
479+
480+
// 在守护区内产生的事件不需要响应
481+
if (SandboxProtector.instance.isInProtecting()) {
482+
logger.debug("listener={} is in protecting, ignore processing call-return-event", listenerId);
483+
}
484+
460485
final EventProcessor wrap = mappingOfEventProcessor.get(listenerId);
461486
if (null == wrap) {
462487
logger.debug("listener={} is not activated, ignore processing call-return-event.", listenerId);
@@ -488,6 +513,12 @@ public void handleOnCallReturn(int listenerId) throws Throwable {
488513

489514
@Override
490515
public void handleOnCallThrows(int listenerId, String throwException) throws Throwable {
516+
517+
// 在守护区内产生的事件不需要响应
518+
if (SandboxProtector.instance.isInProtecting()) {
519+
logger.debug("listener={} is in protecting, ignore processing call-throws-event", listenerId);
520+
}
521+
491522
final EventProcessor wrap = mappingOfEventProcessor.get(listenerId);
492523
if (null == wrap) {
493524
logger.debug("listener={} is not activated, ignore processing call-throws-event.", listenerId);
@@ -519,6 +550,12 @@ public void handleOnCallThrows(int listenerId, String throwException) throws Thr
519550

520551
@Override
521552
public void handleOnLine(int listenerId, int lineNumber) throws Throwable {
553+
554+
// 在守护区内产生的事件不需要响应
555+
if (SandboxProtector.instance.isInProtecting()) {
556+
logger.debug("listener={} is in protecting, ignore processing call-line-event", listenerId);
557+
}
558+
522559
final EventProcessor wrap = mappingOfEventProcessor.get(listenerId);
523560
if (null == wrap) {
524561
logger.debug("listener={} is not activated, ignore processing line-event.", listenerId);

sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/enhance/weaver/EventProcessor.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class Process {
3030
private final GaStack<Integer> stack
3131
= new ThreadUnsafeGaStack<Integer>();
3232

33-
// 需要忽略整个调用过程
33+
// 是否需要忽略整个调用过程
3434
private boolean isIgnoreProcess = false;
3535

3636
// 是否来自ImmediatelyThrowsException所抛出的异常
@@ -143,7 +143,6 @@ void markExceptionFromImmediately() {
143143
isExceptionFromImmediately = true;
144144
}
145145

146-
147146
/**
148147
* 获取事件工厂
149148
*

sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/LoadedClassLoaderListener.java

-7
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
package com.alibaba.jvm.sandbox.core.manager.impl;
2+
3+
import com.alibaba.jvm.sandbox.api.filter.Filter;
4+
import com.alibaba.jvm.sandbox.core.manager.CoreLoadedClassDataSource;
5+
import com.alibaba.jvm.sandbox.core.util.SandboxProtector;
6+
import com.alibaba.jvm.sandbox.core.util.matcher.ExtFilterMatcher;
7+
import com.alibaba.jvm.sandbox.core.util.matcher.Matcher;
8+
import com.alibaba.jvm.sandbox.core.util.matcher.UnsupportedMatcher;
9+
import com.alibaba.jvm.sandbox.core.util.matcher.structure.ClassStructureFactory;
10+
import org.slf4j.Logger;
11+
import org.slf4j.LoggerFactory;
12+
13+
import java.lang.instrument.Instrumentation;
14+
import java.util.*;
15+
16+
import static com.alibaba.jvm.sandbox.api.filter.ExtFilter.ExtFilterFactory.make;
17+
import static com.alibaba.jvm.sandbox.core.util.SandboxClassUtils.isComeFromSandboxFamily;
18+
import static com.alibaba.jvm.sandbox.core.util.SandboxStringUtils.toInternalClassName;
19+
20+
/**
21+
* 已加载类数据源默认实现
22+
*
23+
24+
*/
25+
public class DefaultCoreLoadedClassDataSource implements CoreLoadedClassDataSource {
26+
27+
private final Logger logger = LoggerFactory.getLogger(getClass());
28+
private final Instrumentation inst;
29+
private final boolean isEnableUnsafe;
30+
31+
public DefaultCoreLoadedClassDataSource(final Instrumentation inst,
32+
final boolean isEnableUnsafe) {
33+
this.inst = inst;
34+
this.isEnableUnsafe = isEnableUnsafe;
35+
}
36+
37+
@Override
38+
public Set<Class<?>> list() {
39+
final Set<Class<?>> classes = new LinkedHashSet<Class<?>>();
40+
for (Class<?> clazz : inst.getAllLoadedClasses()) {
41+
classes.add(clazz);
42+
}
43+
return classes;
44+
}
45+
46+
@Override
47+
public Iterator<Class<?>> iteratorForLoadedClasses() {
48+
return new Iterator<Class<?>>() {
49+
50+
final Class<?>[] loaded = inst.getAllLoadedClasses();
51+
int pos = 0;
52+
53+
@Override
54+
public boolean hasNext() {
55+
return pos < loaded.length;
56+
}
57+
58+
@Override
59+
public Class<?> next() {
60+
return loaded[pos++];
61+
}
62+
63+
@Override
64+
public void remove() {
65+
throw new UnsupportedOperationException();
66+
}
67+
68+
};
69+
}
70+
71+
@Override
72+
public List<Class<?>> findForReTransform(final Matcher matcher) {
73+
return find(matcher, true);
74+
}
75+
76+
private List<Class<?>> find(final Matcher matcher,
77+
final boolean isRemoveUnsupported) {
78+
79+
SandboxProtector.instance.enterProtecting();
80+
try {
81+
82+
final List<Class<?>> classes = new ArrayList<Class<?>>();
83+
if (null == matcher) {
84+
return classes;
85+
}
86+
87+
final Iterator<Class<?>> itForLoaded = iteratorForLoadedClasses();
88+
while (itForLoaded.hasNext()) {
89+
final Class<?> clazz = itForLoaded.next();
90+
91+
// #242 的建议,过滤掉sandbox家族的类
92+
if (isComeFromSandboxFamily(toInternalClassName(clazz.getName()), clazz.getClassLoader())) {
93+
continue;
94+
}
95+
96+
// 过滤掉对于JVM认为不可修改的类
97+
if (isRemoveUnsupported
98+
&& !inst.isModifiableClass(clazz)) {
99+
// logger.debug("remove from findForReTransform, because class:{} is unModifiable", clazz.getName());
100+
continue;
101+
}
102+
try {
103+
if (isRemoveUnsupported) {
104+
if (new UnsupportedMatcher(clazz.getClassLoader(), isEnableUnsafe)
105+
.and(matcher)
106+
.matching(ClassStructureFactory.createClassStructure(clazz))
107+
.isMatched()) {
108+
classes.add(clazz);
109+
}
110+
} else {
111+
if (matcher.matching(ClassStructureFactory.createClassStructure(clazz)).isMatched()) {
112+
classes.add(clazz);
113+
}
114+
}
115+
116+
} catch (Throwable cause) {
117+
// 在这里可能会遇到非常坑爹的模块卸载错误
118+
// 当一个URLClassLoader被动态关闭之后,但JVM已经加载的类并不知情(因为没有GC)
119+
// 所以当尝试获取这个类更多详细信息的时候会引起关联类的ClassNotFoundException等未知的错误(取决于底层ClassLoader的实现)
120+
// 这里没有办法穷举出所有的异常情况,所以catch Throwable来完成异常容灾处理
121+
// 当解析类出现异常的时候,直接简单粗暴的认为根本没有这个类就好了
122+
logger.debug("remove from findForReTransform, because loading class:{} occur an exception", clazz.getName(), cause);
123+
}
124+
}
125+
return classes;
126+
127+
} finally {
128+
SandboxProtector.instance.exitProtecting();
129+
}
130+
131+
}
132+
133+
134+
/**
135+
* 根据过滤器搜索出匹配的类集合
136+
*
137+
* @param filter 扩展过滤器
138+
* @return 匹配的类集合
139+
*/
140+
@Override
141+
public Set<Class<?>> find(Filter filter) {
142+
return new LinkedHashSet<Class<?>>(find(new ExtFilterMatcher(make(filter)), false));
143+
}
144+
145+
}

sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/manager/impl/DefaultCoreModuleManager.java

+19-18
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import com.alibaba.jvm.sandbox.core.manager.CoreModuleManager;
1313
import com.alibaba.jvm.sandbox.core.manager.ProviderManager;
1414
import com.alibaba.jvm.sandbox.core.manager.impl.ModuleLibLoader.ModuleJarLoadCallback;
15+
import com.alibaba.jvm.sandbox.core.util.SandboxProtector;
1516
import org.apache.commons.io.FileUtils;
1617
import org.apache.commons.lang3.StringUtils;
1718
import org.apache.commons.lang3.reflect.FieldUtils;
@@ -211,25 +212,25 @@ private void injectResourceOnLoadIfNecessary(final CoreModule coreModule) throws
211212

212213
// ModuleEventWatcher对象注入
213214
else if (ModuleEventWatcher.class.isAssignableFrom(fieldType)) {
214-
final ModuleEventWatcher moduleEventWatcher = coreModule.append(new ReleaseResource<ModuleEventWatcher>(new DefaultModuleEventWatcher(
215-
inst,
216-
classDataSource,
217-
coreModule,
218-
cfg.isEnableUnsafe(),
219-
cfg.getNamespace()
220-
)) {
221-
@Override
222-
public void release() {
223-
logger.info("release all SandboxClassFileTransformer for module={}", coreModule.getUniqueId());
224-
final ModuleEventWatcher moduleEventWatcher = get();
225-
if (null != moduleEventWatcher) {
226-
for (final SandboxClassFileTransformer sandboxClassFileTransformer
227-
: new ArrayList<SandboxClassFileTransformer>(coreModule.getSandboxClassFileTransformers())) {
228-
moduleEventWatcher.delete(sandboxClassFileTransformer.getWatchId());
215+
final ModuleEventWatcher moduleEventWatcher = coreModule.append(
216+
new ReleaseResource<ModuleEventWatcher>(
217+
SandboxProtector.instance.protectProxy(
218+
ModuleEventWatcher.class,
219+
new DefaultModuleEventWatcher(inst, classDataSource, coreModule, cfg.isEnableUnsafe(), cfg.getNamespace())
220+
)
221+
) {
222+
@Override
223+
public void release() {
224+
logger.info("release all SandboxClassFileTransformer for module={}", coreModule.getUniqueId());
225+
final ModuleEventWatcher moduleEventWatcher = get();
226+
if (null != moduleEventWatcher) {
227+
for (final SandboxClassFileTransformer sandboxClassFileTransformer
228+
: new ArrayList<SandboxClassFileTransformer>(coreModule.getSandboxClassFileTransformers())) {
229+
moduleEventWatcher.delete(sandboxClassFileTransformer.getWatchId());
230+
}
231+
}
229232
}
230-
}
231-
}
232-
});
233+
});
233234

234235
writeField(
235236
resourceField,

0 commit comments

Comments
 (0)