1*65c59e02SInna Palant /* 2*65c59e02SInna Palant * Copyright (c) Facebook, Inc. and its affiliates. 3*65c59e02SInna Palant * 4*65c59e02SInna Palant * Licensed under the Apache License, Version 2.0 (the "License"); 5*65c59e02SInna Palant * you may not use this file except in compliance with the License. 6*65c59e02SInna Palant * You may obtain a copy of the License at 7*65c59e02SInna Palant * 8*65c59e02SInna Palant * http://www.apache.org/licenses/LICENSE-2.0 9*65c59e02SInna Palant * 10*65c59e02SInna Palant * Unless required by applicable law or agreed to in writing, software 11*65c59e02SInna Palant * distributed under the License is distributed on an "AS IS" BASIS, 12*65c59e02SInna Palant * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*65c59e02SInna Palant * See the License for the specific language governing permissions and 14*65c59e02SInna Palant * limitations under the License. 15*65c59e02SInna Palant */ 16*65c59e02SInna Palant 17*65c59e02SInna Palant package com.facebook.jni; 18*65c59e02SInna Palant 19*65c59e02SInna Palant import com.facebook.jni.annotations.DoNotStripAny; 20*65c59e02SInna Palant 21*65c59e02SInna Palant /** 22*65c59e02SInna Palant * This object holds a native C++ member for hybrid Java/C++ objects. 23*65c59e02SInna Palant * 24*65c59e02SInna Palant * <p>NB: THREAD SAFETY 25*65c59e02SInna Palant * 26*65c59e02SInna Palant * <p>{@link #resetNative} deletes the corresponding native object synchronously on whatever thread 27*65c59e02SInna Palant * the method is called on. Otherwise, deletion will occur on the {@link DestructorThread} thread. 28*65c59e02SInna Palant */ 29*65c59e02SInna Palant @DoNotStripAny 30*65c59e02SInna Palant public class HybridData { 31*65c59e02SInna Palant 32*65c59e02SInna Palant static { 33*65c59e02SInna Palant System.loadLibrary("fbjni"); 34*65c59e02SInna Palant } 35*65c59e02SInna Palant 36*65c59e02SInna Palant private final Destructor mDestructor = new Destructor(this); 37*65c59e02SInna Palant 38*65c59e02SInna Palant /** 39*65c59e02SInna Palant * To explicitly delete the instance, call resetNative(). If the C++ instance is referenced after 40*65c59e02SInna Palant * this is called, a NullPointerException will be thrown. resetNative() may be called multiple 41*65c59e02SInna Palant * times safely. Because the {@link DestructorThread} also calls resetNative, the instance will 42*65c59e02SInna Palant * not leak if this is not called, but timing of deletion and the thread the C++ dtor is called on 43*65c59e02SInna Palant * will be at the whim of the Java GC. If you want to control the thread and timing of the 44*65c59e02SInna Palant * destructor, you should call resetNative() explicitly. 45*65c59e02SInna Palant */ resetNative()46*65c59e02SInna Palant public synchronized void resetNative() { 47*65c59e02SInna Palant mDestructor.destruct(); 48*65c59e02SInna Palant } 49*65c59e02SInna Palant 50*65c59e02SInna Palant /** 51*65c59e02SInna Palant * N.B. Thread safety. If you call isValid from a different thread than {@link #resetNative()} 52*65c59e02SInna Palant * then be sure to do so while synchronizing on the hybrid. For example: 53*65c59e02SInna Palant * 54*65c59e02SInna Palant * <pre><code> 55*65c59e02SInna Palant * synchronized(hybrid) { 56*65c59e02SInna Palant * if (hybrid.isValid) { 57*65c59e02SInna Palant * // Do stuff. 58*65c59e02SInna Palant * } 59*65c59e02SInna Palant * } 60*65c59e02SInna Palant * </code></pre> 61*65c59e02SInna Palant */ isValid()62*65c59e02SInna Palant public boolean isValid() { 63*65c59e02SInna Palant return mDestructor.mNativePointer != 0; 64*65c59e02SInna Palant } 65*65c59e02SInna Palant 66*65c59e02SInna Palant @DoNotStripAny 67*65c59e02SInna Palant public static class Destructor extends DestructorThread.Destructor { 68*65c59e02SInna Palant 69*65c59e02SInna Palant // Private C++ instance 70*65c59e02SInna Palant private volatile long mNativePointer; 71*65c59e02SInna Palant Destructor(Object referent)72*65c59e02SInna Palant Destructor(Object referent) { 73*65c59e02SInna Palant super(referent); 74*65c59e02SInna Palant } 75*65c59e02SInna Palant 76*65c59e02SInna Palant @Override destruct()77*65c59e02SInna Palant protected final void destruct() { 78*65c59e02SInna Palant // When invoked from the DestructorThread instead of resetNative, 79*65c59e02SInna Palant // the DestructorThread has exclusive ownership of the HybridData 80*65c59e02SInna Palant // so synchronization is not necessary. 81*65c59e02SInna Palant deleteNative(mNativePointer); 82*65c59e02SInna Palant mNativePointer = 0; 83*65c59e02SInna Palant } 84*65c59e02SInna Palant deleteNative(long pointer)85*65c59e02SInna Palant static native void deleteNative(long pointer); 86*65c59e02SInna Palant } 87*65c59e02SInna Palant } 88