/* * Copyright 2017 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ // Originally these classes are from Chromium. // https://cs.chromium.org/chromium/src/base/android/scoped_java_ref.h. #ifndef SDK_ANDROID_NATIVE_API_JNI_SCOPED_JAVA_REF_H_ #define SDK_ANDROID_NATIVE_API_JNI_SCOPED_JAVA_REF_H_ #include #include #include "rtc_base/constructor_magic.h" #include "sdk/android/native_api/jni/jvm.h" namespace webrtc { // Generic base class for ScopedJavaLocalRef and ScopedJavaGlobalRef. Useful // for allowing functions to accept a reference without having to mandate // whether it is a local or global type. template class JavaRef; // Template specialization of JavaRef, which acts as the base class for all // other JavaRef<> template types. This allows you to e.g. pass JavaRef // into a function taking const JavaRef&. template <> class JavaRef { public: jobject obj() const { return obj_; } bool is_null() const { // This is not valid for weak references. For weak references you need to // use env->IsSameObject(objc_, nullptr), but that should be avoided anyway // since it does not prevent the object from being freed immediately // thereafter. Consequently, programmers should not use this check on weak // references anyway and should first make a ScopedJavaLocalRef or // ScopedJavaGlobalRef before checking if it is null. return obj_ == nullptr; } protected: constexpr JavaRef() : obj_(nullptr) {} explicit JavaRef(jobject obj) : obj_(obj) {} jobject obj_; private: RTC_DISALLOW_COPY_AND_ASSIGN(JavaRef); }; template class JavaRef : public JavaRef { public: T obj() const { return static_cast(obj_); } protected: JavaRef() : JavaRef(nullptr) {} explicit JavaRef(T obj) : JavaRef(obj) {} private: RTC_DISALLOW_COPY_AND_ASSIGN(JavaRef); }; // Holds a local reference to a JNI method parameter. // Method parameters should not be deleted, and so this class exists purely to // wrap them as a JavaRef in the JNI binding generator. Do not create // instances manually. template class JavaParamRef : public JavaRef { public: // Assumes that |obj| is a parameter passed to a JNI method from Java. // Does not assume ownership as parameters should not be deleted. explicit JavaParamRef(T obj) : JavaRef(obj) {} JavaParamRef(JNIEnv*, T obj) : JavaRef(obj) {} private: RTC_DISALLOW_COPY_AND_ASSIGN(JavaParamRef); }; // Holds a local reference to a Java object. The local reference is scoped // to the lifetime of this object. // Instances of this class may hold onto any JNIEnv passed into it until // destroyed. Therefore, since a JNIEnv is only suitable for use on a single // thread, objects of this class must be created, used, and destroyed, on a // single thread. // Therefore, this class should only be used as a stack-based object and from a // single thread. If you wish to have the reference outlive the current // callstack (e.g. as a class member) or you wish to pass it across threads, // use a ScopedJavaGlobalRef instead. template class ScopedJavaLocalRef : public JavaRef { public: ScopedJavaLocalRef() = default; ScopedJavaLocalRef(std::nullptr_t) {} // NOLINT(runtime/explicit) ScopedJavaLocalRef(JNIEnv* env, const JavaRef& other) : env_(env) { Reset(other.obj(), OwnershipPolicy::RETAIN); } // Allow constructing e.g. ScopedJavaLocalRef from // ScopedJavaLocalRef. template ScopedJavaLocalRef(ScopedJavaLocalRef&& other) : env_(other.env()) { Reset(other.Release(), OwnershipPolicy::ADOPT); } ScopedJavaLocalRef(const ScopedJavaLocalRef& other) : env_(other.env_) { Reset(other.obj(), OwnershipPolicy::RETAIN); } // Assumes that |obj| is a reference to a Java object and takes // ownership of this reference. This should preferably not be used // outside of JNI helper functions. ScopedJavaLocalRef(JNIEnv* env, T obj) : JavaRef(obj), env_(env) {} ~ScopedJavaLocalRef() { if (obj_ != nullptr) env_->DeleteLocalRef(obj_); } void operator=(const ScopedJavaLocalRef& other) { Reset(other.obj(), OwnershipPolicy::RETAIN); } void operator=(ScopedJavaLocalRef&& other) { Reset(other.Release(), OwnershipPolicy::ADOPT); } // Releases the reference to the caller. The caller *must* delete the // reference when it is done with it. Note that calling a Java method // is *not* a transfer of ownership and Release() should not be used. T Release() { T obj = static_cast(obj_); obj_ = nullptr; return obj; } JNIEnv* env() const { return env_; } private: using JavaRef::obj_; enum OwnershipPolicy { // The scoped object takes ownership of an object by taking over an existing // ownership claim. ADOPT, // The scoped object will retain the the object and any initial ownership is // not changed. RETAIN }; void Reset(T obj, OwnershipPolicy policy) { if (obj_ != nullptr) env_->DeleteLocalRef(obj_); obj_ = (obj != nullptr && policy == OwnershipPolicy::RETAIN) ? env_->NewLocalRef(obj) : obj; } JNIEnv* const env_ = AttachCurrentThreadIfNeeded(); }; // Holds a global reference to a Java object. The global reference is scoped // to the lifetime of this object. This class does not hold onto any JNIEnv* // passed to it, hence it is safe to use across threads (within the constraints // imposed by the underlying Java object that it references). template class ScopedJavaGlobalRef : public JavaRef { public: using JavaRef::obj_; explicit constexpr ScopedJavaGlobalRef(std::nullptr_t) {} ScopedJavaGlobalRef(JNIEnv* env, const JavaRef& other) : JavaRef(static_cast(env->NewGlobalRef(other.obj()))) {} explicit ScopedJavaGlobalRef(const ScopedJavaLocalRef& other) : ScopedJavaGlobalRef(other.env(), other) {} ScopedJavaGlobalRef(ScopedJavaGlobalRef&& other) : JavaRef(other.Release()) {} ~ScopedJavaGlobalRef() { if (obj_ != nullptr) AttachCurrentThreadIfNeeded()->DeleteGlobalRef(obj_); } // Releases the reference to the caller. The caller *must* delete the // reference when it is done with it. Note that calling a Java method // is *not* a transfer of ownership and Release() should not be used. T Release() { T obj = static_cast(obj_); obj_ = nullptr; return obj; } private: RTC_DISALLOW_COPY_AND_ASSIGN(ScopedJavaGlobalRef); }; template inline ScopedJavaLocalRef static_java_ref_cast(JNIEnv* env, JavaRef const& ref) { ScopedJavaLocalRef owned_ref(env, ref); return ScopedJavaLocalRef(env, static_cast(owned_ref.Release())); } } // namespace webrtc #endif // SDK_ANDROID_NATIVE_API_JNI_SCOPED_JAVA_REF_H_