[#916] Only access Cleaner if it is really present to prevent errors on android

This commit is contained in:
Norman Maurer 2013-01-10 07:32:51 +01:00
parent bfa3445bb3
commit 5b5b39a606
3 changed files with 102 additions and 52 deletions

View File

@ -15,12 +15,12 @@
*/ */
package io.netty.buffer; 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.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.lang.reflect.Field;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.nio.channels.ClosedChannelException; import java.nio.channels.ClosedChannelException;
@ -37,37 +37,6 @@ import java.util.Queue;
@SuppressWarnings("restriction") @SuppressWarnings("restriction")
final class UnpooledDirectByteBuf extends AbstractByteBuf { 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 final ByteBufAllocator alloc;
private ByteBuffer buffer; private ByteBuffer buffer;
private ByteBuffer tmpNioBuf; private ByteBuffer tmpNioBuf;
@ -532,4 +501,10 @@ final class UnpooledDirectByteBuf extends AbstractByteBuf {
public ByteBuf unwrap() { public ByteBuf unwrap() {
return null; return null;
} }
static void freeDirect(ByteBuffer buffer) {
if (DetectionUtil.canFreeDirectBuffer()) {
DirectByteBufUtil.freeDirect(buffer);
}
}
} }

View File

@ -15,13 +15,8 @@
*/ */
package io.netty.util.internal; 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.InetSocketAddress;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.security.AccessController; import java.security.AccessController;
import java.security.PrivilegedActionException; import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction; import java.security.PrivilegedExceptionAction;
@ -90,15 +85,14 @@ public final class DetectionUtil {
boolean canFreeDirectBuffer = false; boolean canFreeDirectBuffer = false;
try { // Only try to use DirectByteBufUtil if it is not android as otherwise it will give errors because
ByteBuffer direct = ByteBuffer.allocateDirect(1); // it try to access sun.misc.Cleaner
Field cleanerField = direct.getClass().getDeclaredField("cleaner"); if (!isAndroid()) {
cleanerField.setAccessible(true); try {
Cleaner cleaner = (Cleaner) cleanerField.get(direct); canFreeDirectBuffer = DirectByteBufUtil.canFreeDirect();
cleaner.clean(); } catch (Throwable t) {
canFreeDirectBuffer = true; // Ignore.
} catch (Throwable t) { }
// Ignore.
} }
CAN_FREE_DIRECT_BUFFER = canFreeDirectBuffer; 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() { public static boolean hasUnsafe() {
return HAS_UNSAFE; return HAS_UNSAFE;
@ -181,11 +175,8 @@ public final class DetectionUtil {
private static int javaVersion0() { private static int javaVersion0() {
// Android // Android
try { if (isAndroid()) {
Class.forName("android.app.Application", false, ClassLoader.getSystemClassLoader());
return 6; return 6;
} catch (Exception e) {
// Ignore
} }
try { try {
@ -200,6 +191,17 @@ public final class DetectionUtil {
return 6; 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() { private DetectionUtil() {
// only static method supported // only static method supported
} }

View File

@ -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() {
}
}