The Android FML backend. (#3489)

This commit is contained in:
Chinmay Garde 2017-03-20 15:18:01 -07:00 committed by GitHub
parent 117679f92e
commit 30ab542443
9 changed files with 792 additions and 0 deletions

View File

@ -0,0 +1,184 @@
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/fml/platform/android/jni_util.h"
#include <codecvt>
#include <string>
#include "lib/ftl/logging.h"
namespace fml {
namespace jni {
static JavaVM* g_jvm = nullptr;
static ScopedJavaGlobalRef<jobject>* g_android_application_context = nullptr;
#define ASSERT_NO_EXCEPTION() FTL_CHECK(env->ExceptionCheck() == JNI_FALSE);
void InitJavaVM(JavaVM* vm) {
FTL_DCHECK(g_jvm == nullptr);
g_jvm = vm;
}
JNIEnv* AttachCurrentThread() {
FTL_DCHECK(g_jvm != nullptr)
<< "Trying to attach to current thread without calling InitJavaVM first.";
JNIEnv* env = nullptr;
jint ret = g_jvm->AttachCurrentThread(&env, nullptr);
FTL_DCHECK(JNI_OK == ret);
return env;
}
void DetachFromVM() {
if (g_jvm) {
g_jvm->DetachCurrentThread();
}
}
void InitAndroidApplicationContext(const JavaRef<jobject>& context) {
FTL_DCHECK(g_android_application_context == nullptr);
g_android_application_context = new ScopedJavaGlobalRef<jobject>(context);
FTL_DCHECK(g_android_application_context->obj() != nullptr);
}
const jobject GetAndroidApplicationContext() {
jobject object = g_android_application_context->obj();
FTL_DCHECK(object != nullptr)
<< "Trying to get Android application context without first calling "
"InitAndroidApplicationContext.";
return object;
}
static std::string UTF16StringToUTF8String(const char16_t* chars, size_t len) {
std::u16string u16_string(chars, len);
return std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}
.to_bytes(u16_string);
}
std::string JavaStringToString(JNIEnv* env, jstring str) {
if (env == nullptr || str == nullptr) {
return "";
}
const jchar* chars = env->GetStringChars(str, NULL);
if (chars == nullptr) {
return "";
}
std::string u8_string = UTF16StringToUTF8String(
reinterpret_cast<const char16_t*>(chars), env->GetStringLength(str));
env->ReleaseStringChars(str, chars);
ASSERT_NO_EXCEPTION();
return u8_string;
}
static std::u16string UTF8StringToUTF16String(const std::string& string) {
return std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}
.from_bytes(string);
}
ScopedJavaLocalRef<jstring> StringToJavaString(JNIEnv* env,
const std::string& u8_string) {
std::u16string u16_string = UTF8StringToUTF16String(u8_string);
auto result = ScopedJavaLocalRef<jstring>(
env, env->NewString(reinterpret_cast<const jchar*>(u16_string.data()),
u16_string.length()));
ASSERT_NO_EXCEPTION();
return result;
}
std::vector<std::string> StringArrayToVector(JNIEnv* env, jobjectArray array) {
std::vector<std::string> out;
if (env == nullptr || array == nullptr) {
return out;
}
jsize length = env->GetArrayLength(array);
if (length == -1) {
return out;
}
out.resize(length);
for (size_t i = 0; i < length; ++i) {
ScopedJavaLocalRef<jstring> java_string(
env, static_cast<jstring>(env->GetObjectArrayElement(array, i)));
out[i] = JavaStringToString(env, java_string.obj());
}
return out;
}
ScopedJavaLocalRef<jobjectArray> VectorToStringArray(
JNIEnv* env,
const std::vector<std::string>& vector) {
FTL_DCHECK(env);
ScopedJavaLocalRef<jclass> string_clazz(env,
env->FindClass("java/lang/String"));
FTL_DCHECK(!string_clazz.is_null());
jobjectArray joa =
env->NewObjectArray(vector.size(), string_clazz.obj(), NULL);
ASSERT_NO_EXCEPTION();
for (size_t i = 0; i < vector.size(); ++i) {
ScopedJavaLocalRef<jstring> item = StringToJavaString(env, vector[i]);
env->SetObjectArrayElement(joa, i, item.obj());
}
return ScopedJavaLocalRef<jobjectArray>(env, joa);
}
bool HasException(JNIEnv* env) {
return env->ExceptionCheck() != JNI_FALSE;
}
bool ClearException(JNIEnv* env) {
if (!HasException(env))
return false;
env->ExceptionDescribe();
env->ExceptionClear();
return true;
}
std::string GetJavaExceptionInfo(JNIEnv* env, jthrowable java_throwable) {
ScopedJavaLocalRef<jclass> throwable_clazz(
env, env->FindClass("java/lang/Throwable"));
jmethodID throwable_printstacktrace = env->GetMethodID(
throwable_clazz.obj(), "printStackTrace", "(Ljava/io/PrintStream;)V");
// Create an instance of ByteArrayOutputStream.
ScopedJavaLocalRef<jclass> bytearray_output_stream_clazz(
env, env->FindClass("java/io/ByteArrayOutputStream"));
jmethodID bytearray_output_stream_constructor =
env->GetMethodID(bytearray_output_stream_clazz.obj(), "<init>", "()V");
jmethodID bytearray_output_stream_tostring = env->GetMethodID(
bytearray_output_stream_clazz.obj(), "toString", "()Ljava/lang/String;");
ScopedJavaLocalRef<jobject> bytearray_output_stream(
env, env->NewObject(bytearray_output_stream_clazz.obj(),
bytearray_output_stream_constructor));
// Create an instance of PrintStream.
ScopedJavaLocalRef<jclass> printstream_clazz(
env, env->FindClass("java/io/PrintStream"));
jmethodID printstream_constructor = env->GetMethodID(
printstream_clazz.obj(), "<init>", "(Ljava/io/OutputStream;)V");
ScopedJavaLocalRef<jobject> printstream(
env, env->NewObject(printstream_clazz.obj(), printstream_constructor,
bytearray_output_stream.obj()));
// Call Throwable.printStackTrace(PrintStream)
env->CallVoidMethod(java_throwable, throwable_printstacktrace,
printstream.obj());
// Call ByteArrayOutputStream.toString()
ScopedJavaLocalRef<jstring> exception_string(
env,
static_cast<jstring>(env->CallObjectMethod(
bytearray_output_stream.obj(), bytearray_output_stream_tostring)));
return JavaStringToString(env, exception_string.obj());
}
} // namespace jni
} // namespace fml

