From d291d3bec453742e0a6250fe59b149804e27a185 Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Tue, 1 Apr 2014 15:16:52 -0400 Subject: [PATCH] Bug 984458 - a. Add NativeJSContainer implementation; r=blassey --- mobile/android/base/Makefile.in | 4 +- mobile/android/base/moz.build | 2 + .../android/base/util/NativeJSContainer.java | 28 +++++ mobile/android/base/util/NativeJSObject.java | 17 +++ mozglue/android/jni-stubs.inc | 107 +++++++++------- widget/android/NativeJSContainer.cpp | 114 ++++++++++++++++++ widget/android/NativeJSContainer.h | 21 ++++ widget/android/moz.build | 1 + 8 files changed, 249 insertions(+), 45 deletions(-) create mode 100644 mobile/android/base/util/NativeJSContainer.java create mode 100644 mobile/android/base/util/NativeJSObject.java create mode 100644 widget/android/NativeJSContainer.cpp create mode 100644 widget/android/NativeJSContainer.h diff --git a/mobile/android/base/Makefile.in b/mobile/android/base/Makefile.in index a3fe51a7a008..5f79075bd22b 100644 --- a/mobile/android/base/Makefile.in +++ b/mobile/android/base/Makefile.in @@ -111,10 +111,12 @@ endif -libraryjars $(ANDROID_SDK)/android.jar:$(ANDROID_COMPAT_LIB) CLASSES_WITH_JNI= \ + org.mozilla.gecko.ANRReporter \ org.mozilla.gecko.GeckoAppShell \ org.mozilla.gecko.GeckoJavaSampler \ org.mozilla.gecko.gfx.NativePanZoomController \ - org.mozilla.gecko.ANRReporter \ + org.mozilla.gecko.util.NativeJSContainer \ + org.mozilla.gecko.util.NativeJSObject \ $(NULL) ifdef MOZ_WEBSMS_BACKEND diff --git a/mobile/android/base/moz.build b/mobile/android/base/moz.build index 3190848c5b80..5f869721e34e 100644 --- a/mobile/android/base/moz.build +++ b/mobile/android/base/moz.build @@ -60,6 +60,8 @@ gujar.sources += [ 'util/INISection.java', 'util/JSONUtils.java', 'util/MenuUtils.java', + 'util/NativeJSContainer.java', + 'util/NativeJSObject.java', 'util/NonEvictingLruCache.java', 'util/ProxySelector.java', 'util/StringUtils.java', diff --git a/mobile/android/base/util/NativeJSContainer.java b/mobile/android/base/util/NativeJSContainer.java new file mode 100644 index 000000000000..770c8a48861d --- /dev/null +++ b/mobile/android/base/util/NativeJSContainer.java @@ -0,0 +1,28 @@ +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.gecko.util; + +import org.mozilla.gecko.mozglue.JNITarget; + +/** + * NativeJSContainer is a wrapper around the SpiderMonkey JSAPI to make it possible to + * access Javascript objects in Java. + */ +@JNITarget +public final class NativeJSContainer extends NativeJSObject +{ + private long mNativeObject; + + private NativeJSContainer(long nativeObject) { + mNativeObject = nativeObject; + } + + /** + * Dispose all associated native objects. Subsequent use of any objects derived from + * this container will throw a NullPointerException. + */ + public native void dispose(); +} diff --git a/mobile/android/base/util/NativeJSObject.java b/mobile/android/base/util/NativeJSObject.java new file mode 100644 index 000000000000..e0d667c5125d --- /dev/null +++ b/mobile/android/base/util/NativeJSObject.java @@ -0,0 +1,17 @@ +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.gecko.util; + +import org.mozilla.gecko.mozglue.JNITarget; + +/** + * NativeJSObject is a wrapper around the SpiderMonkey JSAPI to make it possible to + * access Javascript objects in Java. + */ +@JNITarget +public class NativeJSObject +{ +} diff --git a/mozglue/android/jni-stubs.inc b/mozglue/android/jni-stubs.inc index 4767db7259a0..21ea258ab4c9 100644 --- a/mozglue/android/jni-stubs.inc +++ b/mozglue/android/jni-stubs.inc @@ -1,6 +1,63 @@ /* WARNING - This file is autogenerated by mobile/android/base/jni-generator.py. Do not edit manually! */ #ifdef JNI_STUBS +typedef jboolean (*Java_org_mozilla_gecko_ANRReporter_requestNativeStack_t)(JNIEnv *, jclass, jboolean); +static Java_org_mozilla_gecko_ANRReporter_requestNativeStack_t f_Java_org_mozilla_gecko_ANRReporter_requestNativeStack; +extern "C" NS_EXPORT jboolean JNICALL +Java_org_mozilla_gecko_ANRReporter_requestNativeStack(JNIEnv * arg0, jclass arg1, jboolean arg2) { + if (!f_Java_org_mozilla_gecko_ANRReporter_requestNativeStack) { + arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"), + "JNI Function called before it was loaded"); + return false; + } + return f_Java_org_mozilla_gecko_ANRReporter_requestNativeStack(arg0, arg1, arg2); +} +#endif + +#ifdef JNI_BINDINGS + xul_dlsym("Java_org_mozilla_gecko_ANRReporter_requestNativeStack", &f_Java_org_mozilla_gecko_ANRReporter_requestNativeStack); +#endif + +#ifdef JNI_STUBS + +typedef jstring (*Java_org_mozilla_gecko_ANRReporter_getNativeStack_t)(JNIEnv *, jclass); +static Java_org_mozilla_gecko_ANRReporter_getNativeStack_t f_Java_org_mozilla_gecko_ANRReporter_getNativeStack; +extern "C" NS_EXPORT jstring JNICALL +Java_org_mozilla_gecko_ANRReporter_getNativeStack(JNIEnv * arg0, jclass arg1) { + if (!f_Java_org_mozilla_gecko_ANRReporter_getNativeStack) { + arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"), + "JNI Function called before it was loaded"); + return nullptr; + } + return f_Java_org_mozilla_gecko_ANRReporter_getNativeStack(arg0, arg1); +} +#endif + +#ifdef JNI_BINDINGS + xul_dlsym("Java_org_mozilla_gecko_ANRReporter_getNativeStack", &f_Java_org_mozilla_gecko_ANRReporter_getNativeStack); +#endif + +#ifdef JNI_STUBS + +typedef void (*Java_org_mozilla_gecko_ANRReporter_releaseNativeStack_t)(JNIEnv *, jclass); +static Java_org_mozilla_gecko_ANRReporter_releaseNativeStack_t f_Java_org_mozilla_gecko_ANRReporter_releaseNativeStack; +extern "C" NS_EXPORT void JNICALL +Java_org_mozilla_gecko_ANRReporter_releaseNativeStack(JNIEnv * arg0, jclass arg1) { + if (!f_Java_org_mozilla_gecko_ANRReporter_releaseNativeStack) { + arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"), + "JNI Function called before it was loaded"); + return ; + } + f_Java_org_mozilla_gecko_ANRReporter_releaseNativeStack(arg0, arg1); +} +#endif + +#ifdef JNI_BINDINGS + xul_dlsym("Java_org_mozilla_gecko_ANRReporter_releaseNativeStack", &f_Java_org_mozilla_gecko_ANRReporter_releaseNativeStack); +#endif + +#ifdef JNI_STUBS + typedef void (*Java_org_mozilla_gecko_GeckoAppShell_nativeInit_t)(JNIEnv *, jclass); static Java_org_mozilla_gecko_GeckoAppShell_nativeInit_t f_Java_org_mozilla_gecko_GeckoAppShell_nativeInit; extern "C" NS_EXPORT void JNICALL @@ -514,58 +571,20 @@ Java_org_mozilla_gecko_gfx_NativePanZoomController_getOverScrollMode(JNIEnv * ar #ifdef JNI_STUBS -typedef jboolean (*Java_org_mozilla_gecko_ANRReporter_requestNativeStack_t)(JNIEnv *, jclass, jboolean); -static Java_org_mozilla_gecko_ANRReporter_requestNativeStack_t f_Java_org_mozilla_gecko_ANRReporter_requestNativeStack; -extern "C" NS_EXPORT jboolean JNICALL -Java_org_mozilla_gecko_ANRReporter_requestNativeStack(JNIEnv * arg0, jclass arg1, jboolean arg2) { - if (!f_Java_org_mozilla_gecko_ANRReporter_requestNativeStack) { - arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"), - "JNI Function called before it was loaded"); - return false; - } - return f_Java_org_mozilla_gecko_ANRReporter_requestNativeStack(arg0, arg1, arg2); -} -#endif - -#ifdef JNI_BINDINGS - xul_dlsym("Java_org_mozilla_gecko_ANRReporter_requestNativeStack", &f_Java_org_mozilla_gecko_ANRReporter_requestNativeStack); -#endif - -#ifdef JNI_STUBS - -typedef jstring (*Java_org_mozilla_gecko_ANRReporter_getNativeStack_t)(JNIEnv *, jclass); -static Java_org_mozilla_gecko_ANRReporter_getNativeStack_t f_Java_org_mozilla_gecko_ANRReporter_getNativeStack; -extern "C" NS_EXPORT jstring JNICALL -Java_org_mozilla_gecko_ANRReporter_getNativeStack(JNIEnv * arg0, jclass arg1) { - if (!f_Java_org_mozilla_gecko_ANRReporter_getNativeStack) { - arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"), - "JNI Function called before it was loaded"); - return nullptr; - } - return f_Java_org_mozilla_gecko_ANRReporter_getNativeStack(arg0, arg1); -} -#endif - -#ifdef JNI_BINDINGS - xul_dlsym("Java_org_mozilla_gecko_ANRReporter_getNativeStack", &f_Java_org_mozilla_gecko_ANRReporter_getNativeStack); -#endif - -#ifdef JNI_STUBS - -typedef void (*Java_org_mozilla_gecko_ANRReporter_releaseNativeStack_t)(JNIEnv *, jclass); -static Java_org_mozilla_gecko_ANRReporter_releaseNativeStack_t f_Java_org_mozilla_gecko_ANRReporter_releaseNativeStack; +typedef void (*Java_org_mozilla_gecko_util_NativeJSContainer_dispose_t)(JNIEnv *, jobject); +static Java_org_mozilla_gecko_util_NativeJSContainer_dispose_t f_Java_org_mozilla_gecko_util_NativeJSContainer_dispose; extern "C" NS_EXPORT void JNICALL -Java_org_mozilla_gecko_ANRReporter_releaseNativeStack(JNIEnv * arg0, jclass arg1) { - if (!f_Java_org_mozilla_gecko_ANRReporter_releaseNativeStack) { +Java_org_mozilla_gecko_util_NativeJSContainer_dispose(JNIEnv * arg0, jobject arg1) { + if (!f_Java_org_mozilla_gecko_util_NativeJSContainer_dispose) { arg0->ThrowNew(arg0->FindClass("java/lang/UnsupportedOperationException"), "JNI Function called before it was loaded"); return ; } - f_Java_org_mozilla_gecko_ANRReporter_releaseNativeStack(arg0, arg1); + f_Java_org_mozilla_gecko_util_NativeJSContainer_dispose(arg0, arg1); } #endif #ifdef JNI_BINDINGS - xul_dlsym("Java_org_mozilla_gecko_ANRReporter_releaseNativeStack", &f_Java_org_mozilla_gecko_ANRReporter_releaseNativeStack); + xul_dlsym("Java_org_mozilla_gecko_util_NativeJSContainer_dispose", &f_Java_org_mozilla_gecko_util_NativeJSContainer_dispose); #endif diff --git a/widget/android/NativeJSContainer.cpp b/widget/android/NativeJSContainer.cpp new file mode 100644 index 000000000000..d0071398858e --- /dev/null +++ b/widget/android/NativeJSContainer.cpp @@ -0,0 +1,114 @@ +/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "NativeJSContainer.h" +#include "AndroidBridge.h" + +using namespace mozilla; +using namespace mozilla::widget; + +namespace mozilla { +namespace widget { + +class NativeJSContainer +{ +public: + static void InitJNI(JNIEnv* env) { + if (jNativeJSContainer) { + return; + } + jNativeJSContainer = AndroidBridge::GetClassGlobalRef( + env, "org/mozilla/gecko/util/NativeJSContainer"); + MOZ_ASSERT(jNativeJSContainer); + jContainerNativeObject = AndroidBridge::GetFieldID( + env, jNativeJSContainer, "mNativeObject", "J"); + MOZ_ASSERT(jContainerNativeObject); + jContainerConstructor = AndroidBridge::GetMethodID( + env, jNativeJSContainer, "", "(J)V"); + MOZ_ASSERT(jContainerConstructor); + } + + static jobject CreateInstance(JNIEnv* env, JSContext* cx, + JS::HandleObject object) { + return CreateInstance(env, new NativeJSContainer(cx, object)); + } + + static NativeJSContainer* FromInstance(JNIEnv* env, jobject instance) { + MOZ_ASSERT(instance); + + const jlong fieldValue = + env->GetLongField(instance, jContainerNativeObject); + NativeJSContainer* const nativeObject = + reinterpret_cast( + static_cast(fieldValue)); + if (!nativeObject) { + AndroidBridge::ThrowException(env, + "java/lang/NullPointerException", + "Uninitialized NativeJSContainer"); + } + return nativeObject; + } + + static void DisposeInstance(JNIEnv* env, jobject instance) { + NativeJSContainer* const container = FromInstance(env, instance); + if (container) { + env->SetLongField(instance, jContainerNativeObject, + static_cast(reinterpret_cast(nullptr))); + delete container; + } + } + +private: + static jclass jNativeJSContainer; + static jfieldID jContainerNativeObject; + static jmethodID jContainerConstructor; + + static jobject CreateInstance(JNIEnv* env, + NativeJSContainer* nativeObject) { + InitJNI(env); + const jobject newObject = + env->NewObject(jNativeJSContainer, jContainerConstructor, + static_cast( + reinterpret_cast(nativeObject))); + AndroidBridge::HandleUncaughtException(env); + MOZ_ASSERT(newObject); + return newObject; + } + + JSContext* const mContext; + // Root JS object + const JS::Heap mJSObject; + + // Create a new container containing the given object + NativeJSContainer(JSContext* cx, JS::HandleObject object) + : mContext(cx) + , mJSObject(object) + { + } +}; + +jclass NativeJSContainer::jNativeJSContainer = 0; +jfieldID NativeJSContainer::jContainerNativeObject = 0; +jmethodID NativeJSContainer::jContainerConstructor = 0; + +jobject +CreateNativeJSContainer(JNIEnv* env, JSContext* cx, JS::HandleObject object) +{ + return NativeJSContainer::CreateInstance(env, cx, object); +} + +} // namespace widget +} // namespace mozilla + +extern "C" { + +NS_EXPORT void JNICALL +Java_org_mozilla_gecko_util_NativeJSContainer_dispose(JNIEnv* env, jobject instance) +{ + MOZ_ASSERT(env); + NativeJSContainer::DisposeInstance(env, instance); +} + +} // extern "C" diff --git a/widget/android/NativeJSContainer.h b/widget/android/NativeJSContainer.h new file mode 100644 index 000000000000..b6ac86d1c4b4 --- /dev/null +++ b/widget/android/NativeJSContainer.h @@ -0,0 +1,21 @@ +/* -*- Mode: c++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 4; -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef NativeJSObject_h__ +#define NativeJSObject_h__ + +#include +#include "jsapi.h" + +namespace mozilla { +namespace widget { + +jobject CreateNativeJSContainer(JNIEnv* env, JSContext* cx, JS::HandleObject object); + +} // namespace widget +} // namespace mozilla + +#endif // NativeJSObject_h__ + diff --git a/widget/android/moz.build b/widget/android/moz.build index db62591a085a..8878a65303ff 100644 --- a/widget/android/moz.build +++ b/widget/android/moz.build @@ -26,6 +26,7 @@ SOURCES += [ 'AndroidJNIWrapper.cpp', 'GeneratedJNIWrappers.cpp', 'GfxInfo.cpp', + 'NativeJSContainer.cpp', 'nsAppShell.cpp', 'nsClipboard.cpp', 'nsDeviceContextAndroid.cpp',