From 0ee49e6d668bd100320003b7d6b287bc289db28f Mon Sep 17 00:00:00 2001 From: Norman Maurer Date: Fri, 12 May 2017 08:49:25 +0200 Subject: [PATCH] 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. --- .../util/internal/PlatformDependent.java | 56 +------ .../util/internal/PlatformDependent0.java | 148 +++++++++++++----- .../util/internal/PlatformDependent0Test.java | 37 +++++ .../util/internal/PlatformDependentTest.java | 37 ----- 4 files changed, 145 insertions(+), 133 deletions(-) diff --git a/common/src/main/java/io/netty/util/internal/PlatformDependent.java b/common/src/main/java/io/netty/util/internal/PlatformDependent.java index fcc1c20f13..2fd3c985a9 100644 --- a/common/src/main/java/io/netty/util/internal/PlatformDependent.java +++ b/common/src/main/java/io/netty/util/internal/PlatformDependent.java @@ -67,12 +67,9 @@ public final class PlatformDependent { private static final Pattern MAX_DIRECT_MEMORY_SIZE_ARG_PATTERN = Pattern.compile( "\\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 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 HAS_UNSAFE = hasUnsafe0(); @@ -197,7 +194,7 @@ public final class PlatformDependent { * Returns {@code true} if and only if the current platform is Android */ 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. */ public static int javaVersion() { - return JAVA_VERSION; + return PlatformDependent0.javaVersion(); } /** @@ -913,22 +910,6 @@ public final class PlatformDependent { 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() { boolean windows = SystemPropertyUtil.get("os.name", "").toLowerCase(Locale.US).contains("win"); if (windows) { @@ -946,39 +927,6 @@ public final class PlatformDependent { 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() { if (isAndroid()) { logger.debug("sun.misc.Unsafe: unavailable (Android)"); diff --git a/common/src/main/java/io/netty/util/internal/PlatformDependent0.java b/common/src/main/java/io/netty/util/internal/PlatformDependent0.java index 21178035b4..0664ec9e8b 100644 --- a/common/src/main/java/io/netty/util/internal/PlatformDependent0.java +++ b/common/src/main/java/io/netty/util/internal/PlatformDependent0.java @@ -41,6 +41,8 @@ final class PlatformDependent0 { private static final Constructor DIRECT_BUFFER_CONSTRUCTOR; private static final boolean IS_EXPLICIT_NO_UNSAFE = explicitNoUnsafe0(); 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; static final Unsafe UNSAFE; @@ -285,60 +287,63 @@ final class PlatformDependent0 { UNALIGNED = unaligned; - Object maybeException = AccessController.doPrivileged(new PrivilegedAction() { - @Override - 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() { + if (javaVersion() >= 9) { + Object maybeException = AccessController.doPrivileged(new PrivilegedAction() { @Override public Object run() { try { - return finalInternalUnsafe.getClass().getDeclaredMethod( - "allocateUninitializedArray", Class.class, int.class); - } catch (NoSuchMethodException e) { - return e; - } catch (SecurityException e) { + // 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() { + @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) { - try { - Method m = (Method) maybeException; - byte[] bytes = (byte[]) m.invoke(finalInternalUnsafe, byte.class, 8); - assert bytes.length == 8; - allocateArrayMethod = m; - } catch (IllegalAccessException e) { - maybeException = e; - } catch (InvocationTargetException e) { - maybeException = e; + if (maybeException instanceof Method) { + try { + Method m = (Method) maybeException; + byte[] bytes = (byte[]) m.invoke(finalInternalUnsafe, byte.class, 8); + assert bytes.length == 8; + allocateArrayMethod = m; + } catch (IllegalAccessException e) { + maybeException = e; + } catch (InvocationTargetException 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; - - 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; @@ -756,6 +761,65 @@ final class PlatformDependent0 { 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() { } } diff --git a/common/src/test/java/io/netty/util/internal/PlatformDependent0Test.java b/common/src/test/java/io/netty/util/internal/PlatformDependent0Test.java index 0b4a046545..543c38135d 100644 --- a/common/src/test/java/io/netty/util/internal/PlatformDependent0Test.java +++ b/common/src/test/java/io/netty/util/internal/PlatformDependent0Test.java @@ -19,6 +19,7 @@ import org.junit.BeforeClass; import org.junit.Test; import java.nio.ByteBuffer; +import java.security.Permission; import static org.junit.Assert.assertEquals; import static org.junit.Assume.assumeTrue; @@ -54,4 +55,40 @@ public class PlatformDependent0Test { assertEquals(address, PlatformDependent0.directBufferAddress(buffer)); 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")); + } } diff --git a/common/src/test/java/io/netty/util/internal/PlatformDependentTest.java b/common/src/test/java/io/netty/util/internal/PlatformDependentTest.java index 3169dadf28..245ac56dbf 100644 --- a/common/src/test/java/io/netty/util/internal/PlatformDependentTest.java +++ b/common/src/test/java/io/netty/util/internal/PlatformDependentTest.java @@ -17,7 +17,6 @@ package io.netty.util.internal; import org.junit.Test; -import java.security.Permission; import java.util.Random; import static io.netty.util.internal.PlatformDependent.hashCodeAscii; @@ -147,40 +146,4 @@ public class PlatformDependentTest { 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")); - } }