View File

@ -0,0 +1,48 @@
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_FML_PLATFORM_ANDROID_JNI_UTIL_H_
#define FLUTTER_FML_PLATFORM_ANDROID_JNI_UTIL_H_
#include <jni.h>
#include <vector>
#include "flutter/fml/platform/android/scoped_java_ref.h"
#include "lib/ftl/macros.h"
namespace fml {
namespace jni {
void InitJavaVM(JavaVM* vm);
JNIEnv* AttachCurrentThread();
void DetachFromVM();
void InitAndroidApplicationContext(const JavaRef<jobject>& context);
const jobject GetAndroidApplicationContext();
std::string JavaStringToString(JNIEnv* env, jstring string);
ScopedJavaLocalRef<jstring> StringToJavaString(JNIEnv* env,
const std::string& str);
std::vector<std::string> StringArrayToVector(JNIEnv* env, jobjectArray jargs);
ScopedJavaLocalRef<jobjectArray> VectorToStringArray(
JNIEnv* env,
const std::vector<std::string>& vector);
bool HasException(JNIEnv* env);
bool ClearException(JNIEnv* env);
std::string GetJavaExceptionInfo(JNIEnv* env, jthrowable java_throwable);
} // namespace jni
} // namespace fml
#endif // FLUTTER_FML_PLATFORM_ANDROID_JNI_UTIL_H_

View File

