[#2604] Not try to use sun.misc.Cleaner when on android
Motivation: When a user tries to use netty on android it currently fails with "Could not find class 'sun.misc.Cleaner'" Modification: Encapsulate sun.misc.Cleaner usage in extra class to workaround this isssue. Result: Netty can be used on android again
This commit is contained in:
parent
d062500ca0
commit
522b3e1b92
74
common/src/main/java/io/netty/util/internal/Cleaner0.java
Normal file
74
common/src/main/java/io/netty/util/internal/Cleaner0.java
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014 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 io.netty.util.internal.logging.InternalLogger;
|
||||||
|
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||||
|
import sun.misc.Cleaner;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows to free direct {@link ByteBuffer} by using {@link Cleaner}. This is encapsulated in an extra class to be able
|
||||||
|
* to use {@link PlatformDependent0} on Android without problems.
|
||||||
|
*
|
||||||
|
* For more details see <a href="https://github.com/netty/netty/issues/2604">#2604</a>.
|
||||||
|
*/
|
||||||
|
final class Cleaner0 {
|
||||||
|
private static final long CLEANER_FIELD_OFFSET;
|
||||||
|
private static final InternalLogger logger = InternalLoggerFactory.getInstance(Cleaner0.class);
|
||||||
|
|
||||||
|
static {
|
||||||
|
ByteBuffer direct = ByteBuffer.allocateDirect(1);
|
||||||
|
Field cleanerField;
|
||||||
|
long fieldOffset = -1;
|
||||||
|
if (PlatformDependent0.hasUnsafe()) {
|
||||||
|
try {
|
||||||
|
cleanerField = direct.getClass().getDeclaredField("cleaner");
|
||||||
|
cleanerField.setAccessible(true);
|
||||||
|
Cleaner cleaner = (Cleaner) cleanerField.get(direct);
|
||||||
|
cleaner.clean();
|
||||||
|
fieldOffset = PlatformDependent0.objectFieldOffset(cleanerField);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
// We don't have ByteBuffer.cleaner().
|
||||||
|
fieldOffset = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.debug("java.nio.ByteBuffer.cleaner(): {}", fieldOffset != -1? "available" : "unavailable");
|
||||||
|
CLEANER_FIELD_OFFSET = fieldOffset;
|
||||||
|
|
||||||
|
// free buffer if possible
|
||||||
|
freeDirectBuffer(direct);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void freeDirectBuffer(ByteBuffer buffer) {
|
||||||
|
if (CLEANER_FIELD_OFFSET == -1 || !buffer.isDirect()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Cleaner cleaner = (Cleaner) PlatformDependent0.getObject(buffer, CLEANER_FIELD_OFFSET);
|
||||||
|
if (cleaner != null) {
|
||||||
|
cleaner.clean();
|
||||||
|
}
|
||||||
|
} catch (Throwable t) {
|
||||||
|
// Nothing we can do here.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Cleaner0() { }
|
||||||
|
}
|
@ -250,7 +250,9 @@ public final class PlatformDependent {
|
|||||||
* the current platform does not support this operation or the specified buffer is not a direct buffer.
|
* the current platform does not support this operation or the specified buffer is not a direct buffer.
|
||||||
*/
|
*/
|
||||||
public static void freeDirectBuffer(ByteBuffer buffer) {
|
public static void freeDirectBuffer(ByteBuffer buffer) {
|
||||||
if (hasUnsafe()) {
|
if (hasUnsafe() && !isAndroid()) {
|
||||||
|
// only direct to method if we are not running on android.
|
||||||
|
// See https://github.com/netty/netty/issues/2604
|
||||||
PlatformDependent0.freeDirectBuffer(buffer);
|
PlatformDependent0.freeDirectBuffer(buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,6 @@ package io.netty.util.internal;
|
|||||||
|
|
||||||
import io.netty.util.internal.logging.InternalLogger;
|
import io.netty.util.internal.logging.InternalLogger;
|
||||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||||
import sun.misc.Cleaner;
|
|
||||||
import sun.misc.Unsafe;
|
import sun.misc.Unsafe;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
@ -40,7 +39,6 @@ final class PlatformDependent0 {
|
|||||||
private static final Unsafe UNSAFE;
|
private static final Unsafe UNSAFE;
|
||||||
private static final boolean BIG_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
|
private static final boolean BIG_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
|
||||||
private static final long ADDRESS_FIELD_OFFSET;
|
private static final long ADDRESS_FIELD_OFFSET;
|
||||||
private static final long CLEANER_FIELD_OFFSET;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Limits the number of bytes to copy per {@link Unsafe#copyMemory(long, long, long)} to allow safepoint polling
|
* Limits the number of bytes to copy per {@link Unsafe#copyMemory(long, long, long)} to allow safepoint polling
|
||||||
@ -57,19 +55,6 @@ final class PlatformDependent0 {
|
|||||||
|
|
||||||
static {
|
static {
|
||||||
ByteBuffer direct = ByteBuffer.allocateDirect(1);
|
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) {
|
|
||||||
// We don't have ByteBuffer.cleaner().
|
|
||||||
cleanerField = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.debug("java.nio.ByteBuffer.cleaner(): {}", cleanerField != null? "available" : "unavailable");
|
|
||||||
|
|
||||||
Field addressField;
|
Field addressField;
|
||||||
try {
|
try {
|
||||||
addressField = Buffer.class.getDeclaredField("address");
|
addressField = Buffer.class.getDeclaredField("address");
|
||||||
@ -90,7 +75,7 @@ final class PlatformDependent0 {
|
|||||||
logger.debug("java.nio.Buffer.address: {}", addressField != null? "available" : "unavailable");
|
logger.debug("java.nio.Buffer.address: {}", addressField != null? "available" : "unavailable");
|
||||||
|
|
||||||
Unsafe unsafe;
|
Unsafe unsafe;
|
||||||
if (addressField != null && cleanerField != null) {
|
if (addressField != null) {
|
||||||
try {
|
try {
|
||||||
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
|
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
|
||||||
unsafeField.setAccessible(true);
|
unsafeField.setAccessible(true);
|
||||||
@ -127,11 +112,9 @@ final class PlatformDependent0 {
|
|||||||
|
|
||||||
if (unsafe == null) {
|
if (unsafe == null) {
|
||||||
ADDRESS_FIELD_OFFSET = -1;
|
ADDRESS_FIELD_OFFSET = -1;
|
||||||
CLEANER_FIELD_OFFSET = -1;
|
|
||||||
UNALIGNED = false;
|
UNALIGNED = false;
|
||||||
} else {
|
} else {
|
||||||
ADDRESS_FIELD_OFFSET = objectFieldOffset(addressField);
|
ADDRESS_FIELD_OFFSET = objectFieldOffset(addressField);
|
||||||
CLEANER_FIELD_OFFSET = objectFieldOffset(cleanerField);
|
|
||||||
boolean unaligned;
|
boolean unaligned;
|
||||||
try {
|
try {
|
||||||
Class<?> bitsClass = Class.forName("java.nio.Bits", false, ClassLoader.getSystemClassLoader());
|
Class<?> bitsClass = Class.forName("java.nio.Bits", false, ClassLoader.getSystemClassLoader());
|
||||||
@ -148,9 +131,6 @@ final class PlatformDependent0 {
|
|||||||
UNALIGNED = unaligned;
|
UNALIGNED = unaligned;
|
||||||
logger.debug("java.nio.Bits.unaligned: {}", UNALIGNED);
|
logger.debug("java.nio.Bits.unaligned: {}", UNALIGNED);
|
||||||
}
|
}
|
||||||
|
|
||||||
// free temporary buffer if possible
|
|
||||||
freeDirectBuffer(direct);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean hasUnsafe() {
|
static boolean hasUnsafe() {
|
||||||
@ -162,17 +142,9 @@ final class PlatformDependent0 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void freeDirectBuffer(ByteBuffer buffer) {
|
static void freeDirectBuffer(ByteBuffer buffer) {
|
||||||
if (CLEANER_FIELD_OFFSET == -1 || !buffer.isDirect()) {
|
// Delegate to other class to not break on android
|
||||||
return;
|
// See https://github.com/netty/netty/issues/2604
|
||||||
}
|
Cleaner0.freeDirectBuffer(buffer);
|
||||||
try {
|
|
||||||
Cleaner cleaner = (Cleaner) getObject(buffer, CLEANER_FIELD_OFFSET);
|
|
||||||
if (cleaner != null) {
|
|
||||||
cleaner.clean();
|
|
||||||
}
|
|
||||||
} catch (Throwable t) {
|
|
||||||
// Nothing we can do here.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static long directBufferAddress(ByteBuffer buffer) {
|
static long directBufferAddress(ByteBuffer buffer) {
|
||||||
|
Loading…
Reference in New Issue
Block a user