|
@@ -25,9 +25,6 @@ |
|
|
|
|
|
package jdk.jfr.internal; |
|
|
|
|
|
import java.io.IOException; |
|
|
import java.io.ObjectInputStream; |
|
|
import java.io.ObjectOutputStream; |
|
|
import java.security.AccessControlContext; |
|
|
import java.security.AccessController; |
|
|
import java.security.PrivilegedAction; |
|
@@ -36,61 +33,44 @@ |
|
|
import java.util.Objects; |
|
|
import java.util.Set; |
|
|
|
|
|
// User must never be able to subclass directly. |
|
|
// |
|
|
// Never put Control or Setting Control in a collections |
|
|
// so overridable versions of hashCode or equals are |
|
|
// executed in the wrong context. TODO: wrap this class |
|
|
// in SsecureControl directly when it is instantiated and |
|
|
// forward calls using AccessControlContext |
|
|
abstract public class Control { |
|
|
import jdk.jfr.SettingControl; |
|
|
import jdk.jfr.internal.settings.JDKSettingControl; |
|
|
|
|
|
public final class Control { |
|
|
private final AccessControlContext context; |
|
|
private final static int CACHE_SIZE = 5; |
|
|
private final Set<?>[] cachedUnions = new HashSet<?>[CACHE_SIZE]; |
|
|
private final String[] cachedValues = new String[CACHE_SIZE]; |
|
|
private final SettingControl delegate; |
|
|
private String defaultValue; |
|
|
private String lastValue; |
|
|
|
|
|
// called by exposed subclass in external API |
|
|
public Control(AccessControlContext acc) { |
|
|
Objects.requireNonNull(acc); |
|
|
this.context = acc; |
|
|
|
|
|
} |
|
|
|
|
|
// only to be called by trusted VM code |
|
|
public Control(String defaultValue) { |
|
|
public Control(SettingControl delegate, String defaultValue) { |
|
|
this.context = PrivateAccess.getInstance().getContext(delegate); |
|
|
this.delegate = delegate; |
|
|
this.defaultValue = defaultValue; |
|
|
this.context = null; |
|
|
if (this.context == null && !(delegate instanceof JDKSettingControl)) { |
|
|
throw new InternalError("Security context can only be null for trusted setting controls"); |
|
|
} |
|
|
} |
|
|
|
|
|
// For user code to override, must never be called from jdk.jfr.internal |
|
|
// for user defined settings |
|
|
public abstract String combine(Set<String> values); |
|
|
|
|
|
// For user code to override, must never be called from jdk.jfr.internal |
|
|
// for user defined settings |
|
|
public abstract void setValue(String value); |
|
|
|
|
|
// For user code to override, must never be called from jdk.jfr.internal |
|
|
// for user defined settings |
|
|
public abstract String getValue(); |
|
|
boolean isType(Class<? extends SettingControl> clazz) { |
|
|
return delegate.getClass() == clazz; |
|
|
} |
|
|
|
|
|
// Package private, user code should not have access to this method |
|
|
final void apply(Set<String> values) { |
|
|
setValueSafe(findCombineSafe(values)); |
|
|
setValue(findCombine(values)); |
|
|
} |
|
|
|
|
|
// Package private, user code should not have access to this method. |
|
|
// Only called during event registration |
|
|
final void setDefault() { |
|
|
if (defaultValue == null) { |
|
|
defaultValue = getValueSafe(); |
|
|
defaultValue = getValue(); |
|
|
} |
|
|
apply(defaultValue); |
|
|
} |
|
|
|
|
|
final String getValueSafe() { |
|
|
public String getValue() { |
|
|
if (context == null) { |
|
|
// VM events requires no access control context |
|
|
return getValue(); |
|
@@ -99,7 +79,7 @@ final String getValueSafe() { |
|
|
@Override |
|
|
public String run() { |
|
|
try { |
|
|
return getValue(); |
|
|
return delegate.getValue(); |
|
|
} catch (Throwable t) { |
|
|
// Prevent malicious user to propagate exception callback in the wrong context |
|
|
Logger.log(LogTag.JFR_SETTING, LogLevel.WARN, "Exception occurred when trying to get value for " + getClass()); |
|
@@ -114,14 +94,14 @@ private void apply(String value) { |
|
|
if (lastValue != null && Objects.equals(value, lastValue)) { |
|
|
return; |
|
|
} |
|
|
setValueSafe(value); |
|
|
setValue(value); |
|
|
} |
|
|
|
|
|
final void setValueSafe(String value) { |
|
|
public void setValue(String value) { |
|
|
if (context == null) { |
|
|
// VM events requires no access control context |
|
|
try { |
|
|
setValue(value); |
|
|
delegate.setValue(value); |
|
|
} catch (Throwable t) { |
|
|
Logger.log(LogTag.JFR_SETTING, LogLevel.WARN, "Exception occurred when setting value \"" + value + "\" for " + getClass()); |
|
|
} |
|
@@ -130,7 +110,7 @@ final void setValueSafe(String value) { |
|
|
@Override |
|
|
public Void run() { |
|
|
try { |
|
|
setValue(value); |
|
|
delegate.setValue(value); |
|
|
} catch (Throwable t) { |
|
|
// Prevent malicious user to propagate exception callback in the wrong context |
|
|
Logger.log(LogTag.JFR_SETTING, LogLevel.WARN, "Exception occurred when setting value \"" + value + "\" for " + getClass()); |
|
@@ -143,16 +123,16 @@ public Void run() { |
|
|
} |
|
|
|
|
|
|
|
|
private String combineSafe(Set<String> values) { |
|
|
public String combine(Set<String> values) { |
|
|
if (context == null) { |
|
|
// VM events requires no access control context |
|
|
return combine(values); |
|
|
return delegate.combine(values); |
|
|
} |
|
|
return AccessController.doPrivileged(new PrivilegedAction<String>() { |
|
|
@Override |
|
|
public String run() { |
|
|
try { |
|
|
combine(Collections.unmodifiableSet(values)); |
|
|
delegate.combine(Collections.unmodifiableSet(values)); |
|
|
} catch (Throwable t) { |
|
|
// Prevent malicious user to propagate exception callback in the wrong context |
|
|
Logger.log(LogTag.JFR_SETTING, LogLevel.WARN, "Exception occurred when combining " + values + " for " + getClass()); |
|
@@ -162,7 +142,7 @@ public String run() { |
|
|
}, context); |
|
|
} |
|
|
|
|
|
private final String findCombineSafe(Set<String> values) { |
|
|
private final String findCombine(Set<String> values) { |
|
|
if (values.size() == 1) { |
|
|
return values.iterator().next(); |
|
|
} |
|
@@ -171,7 +151,7 @@ private final String findCombineSafe(Set<String> values) { |
|
|
return cachedValues[i]; |
|
|
} |
|
|
} |
|
|
String result = combineSafe(values); |
|
|
String result = combine(values); |
|
|
for (int i = 0; i < CACHE_SIZE - 1; i++) { |
|
|
cachedUnions[i + 1] = cachedUnions[i]; |
|
|
cachedValues[i + 1] = cachedValues[i]; |
|
@@ -181,29 +161,11 @@ private final String findCombineSafe(Set<String> values) { |
|
|
return result; |
|
|
} |
|
|
|
|
|
|
|
|
// package private, user code should not have access to this method |
|
|
final String getDefaultValue() { |
|
|
return defaultValue; |
|
|
} |
|
|
|
|
|
// package private, user code should not have access to this method |
|
|
final String getLastValue() { |
|
|
return lastValue; |
|
|
} |
|
|
|
|
|
// Precaution to prevent a malicious user from instantiating instances |
|
|
// of a control where the context has not been set up. |
|
|
@Override |
|
|
public final Object clone() throws java.lang.CloneNotSupportedException { |
|
|
throw new CloneNotSupportedException(); |
|
|
} |
|
|
|
|
|
private final void writeObject(ObjectOutputStream out) throws IOException { |
|
|
throw new IOException("Object cannot be serialized"); |
|
|
} |
|
|
|
|
|
private final void readObject(ObjectInputStream in) throws IOException { |
|
|
throw new IOException("Class cannot be deserialized"); |
|
|
} |
|
|
} |