@ -0,0 +1,67 @@
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/fml/platform/android/jni_weak_ref.h"
#include "flutter/fml/platform/android/jni_util.h"
#include "lib/ftl/logging.h"
namespace fml {
namespace jni {
JavaObjectWeakGlobalRef::JavaObjectWeakGlobalRef() : obj_(NULL) {}
JavaObjectWeakGlobalRef::JavaObjectWeakGlobalRef(
const JavaObjectWeakGlobalRef& orig)
: obj_(NULL) {
Assign(orig);
}
JavaObjectWeakGlobalRef::JavaObjectWeakGlobalRef(JNIEnv* env, jobject obj)
: obj_(env->NewWeakGlobalRef(obj)) {
FTL_DCHECK(obj_);
}
JavaObjectWeakGlobalRef::~JavaObjectWeakGlobalRef() {
reset();
}
void JavaObjectWeakGlobalRef::operator=(const JavaObjectWeakGlobalRef& rhs) {
Assign(rhs);
}
void JavaObjectWeakGlobalRef::reset() {
if (obj_) {
AttachCurrentThread()->DeleteWeakGlobalRef(obj_);
obj_ = NULL;
}
}
ScopedJavaLocalRef<jobject> JavaObjectWeakGlobalRef::get(JNIEnv* env) const {
return GetRealObject(env, obj_);
}
ScopedJavaLocalRef<jobject> GetRealObject(JNIEnv* env, jweak obj) {
jobject real = NULL;
if (obj) {
real = env->NewLocalRef(obj);
if (!real)
FTL_DLOG(ERROR) << "The real object has been deleted!";
}
return ScopedJavaLocalRef<jobject>(env, real);
}
void JavaObjectWeakGlobalRef::Assign(const JavaObjectWeakGlobalRef& other) {
if (&other == this)
return;
JNIEnv* env = AttachCurrentThread();
if (obj_)
env->DeleteWeakGlobalRef(obj_);
obj_ = other.obj_ ? env->NewWeakGlobalRef(other.obj_) : NULL;
}
} // namespace jni
} // namespace fml

View File

@ -0,0 +1,50 @@
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_FML_PLATFORM_ANDROID_JNI_WEAK_REF_H_
#define FLUTTER_FML_PLATFORM_ANDROID_JNI_WEAK_REF_H_
#include <jni.h>
#include "flutter/fml/platform/android/scoped_java_ref.h"
namespace fml {
namespace jni {
// Manages WeakGlobalRef lifecycle.
// This class is not thread-safe w.r.t. get() and reset(). Multiple threads may
// safely use get() concurrently, but if the user calls reset() (or of course,
// calls the destructor) they'll need to provide their own synchronization.
class JavaObjectWeakGlobalRef {
public:
JavaObjectWeakGlobalRef();
JavaObjectWeakGlobalRef(const JavaObjectWeakGlobalRef& orig);
JavaObjectWeakGlobalRef(JNIEnv* env, jobject obj);
virtual ~JavaObjectWeakGlobalRef();
void operator=(const JavaObjectWeakGlobalRef& rhs);
ScopedJavaLocalRef<jobject> get(JNIEnv* env) const;
bool is_empty() const { return obj_ == NULL; }
void reset();
private:
void Assign(const JavaObjectWeakGlobalRef& rhs);
jweak obj_;
};
// Get the real object stored in the weak reference returned as a
// ScopedJavaLocalRef.
ScopedJavaLocalRef<jobject> GetRealObject(JNIEnv* env, jweak obj);
} // namespace jni
} // namespace fml
#endif // FLUTTER_FML_PLATFORM_ANDROID_JNI_WEAK_REF_H_

View File

