| /* |
| * 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. |
| * |
| * <p>NB: THREAD SAFETY |
| * |
| * <p>{@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: |
| * |
| * <pre><code> |
| * synchronized(hybrid) { |
| * if (hybrid.isValid) { |
| * // Do stuff. |
| * } |
| * } |
| * </code></pre> |
| */ |
| 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); |
| } |
| } |