Bug 1305271 - 1. Move GetClassGlobalRef out of AndroidBridge; r=snorp

Move GetClassGlobalRef in AndroidBridge to GetClassRef in jni/Utils. The
new function now returns a local reference instead of a global
reference.
This commit is contained in:
Jim Chen 2016-09-28 23:49:25 -04:00
Родитель 40fd25db11
Коммит 39ed66e9ec
5 изменённых файлов: 44 добавлений и 49 удалений

Просмотреть файл

@ -65,33 +65,6 @@ AndroidBridge* AndroidBridge::sBridge = nullptr;
static jobject sGlobalContext = nullptr; static jobject sGlobalContext = nullptr;
nsDataHashtable<nsStringHashKey, nsString> AndroidBridge::sStoragePaths; nsDataHashtable<nsStringHashKey, nsString> AndroidBridge::sStoragePaths;
jclass AndroidBridge::GetClassGlobalRef(JNIEnv* env, const char* className)
{
// First try the default class loader.
auto classRef = Class::LocalRef::Adopt(
env, env->FindClass(className));
if (!classRef && sBridge && sBridge->mClassLoader) {
// If the default class loader failed but we have an app class loader, try that.
// Clear the pending exception from failed FindClass call above.
env->ExceptionClear();
classRef = Class::LocalRef::Adopt(env, jclass(
env->CallObjectMethod(sBridge->mClassLoader.Get(),
sBridge->mClassLoaderLoadClass,
StringParam(className, env).Get())));
}
if (!classRef) {
ALOG(">>> FATAL JNI ERROR! FindClass(className=\"%s\") failed. "
"Did ProGuard optimize away something it shouldn't have?",
className);
env->ExceptionDescribe();
MOZ_CRASH();
}
return Class::GlobalRef(env, classRef).Forget();
}
jmethodID AndroidBridge::GetMethodID(JNIEnv* env, jclass jClass, jmethodID AndroidBridge::GetMethodID(JNIEnv* env, jclass jClass,
const char* methodName, const char* methodType) const char* methodName, const char* methodType)
{ {
@ -189,11 +162,6 @@ AndroidBridge::AndroidBridge()
JNIEnv* const jEnv = jni::GetGeckoThreadEnv(); JNIEnv* const jEnv = jni::GetGeckoThreadEnv();
AutoLocalJNIFrame jniFrame(jEnv); AutoLocalJNIFrame jniFrame(jEnv);
mClassLoader = Object::GlobalRef(jEnv, java::GeckoThread::ClsLoader());
mClassLoaderLoadClass = GetMethodID(
jEnv, jEnv->GetObjectClass(mClassLoader.Get()),
"loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
mMessageQueue = java::GeckoThread::MsgQueue(); mMessageQueue = java::GeckoThread::MsgQueue();
auto msgQueueClass = Class::LocalRef::Adopt( auto msgQueueClass = Class::LocalRef::Adopt(
jEnv, jEnv->GetObjectClass(mMessageQueue.Get())); jEnv, jEnv->GetObjectClass(mMessageQueue.Get()));

Просмотреть файл

@ -263,7 +263,6 @@ public:
static jstring NewJavaString(AutoLocalJNIFrame* frame, const char* string); static jstring NewJavaString(AutoLocalJNIFrame* frame, const char* string);
static jstring NewJavaString(AutoLocalJNIFrame* frame, const nsACString& string); static jstring NewJavaString(AutoLocalJNIFrame* frame, const nsACString& string);
static jclass GetClassGlobalRef(JNIEnv* env, const char* className);
static jfieldID GetFieldID(JNIEnv* env, jclass jClass, const char* fieldName, const char* fieldType); static jfieldID GetFieldID(JNIEnv* env, jclass jClass, const char* fieldName, const char* fieldType);
static jfieldID GetStaticFieldID(JNIEnv* env, jclass jClass, const char* fieldName, const char* fieldType); static jfieldID GetStaticFieldID(JNIEnv* env, jclass jClass, const char* fieldName, const char* fieldType);
static jmethodID GetMethodID(JNIEnv* env, jclass jClass, const char* methodName, const char* methodType); static jmethodID GetMethodID(JNIEnv* env, jclass jClass, const char* methodName, const char* methodType);
@ -312,9 +311,6 @@ protected:
// some convinient types to have around // some convinient types to have around
jclass jStringClass; jclass jStringClass;
jni::Object::GlobalRef mClassLoader;
jmethodID mClassLoaderLoadClass;
jni::Object::GlobalRef mMessageQueue; jni::Object::GlobalRef mMessageQueue;
jfieldID mMessageQueueMessages; jfieldID mMessageQueueMessages;
jmethodID mMessageQueueNext; jmethodID mMessageQueueNext;
@ -337,11 +333,11 @@ private:
public: public:
AutoJNIClass(JNIEnv* jEnv, const char* name) AutoJNIClass(JNIEnv* jEnv, const char* name)
: mEnv(jEnv) : mEnv(jEnv)
, mClass(AndroidBridge::GetClassGlobalRef(jEnv, name)) , mClass(jni::GetClassRef(jEnv, name))
{} {}
~AutoJNIClass() { ~AutoJNIClass() {
mEnv->DeleteGlobalRef(mClass); mEnv->DeleteLocalRef(mClass);
} }
jclass getRawRef() const { jclass getRawRef() const {

Просмотреть файл

@ -180,7 +180,9 @@ public:
jclass ClassRef() const jclass ClassRef() const
{ {
if (!sClassRef) { if (!sClassRef) {
sClassRef = GetClassGlobalRef(mEnv, Cls::name); const jclass cls = GetClassRef(mEnv, Cls::name);
sClassRef = jclass(mEnv->NewGlobalRef(cls));
mEnv->DeleteLocalRef(cls);
} }
return sClassRef; return sClassRef;
} }

Просмотреть файл

@ -1,11 +1,11 @@
#include "Utils.h" #include "Utils.h"
#include "Types.h" #include "Types.h"
#include <android/log.h>
#include <pthread.h> #include <pthread.h>
#include "mozilla/Assertions.h" #include "mozilla/Assertions.h"
#include "AndroidBridge.h"
#include "GeneratedJNIWrappers.h" #include "GeneratedJNIWrappers.h"
#include "nsAppShell.h" #include "nsAppShell.h"
@ -71,6 +71,8 @@ namespace {
JavaVM* sJavaVM; JavaVM* sJavaVM;
pthread_key_t sThreadEnvKey; pthread_key_t sThreadEnvKey;
jclass sOOMErrorClass; jclass sOOMErrorClass;
jobject sClassLoader;
jmethodID sClassLoaderLoadClass;
void UnregisterThreadEnv(void* env) void UnregisterThreadEnv(void* env)
{ {
@ -106,6 +108,12 @@ void SetGeckoThreadEnv(JNIEnv* aEnv)
sOOMErrorClass = Class::GlobalRef(Class::LocalRef::Adopt( sOOMErrorClass = Class::GlobalRef(Class::LocalRef::Adopt(
aEnv->FindClass("java/lang/OutOfMemoryError"))).Forget(); aEnv->FindClass("java/lang/OutOfMemoryError"))).Forget();
aEnv->ExceptionClear(); aEnv->ExceptionClear();
sClassLoader = Object::GlobalRef(java::GeckoThread::ClsLoader()).Forget();
sClassLoaderLoadClass = aEnv->GetMethodID(
Class::LocalRef::Adopt(aEnv->GetObjectClass(sClassLoader)).Get(),
"loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
MOZ_ASSERT(sClassLoader && sClassLoaderLoadClass);
} }
JNIEnv* GetEnvForThread() JNIEnv* GetEnvForThread()
@ -197,11 +205,11 @@ jfieldID sJNIObjectHandleField;
bool EnsureJNIObject(JNIEnv* env, jobject instance) { bool EnsureJNIObject(JNIEnv* env, jobject instance) {
if (!sJNIObjectClass) { if (!sJNIObjectClass) {
sJNIObjectClass = AndroidBridge::GetClassGlobalRef( sJNIObjectClass = Class::GlobalRef(Class::LocalRef::Adopt(GetClassRef(
env, "org/mozilla/gecko/mozglue/JNIObject"); env, "org/mozilla/gecko/mozglue/JNIObject"))).Forget();
sJNIObjectHandleField = AndroidBridge::GetFieldID( sJNIObjectHandleField = env->GetFieldID(
env, sJNIObjectClass, "mHandle", "J"); sJNIObjectClass, "mHandle", "J");
} }
MOZ_ASSERT(env->IsInstanceOf(instance, sJNIObjectClass)); MOZ_ASSERT(env->IsInstanceOf(instance, sJNIObjectClass));
@ -230,11 +238,33 @@ void SetNativeHandle(JNIEnv* env, jobject instance, uintptr_t handle)
static_cast<jlong>(handle)); static_cast<jlong>(handle));
} }
jclass GetClassGlobalRef(JNIEnv* aEnv, const char* aClassName) jclass GetClassRef(JNIEnv* aEnv, const char* aClassName)
{ {
return AndroidBridge::GetClassGlobalRef(aEnv, aClassName); // First try the default class loader.
} auto classRef = Class::LocalRef::Adopt(aEnv, aEnv->FindClass(aClassName));
if (!classRef && sClassLoader) {
// If the default class loader failed but we have an app class loader, try that.
// Clear the pending exception from failed FindClass call above.
aEnv->ExceptionClear();
classRef = Class::LocalRef::Adopt(aEnv, jclass(
aEnv->CallObjectMethod(sClassLoader, sClassLoaderLoadClass,
StringParam(aClassName, aEnv).Get())));
}
if (classRef) {
return classRef.Forget();
}
__android_log_print(
ANDROID_LOG_ERROR, "Gecko",
">>> FATAL JNI ERROR! FindClass(className=\"%s\") failed. "
"Did ProGuard optimize away something it shouldn't have?",
aClassName);
aEnv->ExceptionDescribe();
MOZ_CRASH("Cannot find JNI class");
return nullptr;
}
void DispatchToGeckoThread(UniquePtr<AbstractCall>&& aCall) void DispatchToGeckoThread(UniquePtr<AbstractCall>&& aCall)
{ {

Просмотреть файл

@ -125,8 +125,7 @@ uintptr_t GetNativeHandle(JNIEnv* env, jobject instance);
void SetNativeHandle(JNIEnv* env, jobject instance, uintptr_t handle); void SetNativeHandle(JNIEnv* env, jobject instance, uintptr_t handle);
jclass GetClassGlobalRef(JNIEnv* aEnv, const char* aClassName); jclass GetClassRef(JNIEnv* aEnv, const char* aClassName);
struct AbstractCall struct AbstractCall
{ {