@ -0,0 +1,97 @@
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/fml/platform/android/message_loop_android.h"
#include <fcntl.h>
#include <unistd.h>
#include "flutter/fml/platform/linux/timerfd.h"
#include "lib/ftl/files/eintr_wrapper.h"
namespace fml {
static constexpr int kClockType = CLOCK_MONOTONIC;
static ALooper* AcquireLooperForThread() {
ALooper* looper = ALooper_forThread();
if (looper == nullptr) {
// No looper has been configured for the current thread. Create one and
// return the same.
looper = ALooper_prepare(0);
}
// The thread already has a looper. Acquire a reference to the same and return
// it.
ALooper_acquire(looper);
return looper;
}
MessageLoopAndroid::MessageLoopAndroid()
: looper_(AcquireLooperForThread()),
timer_fd_(::timerfd_create(kClockType, TFD_NONBLOCK | TFD_CLOEXEC)),
running_(false) {
FTL_CHECK(looper_.is_valid());
FTL_CHECK(timer_fd_.is_valid());
static const int kWakeEvents = ALOOPER_EVENT_INPUT;
ALooper_callbackFunc read_event_fd = [](int, int events, void* data) -> int {
if (events & kWakeEvents) {
reinterpret_cast<MessageLoopAndroid*>(data)->OnEventFired();
}
return 1; // continue receiving callbacks
};
int add_result = ::ALooper_addFd(looper_.get(), // looper
timer_fd_.get(), // fd
ALOOPER_POLL_CALLBACK, // ident
kWakeEvents, // events
read_event_fd, // callback
this // baton
);
FTL_CHECK(add_result == 1);
}
MessageLoopAndroid::~MessageLoopAndroid() {
int remove_result = ::ALooper_removeFd(looper_.get(), timer_fd_.get());
FTL_CHECK(remove_result == 1);
}
void MessageLoopAndroid::Run() {
FTL_DCHECK(looper_.get() == ALooper_forThread());
running_ = true;
while (running_) {
int result = ::ALooper_pollOnce(-1, // infinite timeout
nullptr, // out fd,
nullptr, // out events,
nullptr // out data
);
if (result == ALOOPER_POLL_TIMEOUT || result == ALOOPER_POLL_ERROR) {
// This handles the case where the loop is terminated using ALooper APIs.
running_ = false;
}
}
}
void MessageLoopAndroid::Terminate() {
running_ = false;
ALooper_wake(looper_.get());
}
void MessageLoopAndroid::WakeUp(ftl::TimePoint time_point) {
bool result = TimerRearm(timer_fd_.get(), time_point);
FTL_DCHECK(result);
}
void MessageLoopAndroid::OnEventFired() {
if (TimerDrain(timer_fd_.get())) {
RunExpiredTasksNow();
}
}
} // namespace fml

View File

@ -0,0 +1,50 @@
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_FML_PLATFORM_ANDROID_MESSAGE_LOOP_ANDROID_H_
#define FLUTTER_FML_PLATFORM_ANDROID_MESSAGE_LOOP_ANDROID_H_
#include <android/looper.h>
#include <atomic>
#include "flutter/fml/message_loop_impl.h"
#include "lib/ftl/files/unique_fd.h"
#include "lib/ftl/macros.h"
#include "lib/ftl/memory/unique_object.h"
namespace fml {
struct UniqueLooperTraits {
static ALooper* InvalidValue() { return nullptr; }
static bool IsValid(ALooper* value) { return value != nullptr; }
static void Free(ALooper* value) { ::ALooper_release(value); }
};
class MessageLoopAndroid : public MessageLoopImpl {
private:
ftl::UniqueObject<ALooper*, UniqueLooperTraits> looper_;
ftl::UniqueFD timer_fd_;
bool running_;
MessageLoopAndroid();
~MessageLoopAndroid() override;
void Run() override;
void Terminate() override;
void WakeUp(ftl::TimePoint time_point) override;
void OnEventFired();
FRIEND_MAKE_REF_COUNTED(MessageLoopAndroid);
FRIEND_REF_COUNTED_THREAD_SAFE(MessageLoopAndroid);
FTL_DISALLOW_COPY_AND_ASSIGN(MessageLoopAndroid);
};
} // namespace fml
#endif // FLUTTER_FML_PLATFORM_ANDROID_MESSAGE_LOOP_ANDROID_H_

View File

