[#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;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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