/* * Copyright (c) Facebook, Inc. and its affiliates. * * Licensed 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 com.facebook.jni; import com.facebook.jni.annotations.DoNotStripAny; /** * This object holds a native C++ member for hybrid Java/C++ objects. * *

NB: THREAD SAFETY * *

{@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. */ @DoNotStripAny public class HybridData { static { System.loadLibrary("fbjni"); } private final 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 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 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: * *


   * synchronized(hybrid) {
   *   if (hybrid.isValid) {
   *     // Do stuff.
   *   }
   * }
   * 
*/ public boolean isValid() { return mDestructor.mNativePointer != 0; } @DoNotStripAny public static class Destructor extends DestructorThread.Destructor { // Private C++ instance private volatile long mNativePointer; Destructor(Object referent) { super(referent); } @Override protected final 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); } }