Eliminate noisy logging when using sun.misc.Unsafe and running on pre Java9

Motivation:

We should only try to load jdk.internal.misc.Unsafe if we run on Java9+ to eliminate noise in the log.

Modifications:

- Move javaVersion() and related methods to PlatformDependent0 to be able to use these in the static initializer without creating a cycle.
- Only try to load jdk.internal.misc.Unsafe when running in Java9+

Result:

Less noise in the log when running pre java9.
This commit is contained in:
Norman Maurer 2017-05-12 08:49:25 +02:00
parent 827c409656
commit 0ee49e6d66
4 changed files with 145 additions and 133 deletions

View File

@ -67,12 +67,9 @@ public final class PlatformDependent {
private static final Pattern MAX_DIRECT_MEMORY_SIZE_ARG_PATTERN = Pattern.compile( private static final Pattern MAX_DIRECT_MEMORY_SIZE_ARG_PATTERN = Pattern.compile(
"\\s*-XX:MaxDirectMemorySize\\s*=\\s*([0-9]+)\\s*([kKmMgG]?)\\s*$"); "\\s*-XX:MaxDirectMemorySize\\s*=\\s*([0-9]+)\\s*([kKmMgG]?)\\s*$");
private static final boolean IS_ANDROID = isAndroid0();
private static final boolean IS_WINDOWS = isWindows0(); private static final boolean IS_WINDOWS = isWindows0();
private static final boolean MAYBE_SUPER_USER; private static final boolean MAYBE_SUPER_USER;
private static final int JAVA_VERSION = javaVersion0();
private static final boolean CAN_ENABLE_TCP_NODELAY_BY_DEFAULT = !isAndroid(); private static final boolean CAN_ENABLE_TCP_NODELAY_BY_DEFAULT = !isAndroid();
private static final boolean HAS_UNSAFE = hasUnsafe0(); private static final boolean HAS_UNSAFE = hasUnsafe0();
@ -197,7 +194,7 @@ public final class PlatformDependent {
* Returns {@code true} if and only if the current platform is Android * Returns {@code true} if and only if the current platform is Android
*/ */
public static boolean isAndroid() { public static boolean isAndroid() {
return IS_ANDROID; return PlatformDependent0.isAndroid();
} }
/** /**
@ -219,7 +216,7 @@ public final class PlatformDependent {
* Return the version of Java under which this library is used. * Return the version of Java under which this library is used.
*/ */
public static int javaVersion() { public static int javaVersion() {
return JAVA_VERSION; return PlatformDependent0.javaVersion();
} }
/** /**
@ -913,22 +910,6 @@ public final class PlatformDependent {
return RANDOM_PROVIDER.current(); return RANDOM_PROVIDER.current();
} }
private static boolean isAndroid0() {
boolean android;
try {
Class.forName("android.app.Application", false, getSystemClassLoader());
android = true;
} catch (Throwable ignored) {
// Failed to load the class uniquely available in Android.
android = false;
}
if (android) {
logger.debug("Platform: Android");
}
return android;
}
private static boolean isWindows0() { private static boolean isWindows0() {
boolean windows = SystemPropertyUtil.get("os.name", "").toLowerCase(Locale.US).contains("win"); boolean windows = SystemPropertyUtil.get("os.name", "").toLowerCase(Locale.US).contains("win");
if (windows) { if (windows) {
@ -946,39 +927,6 @@ public final class PlatformDependent {
return "root".equals(username) || "toor".equals(username); return "root".equals(username) || "toor".equals(username);
} }
private static int javaVersion0() {
final int majorVersion;
if (isAndroid()) {
majorVersion = 6;
} else {
majorVersion = majorVersionFromJavaSpecificationVersion();
}
logger.debug("Java version: {}", majorVersion);
return majorVersion;
}
static int majorVersionFromJavaSpecificationVersion() {
return majorVersion(SystemPropertyUtil.get("java.specification.version", "1.6"));
}
static int majorVersion(final String javaSpecVersion) {
final String[] components = javaSpecVersion.split("\\.");
final int[] version = new int[components.length];
for (int i = 0; i < components.length; i++) {
version[i] = Integer.parseInt(components[i]);
}
if (version[0] == 1) {
assert version[1] >= 6;
return version[1];
} else {
return version[0];
}
}
private static boolean hasUnsafe0() { private static boolean hasUnsafe0() {
if (isAndroid()) { if (isAndroid()) {
logger.debug("sun.misc.Unsafe: unavailable (Android)"); logger.debug("sun.misc.Unsafe: unavailable (Android)");

View File

@ -41,6 +41,8 @@ final class PlatformDependent0 {
private static final Constructor<?> DIRECT_BUFFER_CONSTRUCTOR; private static final Constructor<?> DIRECT_BUFFER_CONSTRUCTOR;
private static final boolean IS_EXPLICIT_NO_UNSAFE = explicitNoUnsafe0(); private static final boolean IS_EXPLICIT_NO_UNSAFE = explicitNoUnsafe0();
private static final Method ALLOCATE_ARRAY_METHOD; private static final Method ALLOCATE_ARRAY_METHOD;
private static final int JAVA_VERSION = javaVersion0();
private static final boolean IS_ANDROID = isAndroid0();
private static final Object INTERNAL_UNSAFE; private static final Object INTERNAL_UNSAFE;
static final Unsafe UNSAFE; static final Unsafe UNSAFE;
@ -285,60 +287,63 @@ final class PlatformDependent0 {
UNALIGNED = unaligned; UNALIGNED = unaligned;
Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() { if (javaVersion() >= 9) {
@Override Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
try {
// Java9 has jdk.internal.misc.Unsafe and not all methods are propagated to
// sun.misc.Unsafe
Class<?> internalUnsafeClass = getClassLoader(PlatformDependent0.class)
.loadClass("jdk.internal.misc.Unsafe");
Method method = internalUnsafeClass.getDeclaredMethod("getUnsafe");
return method.invoke(null);
} catch (Throwable e) {
return e;
}
}
});
if (!(maybeException instanceof Throwable)) {
internalUnsafe = maybeException;
final Object finalInternalUnsafe = internalUnsafe;
maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override @Override
public Object run() { public Object run() {
try { try {
return finalInternalUnsafe.getClass().getDeclaredMethod( // Java9 has jdk.internal.misc.Unsafe and not all methods are propagated to
"allocateUninitializedArray", Class.class, int.class); // sun.misc.Unsafe
} catch (NoSuchMethodException e) { Class<?> internalUnsafeClass = getClassLoader(PlatformDependent0.class)
return e; .loadClass("jdk.internal.misc.Unsafe");
} catch (SecurityException e) { Method method = internalUnsafeClass.getDeclaredMethod("getUnsafe");
return method.invoke(null);
} catch (Throwable e) {
return e; return e;
} }
} }
}); });
if (!(maybeException instanceof Throwable)) {
internalUnsafe = maybeException;
final Object finalInternalUnsafe = internalUnsafe;
maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
try {
return finalInternalUnsafe.getClass().getDeclaredMethod(
"allocateUninitializedArray", Class.class, int.class);
} catch (NoSuchMethodException e) {
return e;
} catch (SecurityException e) {
return e;
}
}
});
if (maybeException instanceof Method) { if (maybeException instanceof Method) {
try { try {
Method m = (Method) maybeException; Method m = (Method) maybeException;
byte[] bytes = (byte[]) m.invoke(finalInternalUnsafe, byte.class, 8); byte[] bytes = (byte[]) m.invoke(finalInternalUnsafe, byte.class, 8);
assert bytes.length == 8; assert bytes.length == 8;
allocateArrayMethod = m; allocateArrayMethod = m;
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
maybeException = e; maybeException = e;
} catch (InvocationTargetException e) { } catch (InvocationTargetException e) {
maybeException = e; maybeException = e;
}
} }
} }
if (maybeException instanceof Throwable) {
logger.debug("jdk.internal.misc.Unsafe.allocateUninitializedArray(int): unavailable",
(Throwable) maybeException);
} else {
logger.debug("jdk.internal.misc.Unsafe.allocateUninitializedArray(int): available");
}
} else {
logger.debug("jdk.internal.misc.Unsafe.allocateUninitializedArray(int): unavailable prior to Java9");
} }
ALLOCATE_ARRAY_METHOD = allocateArrayMethod; ALLOCATE_ARRAY_METHOD = allocateArrayMethod;
if (maybeException instanceof Throwable) {
logger.debug("jdk.internal.misc.Unsafe.allocateUninitializedArray(int): unavailable",
(Throwable) maybeException);
} else {
logger.debug("jdk.internal.misc.Unsafe.allocateUninitializedArray(int): available");
}
} }
INTERNAL_UNSAFE = internalUnsafe; INTERNAL_UNSAFE = internalUnsafe;
@ -756,6 +761,65 @@ final class PlatformDependent0 {
return UNSAFE.reallocateMemory(address, newSize); return UNSAFE.reallocateMemory(address, newSize);
} }
static boolean isAndroid() {
return IS_ANDROID;
}
private static boolean isAndroid0() {
boolean android;
try {
Class.forName("android.app.Application", false, getSystemClassLoader());
android = true;
} catch (Throwable ignored) {
// Failed to load the class uniquely available in Android.
android = false;
}
if (android) {
logger.debug("Platform: Android");
}
return android;
}
static int javaVersion() {
return JAVA_VERSION;
}
private static int javaVersion0() {
final int majorVersion;
if (isAndroid0()) {
majorVersion = 6;
} else {
majorVersion = majorVersionFromJavaSpecificationVersion();
}
logger.debug("Java version: {}", majorVersion);
return majorVersion;
}
// Package-private for testing only
static int majorVersionFromJavaSpecificationVersion() {
return majorVersion(SystemPropertyUtil.get("java.specification.version", "1.6"));
}
// Package-private for testing only
static int majorVersion(final String javaSpecVersion) {
final String[] components = javaSpecVersion.split("\\.");
final int[] version = new int[components.length];
for (int i = 0; i < components.length; i++) {
version[i] = Integer.parseInt(components[i]);
}
if (version[0] == 1) {
assert version[1] >= 6;
return version[1];
} else {
return version[0];
}
}
private PlatformDependent0() { private PlatformDependent0() {
} }
} }

View File

@ -19,6 +19,7 @@ import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.security.Permission;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assume.assumeTrue; import static org.junit.Assume.assumeTrue;
@ -54,4 +55,40 @@ public class PlatformDependent0Test {
assertEquals(address, PlatformDependent0.directBufferAddress(buffer)); assertEquals(address, PlatformDependent0.directBufferAddress(buffer));
assertEquals(capacity, buffer.capacity()); assertEquals(capacity, buffer.capacity());
} }
@Test
public void testMajorVersionFromJavaSpecificationVersion() {
final SecurityManager current = System.getSecurityManager();
try {
System.setSecurityManager(new SecurityManager() {
@Override
public void checkPropertyAccess(String key) {
if (key.equals("java.specification.version")) {
// deny
throw new SecurityException(key);
}
}
// so we can restore the security manager
@Override
public void checkPermission(Permission perm) {
}
});
assertEquals(6, PlatformDependent0.majorVersionFromJavaSpecificationVersion());
} finally {
System.setSecurityManager(current);
}
}
@Test
public void testMajorVersion() {
assertEquals(6, PlatformDependent0.majorVersion("1.6"));
assertEquals(7, PlatformDependent0.majorVersion("1.7"));
assertEquals(8, PlatformDependent0.majorVersion("1.8"));
assertEquals(8, PlatformDependent0.majorVersion("8"));
assertEquals(9, PlatformDependent0.majorVersion("1.9")); // early version of JDK 9 before Project Verona
assertEquals(9, PlatformDependent0.majorVersion("9"));
}
} }

View File

@ -17,7 +17,6 @@ package io.netty.util.internal;
import org.junit.Test; import org.junit.Test;
import java.security.Permission;
import java.util.Random; import java.util.Random;
import static io.netty.util.internal.PlatformDependent.hashCodeAscii; import static io.netty.util.internal.PlatformDependent.hashCodeAscii;
@ -147,40 +146,4 @@ public class PlatformDependentTest {
hashCodeAscii(string)); hashCodeAscii(string));
} }
} }
@Test
public void testMajorVersionFromJavaSpecificationVersion() {
final SecurityManager current = System.getSecurityManager();
try {
System.setSecurityManager(new SecurityManager() {
@Override
public void checkPropertyAccess(String key) {
if (key.equals("java.specification.version")) {
// deny
throw new SecurityException(key);
}
}
// so we can restore the security manager
@Override
public void checkPermission(Permission perm) {
}
});
assertEquals(6, PlatformDependent.majorVersionFromJavaSpecificationVersion());
} finally {
System.setSecurityManager(current);
}
}
@Test
public void testMajorVersion() {
assertEquals(6, PlatformDependent.majorVersion("1.6"));
assertEquals(7, PlatformDependent.majorVersion("1.7"));
assertEquals(8, PlatformDependent.majorVersion("1.8"));
assertEquals(8, PlatformDependent.majorVersion("8"));
assertEquals(9, PlatformDependent.majorVersion("1.9")); // early version of JDK 9 before Project Verona
assertEquals(9, PlatformDependent.majorVersion("9"));
}
} }