Add missing Java files to RN fbjni sync
Reviewed By: mhorowitz Differential Revision: D5129224 fbshipit-source-id: d9fb5f95505f6be7d3d87ead67dbfaa951c03434
This commit is contained in:
parent
b11dc39430
commit
f0e4a6cd2c
|
@ -0,0 +1,27 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
package com.facebook.jni;
|
||||
|
||||
import com.facebook.proguard.annotations.DoNotStrip;
|
||||
import com.facebook.soloader.SoLoader;
|
||||
|
||||
/**
|
||||
* Utility class to determine CPU capabilities
|
||||
*/
|
||||
@DoNotStrip
|
||||
public class CpuCapabilitiesJni {
|
||||
|
||||
static {
|
||||
SoLoader.loadLibrary("fb");
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
public static native boolean nativeDeviceSupportsNeon();
|
||||
|
||||
@DoNotStrip
|
||||
public static native boolean nativeDeviceSupportsVFPFP16();
|
||||
|
||||
@DoNotStrip
|
||||
public static native boolean nativeDeviceSupportsX86();
|
||||
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
package com.facebook.jni;
|
||||
|
||||
import java.lang.ref.PhantomReference;
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* A thread which invokes the "destruct" routine for objects after they have been garbage collected.
|
||||
*
|
||||
* An object which needs to be destructed should create a static subclass of {@link Destructor}.
|
||||
* Once the referent object is garbage collected, the DestructorThread will callback to the
|
||||
* {@link Destructor#destruct()} method.
|
||||
*
|
||||
* The underlying thread in DestructorThread starts when the first Destructor is constructed
|
||||
* and then runs indefinitely.
|
||||
*/
|
||||
public class DestructorThread {
|
||||
|
||||
/**
|
||||
* N.B The Destructor <b>SHOULD NOT</b> refer back to its referent object either explicitly or
|
||||
* implicitly (for example, as a non-static inner class). This will create a reference cycle where
|
||||
* the referent object will never be garbage collected.
|
||||
*/
|
||||
public abstract static class Destructor extends PhantomReference<Object> {
|
||||
|
||||
private Destructor next;
|
||||
private Destructor previous;
|
||||
|
||||
Destructor(Object referent) {
|
||||
super(referent, sReferenceQueue);
|
||||
sDestructorStack.push(this);
|
||||
}
|
||||
|
||||
private Destructor() {
|
||||
super(null, sReferenceQueue);
|
||||
}
|
||||
|
||||
/** Callback which is invoked when the original object has been garbage collected. */
|
||||
abstract void destruct();
|
||||
}
|
||||
|
||||
/** A list to keep all active Destructors in memory confined to the Destructor thread. */
|
||||
private static DestructorList sDestructorList;
|
||||
/** A thread safe stack where new Destructors are placed before being add to sDestructorList. */
|
||||
private static DestructorStack sDestructorStack;
|
||||
private static ReferenceQueue sReferenceQueue;
|
||||
private static Thread sThread;
|
||||
|
||||
static {
|
||||
sDestructorStack = new DestructorStack();
|
||||
sReferenceQueue = new ReferenceQueue();
|
||||
sDestructorList = new DestructorList();
|
||||
sThread = new Thread("HybridData DestructorThread") {
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
try {
|
||||
Destructor current = (Destructor) sReferenceQueue.remove();
|
||||
current.destruct();
|
||||
|
||||
// If current is in the sDestructorStack,
|
||||
// transfer all the Destructors in the stack to the list.
|
||||
if (current.previous == null) {
|
||||
sDestructorStack.transferAllToList();
|
||||
}
|
||||
|
||||
DestructorList.drop(current);
|
||||
} catch (InterruptedException e) {
|
||||
// Continue. This thread should never be terminated.
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
sThread.start();
|
||||
}
|
||||
|
||||
private static class Terminus extends Destructor {
|
||||
@Override
|
||||
void destruct() {
|
||||
throw new IllegalStateException("Cannot destroy Terminus Destructor.");
|
||||
}
|
||||
}
|
||||
|
||||
/** This is a thread safe, lock-free Treiber-like Stack of Destructors. */
|
||||
private static class DestructorStack {
|
||||
private AtomicReference<Destructor> mHead = new AtomicReference<>();
|
||||
|
||||
public void push(Destructor newHead) {
|
||||
Destructor oldHead;
|
||||
do {
|
||||
oldHead = mHead.get();
|
||||
newHead.next = oldHead;
|
||||
} while (!mHead.compareAndSet(oldHead, newHead));
|
||||
}
|
||||
|
||||
public void transferAllToList() {
|
||||
Destructor current = mHead.getAndSet(null);
|
||||
while (current != null) {
|
||||
Destructor next = current.next;
|
||||
sDestructorList.enqueue(current);
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** A doubly-linked list of Destructors. */
|
||||
private static class DestructorList {
|
||||
private Destructor mHead;
|
||||
|
||||
public DestructorList() {
|
||||
mHead = new Terminus();
|
||||
mHead.next = new Terminus();
|
||||
mHead.next.previous = mHead;
|
||||
}
|
||||
|
||||
public void enqueue(Destructor current) {
|
||||
current.next = mHead.next;
|
||||
mHead.next = current;
|
||||
|
||||
current.next.previous = current;
|
||||
current.previous = mHead;
|
||||
}
|
||||
|
||||
private static void drop(Destructor current) {
|
||||
current.next.previous = current.previous;
|
||||
current.previous.next = current.next;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
package com.facebook.jni;
|
||||
import com.facebook.proguard.annotations.DoNotStrip;
|
||||
|
||||
@DoNotStrip
|
||||
public abstract class HybridClassBase extends HybridData {
|
||||
}
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
package com.facebook.jni;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.facebook.proguard.annotations.DoNotStrip;
|
||||
import com.facebook.soloader.SoLoader;
|
||||
|
||||
|
@ -10,11 +12,9 @@ import com.facebook.soloader.SoLoader;
|
|||
*
|
||||
* NB: THREAD SAFETY
|
||||
*
|
||||
* {@link #dispose} deletes the corresponding native object on whatever thread
|
||||
* the method is called on. In the common case when this is called by
|
||||
* HybridData#finalize(), this will be called on the system finalizer
|
||||
* thread. If you manually call resetNative() on the Java object, the C++
|
||||
* object will be deleted synchronously on that thread.
|
||||
* {@link #resetNative} deletes the corresponding native object synchronously on whatever thread
|
||||
* the method is called on. Otherwise, deletion will occur on the {@link DestructorThread}
|
||||
* thread.
|
||||
*/
|
||||
@DoNotStrip
|
||||
public class HybridData {
|
||||
|
@ -23,27 +23,57 @@ public class HybridData {
|
|||
SoLoader.loadLibrary("fb");
|
||||
}
|
||||
|
||||
// Private C++ instance
|
||||
@DoNotStrip
|
||||
private long mNativePointer = 0;
|
||||
private Destructor mDestructor = new Destructor(this);
|
||||
|
||||
/**
|
||||
* To explicitly delete the instance, call resetNative(). If the C++
|
||||
* instance is referenced after this is called, a NullPointerException will
|
||||
* be thrown. resetNative() may be called multiple times safely. Because
|
||||
* {@link #finalize} calls resetNative, the instance will not leak if this is
|
||||
* the {@link DestructorThread} also calls resetNative, the instance will not leak if this is
|
||||
* not called, but timing of deletion and the thread the C++ dtor is called
|
||||
* on will be at the whim of the Java GC. If you want to control the thread
|
||||
* and timing of the destructor, you should call resetNative() explicitly.
|
||||
*/
|
||||
public native void resetNative();
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
resetNative();
|
||||
super.finalize();
|
||||
public synchronized void resetNative() {
|
||||
mDestructor.destruct();
|
||||
}
|
||||
|
||||
/**
|
||||
* N.B. Thread safety.
|
||||
* If you call isValid from a different thread than {@link #resetNative()} then be sure to
|
||||
* do so while synchronizing on the hybrid. For example:
|
||||
* <pre><code>
|
||||
* synchronized(hybrid) {
|
||||
* if (hybrid.isValid) {
|
||||
* // Do stuff.
|
||||
* }
|
||||
* }
|
||||
* </code></pre>
|
||||
*/
|
||||
public boolean isValid() {
|
||||
return mNativePointer != 0;
|
||||
return mDestructor.mNativePointer != 0;
|
||||
}
|
||||
|
||||
public static class Destructor extends DestructorThread.Destructor {
|
||||
|
||||
// Private C++ instance
|
||||
@DoNotStrip
|
||||
private long mNativePointer;
|
||||
|
||||
Destructor(Object referent) {
|
||||
super(referent);
|
||||
}
|
||||
|
||||
@Override
|
||||
void destruct() {
|
||||
// When invoked from the DestructorThread instead of resetNative,
|
||||
// the DestructorThread has exclusive ownership of the HybridData
|
||||
// so synchronization is not necessary.
|
||||
deleteNative(mNativePointer);
|
||||
mNativePointer = 0;
|
||||
}
|
||||
|
||||
static native void deleteNative(long pointer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
package com.facebook.jni;
|
||||
|
||||
public class JniTerminateHandler {
|
||||
public static void handleTerminate(Throwable t) throws Throwable {
|
||||
Thread.UncaughtExceptionHandler h = Thread.getDefaultUncaughtExceptionHandler();
|
||||
if (h == null) {
|
||||
// Odd. Let the default std::terminate_handler deal with it.
|
||||
return;
|
||||
}
|
||||
h.uncaughtException(Thread.currentThread(), t);
|
||||
// That should exit. If it doesn't, let the default handler deal with it.
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue