From 5b5b39a60611be3d9268c7891e8c26eba7100af0 Mon Sep 17 00:00:00 2001 From: Norman Maurer Date: Thu, 10 Jan 2013 07:32:51 +0100 Subject: [PATCH] [#916] Only access Cleaner if it is really present to prevent errors on android --- .../netty/buffer/UnpooledDirectByteBuf.java | 41 ++--------- .../io/netty/util/internal/DetectionUtil.java | 40 +++++----- .../util/internal/DirectByteBufUtil.java | 73 +++++++++++++++++++ 3 files changed, 102 insertions(+), 52 deletions(-) create mode 100644 common/src/main/java/io/netty/util/internal/DirectByteBufUtil.java diff --git a/buffer/src/main/java/io/netty/buffer/UnpooledDirectByteBuf.java b/buffer/src/main/java/io/netty/buffer/UnpooledDirectByteBuf.java index ae66cd99c4..a741c26142 100644 --- a/buffer/src/main/java/io/netty/buffer/UnpooledDirectByteBuf.java +++ b/buffer/src/main/java/io/netty/buffer/UnpooledDirectByteBuf.java @@ -15,12 +15,12 @@ */ package io.netty.buffer; -import sun.misc.Cleaner; +import io.netty.util.internal.DetectionUtil; +import io.netty.util.internal.DirectByteBufUtil; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.lang.reflect.Field; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.ClosedChannelException; @@ -37,37 +37,6 @@ import java.util.Queue; @SuppressWarnings("restriction") final class UnpooledDirectByteBuf extends AbstractByteBuf { - private static final Field CLEANER_FIELD; - - static { - ByteBuffer direct = ByteBuffer.allocateDirect(1); - Field cleanerField; - try { - cleanerField = direct.getClass().getDeclaredField("cleaner"); - cleanerField.setAccessible(true); - Cleaner cleaner = (Cleaner) cleanerField.get(direct); - cleaner.clean(); - } catch (Throwable t) { - cleanerField = null; - } - CLEANER_FIELD = cleanerField; - } - - static void freeDirect(ByteBuffer buffer) { - if (CLEANER_FIELD == null) { - // Doomed to wait for GC. - return; - } - - Cleaner cleaner; - try { - cleaner = (Cleaner) CLEANER_FIELD.get(buffer); - cleaner.clean(); - } catch (Throwable t) { - // Nothing we can do here. - } - } - private final ByteBufAllocator alloc; private ByteBuffer buffer; private ByteBuffer tmpNioBuf; @@ -532,4 +501,10 @@ final class UnpooledDirectByteBuf extends AbstractByteBuf { public ByteBuf unwrap() { return null; } + + static void freeDirect(ByteBuffer buffer) { + if (DetectionUtil.canFreeDirectBuffer()) { + DirectByteBufUtil.freeDirect(buffer); + } + } } diff --git a/common/src/main/java/io/netty/util/internal/DetectionUtil.java b/common/src/main/java/io/netty/util/internal/DetectionUtil.java index 3c21f836ab..4a5a1c7fb9 100644 --- a/common/src/main/java/io/netty/util/internal/DetectionUtil.java +++ b/common/src/main/java/io/netty/util/internal/DetectionUtil.java @@ -15,13 +15,8 @@ */ package io.netty.util.internal; -import sun.misc.Cleaner; -import sun.misc.Unsafe; - -import java.lang.reflect.Field; import java.net.InetSocketAddress; import java.net.ServerSocket; -import java.nio.ByteBuffer; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; @@ -90,15 +85,14 @@ public final class DetectionUtil { boolean canFreeDirectBuffer = false; - try { - ByteBuffer direct = ByteBuffer.allocateDirect(1); - Field cleanerField = direct.getClass().getDeclaredField("cleaner"); - cleanerField.setAccessible(true); - Cleaner cleaner = (Cleaner) cleanerField.get(direct); - cleaner.clean(); - canFreeDirectBuffer = true; - } catch (Throwable t) { - // Ignore. + // Only try to use DirectByteBufUtil if it is not android as otherwise it will give errors because + // it try to access sun.misc.Cleaner + if (!isAndroid()) { + try { + canFreeDirectBuffer = DirectByteBufUtil.canFreeDirect(); + } catch (Throwable t) { + // Ignore. + } } CAN_FREE_DIRECT_BUFFER = canFreeDirectBuffer; @@ -120,7 +114,7 @@ public final class DetectionUtil { } /** - * Return {@code true} if {@link Unsafe} was found on the classpath and can be used. + * Return {@code true} if {@link sun.misc.Unsafe} was found on the classpath and can be used. */ public static boolean hasUnsafe() { return HAS_UNSAFE; @@ -181,11 +175,8 @@ public final class DetectionUtil { private static int javaVersion0() { // Android - try { - Class.forName("android.app.Application", false, ClassLoader.getSystemClassLoader()); + if (isAndroid()) { return 6; - } catch (Exception e) { - // Ignore } try { @@ -200,6 +191,17 @@ public final class DetectionUtil { return 6; } + private static boolean isAndroid() { + // Android + try { + Class.forName("android.app.Application", false, ClassLoader.getSystemClassLoader()); + return true; + } catch (Exception e) { + // Ignore + } + return false; + } + private DetectionUtil() { // only static method supported } diff --git a/common/src/main/java/io/netty/util/internal/DirectByteBufUtil.java b/common/src/main/java/io/netty/util/internal/DirectByteBufUtil.java new file mode 100644 index 0000000000..b7f8ad6f09 --- /dev/null +++ b/common/src/main/java/io/netty/util/internal/DirectByteBufUtil.java @@ -0,0 +1,73 @@ +/* + * Copyright 2013 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.util.internal; + +import sun.misc.Cleaner; + +import java.lang.reflect.Field; +import java.nio.ByteBuffer; + +// This resist in common because otherwise we would produce a cycle dependency between common and buffer. +public final class DirectByteBufUtil { + + private static final Field CLEANER_FIELD; + + static { + ByteBuffer direct = ByteBuffer.allocateDirect(1); + Field cleanerField; + try { + cleanerField = direct.getClass().getDeclaredField("cleaner"); + cleanerField.setAccessible(true); + Cleaner cleaner = (Cleaner) cleanerField.get(direct); + cleaner.clean(); + } catch (Throwable t) { + cleanerField = null; + } + CLEANER_FIELD = cleanerField; + } + + /** + * Try to clean a direct {@link ByteBuffer}. + * + * Only try to access this method when {@link DetectionUtil#canFreeDirectBuffer()} returns + * {@code true} + * + */ + public static void freeDirect(ByteBuffer buffer) { + if (!buffer.isDirect()) { + return; + } + if (CLEANER_FIELD == null) { + // Doomed to wait for GC. + return; + } + + Cleaner cleaner; + try { + cleaner = (Cleaner) CLEANER_FIELD.get(buffer); + cleaner.clean(); + } catch (Throwable t) { + // Nothing we can do here. + } + } + + static boolean canFreeDirect() { + return CLEANER_FIELD != null; + } + + private DirectByteBufUtil() { + } +}