[#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.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ package io.netty.util.internal;
|
||||
|
||||
import io.netty.util.internal.logging.InternalLogger;
|
||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||
import sun.misc.Cleaner;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
@ -40,7 +39,6 @@ final class PlatformDependent0 {
|
||||
private static final Unsafe UNSAFE;
|
||||
private static final boolean BIG_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
|
||||
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
|
||||
@ -57,19 +55,6 @@ final class PlatformDependent0 {
|
||||
|
||||
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) {
|
||||
// We don't have ByteBuffer.cleaner().
|
||||
cleanerField = null;
|
||||
}
|
||||
|
||||
logger.debug("java.nio.ByteBuffer.cleaner(): {}", cleanerField != null? "available" : "unavailable");
|
||||
|
||||
Field addressField;
|
||||
try {
|
||||
addressField = Buffer.class.getDeclaredField("address");
|
||||
@ -90,7 +75,7 @@ final class PlatformDependent0 {
|
||||
logger.debug("java.nio.Buffer.address: {}", addressField != null? "available" : "unavailable");
|
||||
|
||||
Unsafe unsafe;
|
||||
if (addressField != null && cleanerField != null) {
|
||||
if (addressField != null) {
|
||||
try {
|
||||
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
|
||||
unsafeField.setAccessible(true);
|
||||
@ -127,11 +112,9 @@ final class PlatformDependent0 {
|
||||
|
||||
if (unsafe == null) {
|
||||
ADDRESS_FIELD_OFFSET = -1;
|
||||
CLEANER_FIELD_OFFSET = -1;
|
||||
UNALIGNED = false;
|
||||
} else {
|
||||
ADDRESS_FIELD_OFFSET = objectFieldOffset(addressField);
|
||||
CLEANER_FIELD_OFFSET = objectFieldOffset(cleanerField);
|
||||
boolean unaligned;
|
||||
try {
|
||||
Class<?> bitsClass = Class.forName("java.nio.Bits", false, ClassLoader.getSystemClassLoader());
|
||||
@ -148,9 +131,6 @@ final class PlatformDependent0 {
|
||||
UNALIGNED = unaligned;
|
||||
logger.debug("java.nio.Bits.unaligned: {}", UNALIGNED);
|
||||
}
|
||||
|
||||
// free temporary buffer if possible
|
||||
freeDirectBuffer(direct);
|
||||
}
|
||||
|
||||
static boolean hasUnsafe() {
|
||||
@ -162,17 +142,9 @@ final class PlatformDependent0 {
|
||||
}
|
||||
|
||||
static void freeDirectBuffer(ByteBuffer buffer) {
|
||||
if (CLEANER_FIELD_OFFSET == -1 || !buffer.isDirect()) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Cleaner cleaner = (Cleaner) getObject(buffer, CLEANER_FIELD_OFFSET);
|
||||
if (cleaner != null) {
|
||||
cleaner.clean();
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
// Nothing we can do here.
|
||||
}
|
||||
// Delegate to other class to not break on android
|
||||
// See https://github.com/netty/netty/issues/2604
|
||||
Cleaner0.freeDirectBuffer(buffer);
|
||||
}
|
||||
|
||||
static long directBufferAddress(ByteBuffer buffer) {
|
||||
|
Loading…
Reference in New Issue
Block a user