@ -0,0 +1,89 @@
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/fml/platform/android/scoped_java_ref.h"
#include "flutter/fml/platform/android/jni_util.h"
#include "lib/ftl/logging.h"
namespace fml {
namespace jni {
static const int kDefaultLocalFrameCapacity = 16;
ScopedJavaLocalFrame::ScopedJavaLocalFrame(JNIEnv* env) : env_(env) {
int failed = env_->PushLocalFrame(kDefaultLocalFrameCapacity);
FTL_DCHECK(!failed);
}
ScopedJavaLocalFrame::ScopedJavaLocalFrame(JNIEnv* env, int capacity)
: env_(env) {
int failed = env_->PushLocalFrame(capacity);
FTL_DCHECK(!failed);
}
ScopedJavaLocalFrame::~ScopedJavaLocalFrame() {
env_->PopLocalFrame(NULL);
}
JavaRef<jobject>::JavaRef() : obj_(NULL) {}
JavaRef<jobject>::JavaRef(JNIEnv* env, jobject obj) : obj_(obj) {
if (obj) {
FTL_DCHECK(env && env->GetObjectRefType(obj) == JNILocalRefType);
}
}
JavaRef<jobject>::~JavaRef() = default;
JNIEnv* JavaRef<jobject>::SetNewLocalRef(JNIEnv* env, jobject obj) {
if (!env) {
env = AttachCurrentThread();
} else {
FTL_DCHECK(env == AttachCurrentThread()); // Is |env| on correct thread.
}
if (obj)
obj = env->NewLocalRef(obj);
if (obj_)
env->DeleteLocalRef(obj_);
obj_ = obj;
return env;
}
void JavaRef<jobject>::SetNewGlobalRef(JNIEnv* env, jobject obj) {
if (!env) {
env = AttachCurrentThread();
} else {
FTL_DCHECK(env == AttachCurrentThread()); // Is |env| on correct thread.
}
if (obj)
obj = env->NewGlobalRef(obj);
if (obj_)
env->DeleteGlobalRef(obj_);
obj_ = obj;
}
void JavaRef<jobject>::ResetLocalRef(JNIEnv* env) {
if (obj_) {
FTL_DCHECK(env == AttachCurrentThread()); // Is |env| on correct thread.
env->DeleteLocalRef(obj_);
obj_ = NULL;
}
}
void JavaRef<jobject>::ResetGlobalRef() {
if (obj_) {
AttachCurrentThread()->DeleteGlobalRef(obj_);
obj_ = NULL;
}
}
jobject JavaRef<jobject>::ReleaseInternal() {
jobject obj = obj_;
obj_ = NULL;
return obj;
}
} // namespace jni
} // namespace fml

View File

