[#916] Only access Cleaner if it is really present to prevent errors on android
This commit is contained in:
parent
bfa3445bb3
commit
5b5b39a606
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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() {
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user