@ -0,0 +1,199 @@
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef FLUTTER_FML_PLATFORM_ANDROID_SCOPED_JAVA_REF_H_
#define FLUTTER_FML_PLATFORM_ANDROID_SCOPED_JAVA_REF_H_
#include <jni.h>
#include <stddef.h>
#include "lib/ftl/macros.h"
namespace fml {
namespace jni {
// Creates a new local reference frame, in which at least a given number of
// local references can be created. Note that local references already created
// in previous local frames are still valid in the current local frame.
class ScopedJavaLocalFrame {
public:
explicit ScopedJavaLocalFrame(JNIEnv* env);
ScopedJavaLocalFrame(JNIEnv* env, int capacity);
~ScopedJavaLocalFrame();
private:
// This class is only good for use on the thread it was created on so
// it's safe to cache the non-threadsafe JNIEnv* inside this object.
JNIEnv* env_;
FTL_DISALLOW_COPY_AND_ASSIGN(ScopedJavaLocalFrame);
};
// Forward declare the generic java reference template class.
template <typename T>
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
// ScopedJavaLocalRef<jstring> into a function taking const JavaRef<jobject>&
template <>
class JavaRef<jobject> {
public:
jobject obj() const { return obj_; }
bool is_null() const { return obj_ == NULL; }
protected:
// Initializes a NULL reference.
JavaRef();
// Takes ownership of the |obj| reference passed; requires it to be a local
// reference type.
JavaRef(JNIEnv* env, jobject obj);
~JavaRef();
// The following are implementation detail convenience methods, for
// use by the sub-classes.
JNIEnv* SetNewLocalRef(JNIEnv* env, jobject obj);
void SetNewGlobalRef(JNIEnv* env, jobject obj);
void ResetLocalRef(JNIEnv* env);
void ResetGlobalRef();
jobject ReleaseInternal();
private:
jobject obj_;
FTL_DISALLOW_COPY_AND_ASSIGN(JavaRef);
};
// 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 <typename T>
class JavaRef : public JavaRef<jobject> {
public:
T obj() const { return static_cast<T>(JavaRef<jobject>::obj()); }
protected:
JavaRef() {}
~JavaRef() {}
JavaRef(JNIEnv* env, T obj) : JavaRef<jobject>(env, obj) {}
private:
FTL_DISALLOW_COPY_AND_ASSIGN(JavaRef);
};
// 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 <typename T>
class ScopedJavaLocalRef : public JavaRef<T> {
public:
ScopedJavaLocalRef() : env_(NULL) {}
// Non-explicit copy constructor, to allow ScopedJavaLocalRef to be returned
// by value as this is the normal usage pattern.
ScopedJavaLocalRef(const ScopedJavaLocalRef<T>& other) : env_(other.env_) {
this->SetNewLocalRef(env_, other.obj());
}
template <typename U>
explicit ScopedJavaLocalRef(const U& other) : env_(NULL) {
this->Reset(other);
}
// Assumes that |obj| is a local reference to a Java object and takes
// ownership of this local reference.
ScopedJavaLocalRef(JNIEnv* env, T obj) : JavaRef<T>(env, obj), env_(env) {}
~ScopedJavaLocalRef() { this->Reset(); }
// Overloaded assignment operator defined for consistency with the implicit
// copy constructor.
void operator=(const ScopedJavaLocalRef<T>& other) { this->Reset(other); }
void Reset() { this->ResetLocalRef(env_); }
template <typename U>
void Reset(const ScopedJavaLocalRef<U>& other) {
// We can copy over env_ here as |other| instance must be from the same
// thread as |this| local ref. (See class comment for multi-threading
// limitations, and alternatives).
this->Reset(other.env_, other.obj());
}
template <typename U>
void Reset(const U& other) {
// If |env_| was not yet set (is still NULL) it will be attached to the
// current thread in SetNewLocalRef().
this->Reset(env_, other.obj());
}
template <typename U>
void Reset(JNIEnv* env, U obj) {
env_ = this->SetNewLocalRef(env, obj);
}
// Releases the local reference to the caller. The caller *must* delete the
// local reference when it is done with it.
T Release() { return static_cast<T>(this->ReleaseInternal()); }
private:
// This class is only good for use on the thread it was created on so
// it's safe to cache the non-threadsafe JNIEnv* inside this object.
JNIEnv* env_;
};
// 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 <typename T>
class ScopedJavaGlobalRef : public JavaRef<T> {
public:
ScopedJavaGlobalRef() {}
explicit ScopedJavaGlobalRef(const ScopedJavaGlobalRef<T>& other) {
this->Reset(other);
}
ScopedJavaGlobalRef(JNIEnv* env, T obj) { this->Reset(env, obj); }
template <typename U>
explicit ScopedJavaGlobalRef(const U& other) {
this->Reset(other);
}
~ScopedJavaGlobalRef() { this->Reset(); }
void Reset() { this->ResetGlobalRef(); }
template <typename U>
void Reset(const U& other) {
this->Reset(NULL, other.obj());
}
template <typename U>
void Reset(JNIEnv* env, U obj) {
this->SetNewGlobalRef(env, obj);
}
// Releases the global reference to the caller. The caller *must* delete the
// global reference when it is done with it.
T Release() { return static_cast<T>(this->ReleaseInternal()); }
};
} // namespace jni
} // namespace fml
#endif // FLUTTER_FML_PLATFORM_ANDROID_SCOPED_JAVA_REF_H_

View File

@ -1915,6 +1915,14 @@ FILE: ../../../flutter/fml/message_loop.h
FILE: ../../../flutter/fml/message_loop_impl.cc
FILE: ../../../flutter/fml/message_loop_impl.h
FILE: ../../../flutter/fml/message_loop_unittests.cc
FILE: ../../../flutter/fml/platform/android/jni_util.cc
FILE: ../../../flutter/fml/platform/android/jni_util.h
FILE: ../../../flutter/fml/platform/android/jni_weak_ref.cc
FILE: ../../../flutter/fml/platform/android/jni_weak_ref.h
FILE: ../../../flutter/fml/platform/android/message_loop_android.cc
FILE: ../../../flutter/fml/platform/android/message_loop_android.h
FILE: ../../../flutter/fml/platform/android/scoped_java_ref.cc
FILE: ../../../flutter/fml/platform/android/scoped_java_ref.h
FILE: ../../../flutter/fml/platform/darwin/cf_utils.cc
FILE: ../../../flutter/fml/platform/darwin/cf_utils.h
FILE: ../../../flutter/fml/platform/linux/message_loop_linux.cc