From ab5dc60ad7eaaef0d4746539b065fe3dcbf74cf4 Mon Sep 17 00:00:00 2001 From: Kartikaya Gupta Date: Fri, 4 May 2012 11:08:47 -0400 Subject: [PATCH] Bug 748531 - Guard against exceptions in JNI. r=blassey --- dom/plugins/base/android/ANPAudio.cpp | 2 +- widget/android/AndroidBridge.cpp | 340 ++++++++++++++++++------- widget/android/AndroidBridge.h | 127 ++++----- widget/android/AndroidJavaWrappers.cpp | 84 ++++-- widget/android/AndroidJavaWrappers.h | 14 +- widget/android/nsWindow.cpp | 49 ++-- 6 files changed, 407 insertions(+), 209 deletions(-) diff --git a/dom/plugins/base/android/ANPAudio.cpp b/dom/plugins/base/android/ANPAudio.cpp index c088e1ca179..a9f6b7f889a 100644 --- a/dom/plugins/base/android/ANPAudio.cpp +++ b/dom/plugins/base/android/ANPAudio.cpp @@ -143,7 +143,7 @@ AudioRunnable::Run() if (!jenv) return NS_ERROR_FAILURE; - mozilla::AndroidBridge::AutoLocalJNIFrame autoFrame(jenv); + mozilla::AutoLocalJNIFrame autoFrame(jenv); jbyteArray bytearray = jenv->NewByteArray(mTrack->bufferSize); if (!bytearray) { diff --git a/widget/android/AndroidBridge.cpp b/widget/android/AndroidBridge.cpp index 9cd2832309f..287b1292bd8 100644 --- a/widget/android/AndroidBridge.cpp +++ b/widget/android/AndroidBridge.cpp @@ -104,7 +104,7 @@ AndroidBridge::Init(JNIEnv *jEnv, ALOG_BRIDGE("AndroidBridge::Init"); jEnv->GetJavaVM(&mJavaVM); - AutoLocalJNIFrame frame(jEnv); + AutoLocalJNIFrame jniFrame(jEnv); mJNIEnv = nsnull; mThread = nsnull; @@ -264,6 +264,7 @@ AndroidBridge::NotifyIME(int aType, int aState) if (!env) return; + AutoLocalJNIFrame jniFrame(env, 0); env->CallStaticVoidMethod(sBridge->mGeckoAppShellClass, sBridge->jNotifyIME, aType, aState); } @@ -280,11 +281,11 @@ AndroidBridge::NotifyIMEEnabled(int aState, const nsAString& aTypeHint, if (!env) return; + AutoLocalJNIFrame jniFrame(env); nsPromiseFlatString typeHint(aTypeHint); nsPromiseFlatString actionHint(aActionHint); jvalue args[4]; - AutoLocalJNIFrame jniFrame(env, 1); args[0].i = aState; args[1].l = env->NewString(typeHint.get(), typeHint.Length()); args[2].l = env->NewString(actionHint.get(), actionHint.Length()); @@ -318,16 +319,15 @@ AndroidBridge::NotifyIMEChange(const PRUnichar *aText, PRUint32 aTextLen, int aStart, int aEnd, int aNewEnd) { ALOG_BRIDGE("AndroidBridge::NotifyIMEChange"); - if (!sBridge) { + if (!sBridge) return; - } JNIEnv *env = GetJNIEnv(); if (!env) return; + AutoLocalJNIFrame jniFrame(env); jvalue args[4]; - AutoLocalJNIFrame jniFrame(env, 1); args[0].l = env->NewString(aText, aTextLen); args[1].i = aStart; args[2].i = aEnd; @@ -345,6 +345,7 @@ AndroidBridge::AcknowledgeEventSync() if (!env) return; + AutoLocalJNIFrame jniFrame(env, 0); env->CallStaticVoidMethod(mGeckoAppShellClass, jAcknowledgeEventSync); } @@ -357,7 +358,7 @@ AndroidBridge::EnableLocation(bool aEnable) if (!env) return; - AutoLocalJNIFrame jniFrame(env, 1); + AutoLocalJNIFrame jniFrame(env, 0); env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableLocation, aEnable); } @@ -369,28 +370,30 @@ AndroidBridge::EnableLocationHighAccuracy(bool aEnable) if (!env) return; - AutoLocalJNIFrame jniFrame(env, 1); + AutoLocalJNIFrame jniFrame(env, 0); env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableLocationHighAccuracy, aEnable); } void -AndroidBridge::EnableSensor(int aSensorType) { +AndroidBridge::EnableSensor(int aSensorType) +{ ALOG_BRIDGE("AndroidBridge::EnableSensor"); JNIEnv *env = GetJNIEnv(); if (!env) return; - AutoLocalJNIFrame jniFrame(env, 1); + AutoLocalJNIFrame jniFrame(env, 0); env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableSensor, aSensorType); } void -AndroidBridge::DisableSensor(int aSensorType) { +AndroidBridge::DisableSensor(int aSensorType) +{ ALOG_BRIDGE("AndroidBridge::DisableSensor"); JNIEnv *env = GetJNIEnv(); if (!env) return; - AutoLocalJNIFrame jniFrame(env, 1); + AutoLocalJNIFrame jniFrame(env, 0); env->CallStaticVoidMethod(mGeckoAppShellClass, jDisableSensor, aSensorType); } @@ -404,8 +407,8 @@ AndroidBridge::ReturnIMEQueryResult(const PRUnichar *aResult, PRUint32 aLen, if (!env) return; + AutoLocalJNIFrame jniFrame(env); jvalue args[3]; - AutoLocalJNIFrame jniFrame(env, 1); args[0].l = env->NewString(aResult, aLen); args[1].i = aSelStart; args[2].i = aSelLen; @@ -422,6 +425,7 @@ AndroidBridge::ScheduleRestart() if (!env) return; + AutoLocalJNIFrame jniFrame(env, 0); env->CallStaticVoidMethod(mGeckoAppShellClass, jScheduleRestart); } @@ -434,6 +438,7 @@ AndroidBridge::NotifyXreExit() if (!env) return; + AutoLocalJNIFrame jniFrame(env, 0); env->CallStaticVoidMethod(mGeckoAppShellClass, jNotifyXreExit); } @@ -487,6 +492,9 @@ AndroidBridge::GetHandlersForMimeType(const char *aMimeType, jobject obj = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetHandlersForMimeType, jstrMimeType, jstrAction); + if (jniFrame.CheckForException()) + return false; + jobjectArray arr = static_cast(obj); if (!arr) return false; @@ -523,6 +531,9 @@ AndroidBridge::GetHandlersForURL(const char *aURL, jobject obj = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetHandlersForURL, jstrScheme, jstrAction); + if (jniFrame.CheckForException()) + return false; + jobjectArray arr = static_cast(obj); if (!arr) return false; @@ -564,10 +575,14 @@ AndroidBridge::OpenUriExternal(const nsACString& aUriSpec, const nsACString& aMi jstring jstrTitle = env->NewString(nsPromiseFlatString(aTitle).get(), aTitle.Length()); - return env->CallStaticBooleanMethod(mGeckoAppShellClass, + bool ret = env->CallStaticBooleanMethod(mGeckoAppShellClass, jOpenUriExternal, jstrUri, jstrType, jstrPackage, jstrClass, jstrAction, jstrTitle); + if (jniFrame.CheckForException()) + return false; + + return ret; } void @@ -586,6 +601,9 @@ AndroidBridge::GetMimeTypeFromExtensions(const nsACString& aFileExt, nsCString& env->CallStaticObjectMethod(mGeckoAppShellClass, jGetMimeTypeFromExtensions, jstrExt)); + if (jniFrame.CheckForException()) + return; + nsJNIString jniStr(jstrType, env); aMimeType.Assign(NS_ConvertUTF16toUTF8(jniStr.get())); } @@ -606,6 +624,9 @@ AndroidBridge::GetExtensionFromMimeType(const nsACString& aMimeType, nsACString& env->CallStaticObjectMethod(mGeckoAppShellClass, jGetExtensionFromMimeType, jstrType)); + if (jniFrame.CheckForException()) + return; + nsJNIString jniStr(jstrExt, env); aFileExt.Assign(NS_ConvertUTF16toUTF8(jniStr.get())); } @@ -619,6 +640,7 @@ AndroidBridge::MoveTaskToBack() if (!env) return; + AutoLocalJNIFrame jniFrame(env, 0); env->CallStaticVoidMethod(mGeckoAppShellClass, jMoveTaskToBack); } @@ -631,12 +653,13 @@ AndroidBridge::GetClipboardText(nsAString& aText) if (!env) return false; - jstring jstrType = - static_cast(env-> - CallStaticObjectMethod(mGeckoAppShellClass, - jGetClipboardText)); - if (!jstrType) + AutoLocalJNIFrame jniFrame(env); + jstring jstrType = static_cast( + env->CallStaticObjectMethod(mGeckoAppShellClass, + jGetClipboardText)); + if (jniFrame.CheckForException() || !jstrType) return false; + nsJNIString jniStr(jstrType, env); aText.Assign(jniStr); return true; @@ -666,12 +689,13 @@ AndroidBridge::ClipboardHasText() if (!env) return false; - jstring jstrType = - static_cast(env-> - CallStaticObjectMethod(mGeckoAppShellClass, - jGetClipboardText)); - if (!jstrType) + AutoLocalJNIFrame jniFrame(env); + jstring jstrType = static_cast( + env->CallStaticObjectMethod(mGeckoAppShellClass, + jGetClipboardText)); + if (jniFrame.CheckForException() || !jstrType) return false; + return true; } @@ -684,6 +708,7 @@ AndroidBridge::EmptyClipboard() if (!env) return; + AutoLocalJNIFrame jniFrame(env, 0); env->CallStaticVoidMethod(mGeckoAppShellClass, jSetClipboardText, nsnull); } @@ -754,12 +779,17 @@ int AndroidBridge::GetDPI() { ALOG_BRIDGE("AndroidBridge::GetDPI"); - + const int DEFAULT_DPI = 72; // what is a better value? JNIEnv *env = GetJNIEnv(); if (!env) - return 72; // what is a better value. If we don't have a env here, we are hosed. + return DEFAULT_DPI; + AutoLocalJNIFrame jniFrame(env); - return (int) env->CallStaticIntMethod(mGeckoAppShellClass, jGetDpi); + int dpi = (int)env->CallStaticIntMethod(mGeckoAppShellClass, jGetDpi); + if (jniFrame.CheckForException()) + return DEFAULT_DPI; + + return dpi; } void @@ -774,9 +804,12 @@ AndroidBridge::ShowFilePickerForExtensions(nsAString& aFilePath, const nsAString AutoLocalJNIFrame jniFrame(env); jstring jstrFilers = env->NewString(nsPromiseFlatString(aExtensions).get(), aExtensions.Length()); - jstring jstr = static_cast(env->CallStaticObjectMethod( - mGeckoAppShellClass, - jShowFilePickerForExtensions, jstrFilers)); + jstring jstr = static_cast(env->CallStaticObjectMethod( + mGeckoAppShellClass, + jShowFilePickerForExtensions, jstrFilers)); + if (jniFrame.CheckForException()) + return; + aFilePath.Assign(nsJNIString(jstr, env)); } @@ -792,9 +825,12 @@ AndroidBridge::ShowFilePickerForMimeType(nsAString& aFilePath, const nsAString& AutoLocalJNIFrame jniFrame(env); jstring jstrFilers = env->NewString(nsPromiseFlatString(aMimeType).get(), aMimeType.Length()); - jstring jstr = static_cast(env->CallStaticObjectMethod( - mGeckoAppShellClass, - jShowFilePickerForMimeType, jstrFilers)); + jstring jstr = static_cast(env->CallStaticObjectMethod( + mGeckoAppShellClass, + jShowFilePickerForMimeType, jstrFilers)); + if (jniFrame.CheckForException()) + return; + aFilePath.Assign(nsJNIString(jstr, env)); } @@ -821,6 +857,7 @@ AndroidBridge::SetFullScreen(bool aFullScreen) if (!env) return; + AutoLocalJNIFrame jniFrame(env, 0); env->CallStaticVoidMethod(mGeckoAppShellClass, jSetFullScreen, aFullScreen); } @@ -828,16 +865,19 @@ void AndroidBridge::HideProgressDialogOnce() { static bool once = false; + if (once) + return; JNIEnv *env = GetJNIEnv(); if (!env) return; - if (!once) { - ALOG_BRIDGE("AndroidBridge::HideProgressDialogOnce"); - env->CallStaticVoidMethod(mGeckoAppShellClass, jHideProgressDialog); - once = true; - } + AutoLocalJNIFrame jniFrame(env, 0); + env->CallStaticVoidMethod(mGeckoAppShellClass, jHideProgressDialog); + if (jniFrame.CheckForException()) + return; + + once = true; } void @@ -849,6 +889,7 @@ AndroidBridge::PerformHapticFeedback(bool aIsLongPress) if (!env) return; + AutoLocalJNIFrame jniFrame(env, 0); env->CallStaticVoidMethod(mGeckoAppShellClass, jPerformHapticFeedback, aIsLongPress); } @@ -856,14 +897,12 @@ AndroidBridge::PerformHapticFeedback(bool aIsLongPress) void AndroidBridge::Vibrate(const nsTArray& aPattern) { + ALOG_BRIDGE("AndroidBridge::Vibrate"); JNIEnv *env = GetJNIEnv(); if (!env) return; AutoLocalJNIFrame jniFrame(env); - - ALOG_BRIDGE("AndroidBridge::Vibrate"); - PRUint32 len = aPattern.Length(); if (!len) { ALOG_BRIDGE(" invalid 0-length array"); @@ -916,6 +955,7 @@ AndroidBridge::CancelVibrate() if (!env) return; + AutoLocalJNIFrame jniFrame(env, 0); env->CallStaticVoidMethod(mGeckoAppShellClass, jCancelVibrate); } @@ -928,7 +968,12 @@ AndroidBridge::IsNetworkLinkUp() if (!env) return false; - return !!env->CallStaticBooleanMethod(mGeckoAppShellClass, jIsNetworkLinkUp); + AutoLocalJNIFrame jniFrame(env, 0); + bool ret = !!env->CallStaticBooleanMethod(mGeckoAppShellClass, jIsNetworkLinkUp); + if (jniFrame.CheckForException()) + return false; + + return ret; } bool @@ -940,7 +985,12 @@ AndroidBridge::IsNetworkLinkKnown() if (!env) return false; - return !!env->CallStaticBooleanMethod(mGeckoAppShellClass, jIsNetworkLinkKnown); + AutoLocalJNIFrame jniFrame(env, 0); + bool ret = !!env->CallStaticBooleanMethod(mGeckoAppShellClass, jIsNetworkLinkKnown); + if (jniFrame.CheckForException()) + return false; + + return ret; } void @@ -973,6 +1023,9 @@ AndroidBridge::GetSystemColors(AndroidSystemColors *aColors) AutoLocalJNIFrame jniFrame(env); jobject obj = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetSystemColors); + if (jniFrame.CheckForException()) + return; + jintArray arr = static_cast(obj); if (!arr) return; @@ -1016,6 +1069,9 @@ AndroidBridge::GetIconForExtension(const nsACString& aFileExt, PRUint32 aIconSiz jstring jstrFileExt = env->NewString(nsPromiseFlatString(fileExt).get(), fileExt.Length()); jobject obj = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetIconForExtension, jstrFileExt, aIconSize); + if (jniFrame.CheckForException()) + return; + jbyteArray arr = static_cast(obj); NS_ASSERTION(arr != nsnull, "AndroidBridge::GetIconForExtension: Returned pixels array is null!"); if (!arr) @@ -1041,7 +1097,12 @@ AndroidBridge::GetShowPasswordSetting() if (!env) return false; - return env->CallStaticBooleanMethod(mGeckoAppShellClass, jGetShowPasswordSetting); + AutoLocalJNIFrame jniFrame(env, 0); + bool ret = env->CallStaticBooleanMethod(mGeckoAppShellClass, jGetShowPasswordSetting); + if (jniFrame.CheckForException()) + return false; + + return ret; } void @@ -1067,6 +1128,7 @@ AndroidBridge::ShowInputMethodPicker() if (!env) return; + AutoLocalJNIFrame jniFrame(env, 0); env->CallStaticVoidMethod(mGeckoAppShellClass, jShowInputMethodPicker); } @@ -1075,11 +1137,12 @@ AndroidBridge::CallEglCreateWindowSurface(void *dpy, void *config, AndroidGeckoS { ALOG_BRIDGE("AndroidBridge::CallEglCreateWindowSurface"); - // Called off the main thread by the compositor - JNIEnv *env = GetJNIForThread(); + JNIEnv *env = GetJNIForThread(); // called on the compositor thread if (!env) return NULL; + AutoLocalJNIFrame jniFrame(env); + /* * This is basically: * @@ -1091,7 +1154,7 @@ AndroidBridge::CallEglCreateWindowSurface(void *dpy, void *config, AndroidGeckoS * We can't do it from java, because the EGLConfigImpl constructor is private. */ - jobject surfaceHolder = sview.GetSurfaceHolder(); + jobject surfaceHolder = sview.GetSurfaceHolder(env, &jniFrame); if (!surfaceHolder) return nsnull; @@ -1103,13 +1166,15 @@ AndroidBridge::CallEglCreateWindowSurface(void *dpy, void *config, AndroidGeckoS jmethodID createWindowSurface = env->GetMethodID(jEGL10Class, "eglCreateWindowSurface", "(Ljavax/microedition/khronos/egl/EGLDisplay;Ljavax/microedition/khronos/egl/EGLConfig;Ljava/lang/Object;[I)Ljavax/microedition/khronos/egl/EGLSurface;"); jobject egl = env->CallStaticObjectMethod(jEGLContextClass, getEgl); + if (jniFrame.CheckForException()) + return nsnull; jobject jdpy = env->NewObject(jEGLDisplayImplClass, constructDisplay, (int) dpy); jobject jconf = env->NewObject(jEGLConfigImplClass, constructConfig, (int) config); // make the call jobject surf = env->CallObjectMethod(egl, createWindowSurface, jdpy, jconf, surfaceHolder, NULL); - if (!surf) + if (jniFrame.CheckForException() || !surf) return nsnull; jfieldID sfield = env->GetFieldID(jEGLSurfaceImplClass, "mEGLSurface", "I"); @@ -1129,11 +1194,13 @@ AndroidBridge::RegisterCompositor() if (!env) return; - AutoLocalJNIFrame jniFrame(env, 3); + AutoLocalJNIFrame jniFrame(env); jmethodID registerCompositor = env->GetStaticMethodID(jLayerView, "registerCxxCompositor", "()Lorg/mozilla/gecko/gfx/GLController;"); jobject glController = env->CallStaticObjectMethod(jLayerView, registerCompositor); + if (jniFrame.CheckForException()) + return; sController.Acquire(env, glController); sController.SetGLVersion(2); @@ -1157,7 +1224,7 @@ AndroidBridge::GetStaticIntField(const char *className, const char *fieldName, P return false; } - AutoLocalJNIFrame jniFrame(env, 3); + AutoLocalJNIFrame jniFrame(env); jclass cls = env->FindClass(className); if (!cls) return false; @@ -1174,7 +1241,7 @@ AndroidBridge::GetStaticIntField(const char *className, const char *fieldName, P bool AndroidBridge::GetStaticStringField(const char *className, const char *fieldName, nsAString &result, JNIEnv* env /* = nsnull */) { - ALOG_BRIDGE("AndroidBridge::GetStaticIntField %s", fieldName); + ALOG_BRIDGE("AndroidBridge::GetStaticStringField %s", fieldName); if (!env) { env = GetJNIEnv(); @@ -1182,7 +1249,7 @@ AndroidBridge::GetStaticStringField(const char *className, const char *fieldName return false; } - AutoLocalJNIFrame jniFrame(env, 3); + AutoLocalJNIFrame jniFrame(env); jclass cls = env->FindClass(className); if (!cls) return false; @@ -1208,6 +1275,7 @@ AndroidBridge::SetKeepScreenOn(bool on) if (!env) return; + AutoLocalJNIFrame jniFrame(env, 0); env->CallStaticVoidMethod(sBridge->mGeckoAppShellClass, sBridge->jSetKeepScreenOn, on); } @@ -1265,7 +1333,7 @@ AndroidBridge::PostToJavaThread(JNIEnv *env, nsIRunnable* aRunnable, bool aMainT { mRunnableQueue.AppendObject(aRunnable); - AutoLocalJNIFrame jniFrame(env); + AutoLocalJNIFrame jniFrame(env, 0); env->CallStaticVoidMethod(mGeckoAppShellClass, jPostToJavaThread, (jboolean)aMainThread); } @@ -1350,6 +1418,7 @@ AndroidBridge::FireAndWaitForTracerEvent() { if (!env) return; + AutoLocalJNIFrame jniFrame(env, 0); env->CallStaticVoidMethod(mGeckoAppShellClass, jFireAndWaitForTracerEvent); } @@ -1483,7 +1552,11 @@ AndroidBridge::InitCamera(const nsCString& contentType, PRUint32 camera, PRUint3 NS_ConvertASCIItoUTF16 s(contentType); jstring jstrContentType = env->NewString(s.get(), NS_strlen(s.get())); + jobject obj = env->CallStaticObjectMethod(mGeckoAppShellClass, jInitCamera, jstrContentType, camera, *width, *height); + if (jniFrame.CheckForException()) + return false; + jintArray arr = static_cast(obj); if (!arr) return false; @@ -1502,13 +1575,13 @@ AndroidBridge::InitCamera(const nsCString& contentType, PRUint32 camera, PRUint3 } void -AndroidBridge::CloseCamera() { - +AndroidBridge::CloseCamera() +{ JNIEnv *env = GetJNIEnv(); if (!env) return; - AutoLocalJNIFrame jniFrame(env); + AutoLocalJNIFrame jniFrame(env, 0); env->CallStaticVoidMethod(mGeckoAppShellClass, jCloseCamera); } @@ -1522,6 +1595,7 @@ AndroidBridge::EnableBatteryNotifications() if (!env) return; + AutoLocalJNIFrame jniFrame(env, 0); env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableBatteryNotifications); } @@ -1534,6 +1608,7 @@ AndroidBridge::DisableBatteryNotifications() if (!env) return; + AutoLocalJNIFrame jniFrame(env, 0); env->CallStaticVoidMethod(mGeckoAppShellClass, jDisableBatteryNotifications); } @@ -1551,6 +1626,9 @@ AndroidBridge::GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInf // To prevent calling too many methods through JNI, the Java method returns // an array of double even if we actually want a double and a boolean. jobject obj = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetCurrentBatteryInformation); + if (jniFrame.CheckForException()) + return; + jdoubleArray arr = static_cast(obj); if (!arr || env->GetArrayLength(arr) != 3) { return; @@ -1574,15 +1652,12 @@ AndroidBridge::HandleGeckoMessage(const nsAString &aMessage, nsAString &aRet) if (!env) return; - AutoLocalJNIFrame jniFrame(env, 1); + AutoLocalJNIFrame jniFrame(env); jstring jMessage = env->NewString(nsPromiseFlatString(aMessage).get(), aMessage.Length()); jstring returnMessage = static_cast(env->CallStaticObjectMethod(mGeckoAppShellClass, jHandleGeckoMessage, jMessage)); + if (jniFrame.CheckForException()) + return; - jthrowable ex = env->ExceptionOccurred(); - if (ex) { - env->ExceptionDescribe(); - env->ExceptionClear(); - } nsJNIString jniStr(returnMessage, env); aRet.Assign(jniStr); ALOG_BRIDGE("leaving %s", __PRETTY_FUNCTION__); @@ -1602,8 +1677,8 @@ AndroidBridge::CheckURIVisited(const nsAString& aURI) JNIEnv *env = GetJNIEnv(); if (!env) return; - - AutoLocalJNIFrame jniFrame(env, 1); + + AutoLocalJNIFrame jniFrame(env); jstring jstrURI = env->NewString(nsPromiseFlatString(aURI).get(), aURI.Length()); env->CallStaticVoidMethod(mGeckoAppShellClass, jCheckUriVisited, jstrURI); } @@ -1615,7 +1690,7 @@ AndroidBridge::MarkURIVisited(const nsAString& aURI) if (!env) return; - AutoLocalJNIFrame jniFrame(env, 1); + AutoLocalJNIFrame jniFrame(env); jstring jstrURI = env->NewString(nsPromiseFlatString(aURI).get(), aURI.Length()); env->CallStaticVoidMethod(mGeckoAppShellClass, jMarkUriVisited, jstrURI); } @@ -1631,7 +1706,11 @@ AndroidBridge::GetNumberOfMessagesForText(const nsAString& aText) AutoLocalJNIFrame jniFrame(env); jstring jText = env->NewString(PromiseFlatString(aText).get(), aText.Length()); - return env->CallStaticIntMethod(mGeckoAppShellClass, jNumberOfMessages, jText); + PRUint16 ret = env->CallStaticIntMethod(mGeckoAppShellClass, jNumberOfMessages, jText); + if (jniFrame.CheckForException()) + return 0; + + return ret; } void @@ -1660,10 +1739,14 @@ AndroidBridge::SaveSentMessage(const nsAString& aRecipient, if (!env) return 0; - AutoLocalJNIFrame jniFrame(env, 1); + AutoLocalJNIFrame jniFrame(env); jstring jRecipient = env->NewString(PromiseFlatString(aRecipient).get(), aRecipient.Length()); jstring jBody = env->NewString(PromiseFlatString(aBody).get(), aBody.Length()); - return env->CallStaticIntMethod(mGeckoAppShellClass, jSaveSentMessage, jRecipient, jBody, aDate); + PRInt32 ret = env->CallStaticIntMethod(mGeckoAppShellClass, jSaveSentMessage, jRecipient, jBody, aDate); + if (jniFrame.CheckForException()) + return 0; + + return ret; } void @@ -1675,6 +1758,7 @@ AndroidBridge::GetMessage(PRInt32 aMessageId, PRInt32 aRequestId, PRUint64 aProc if (!env) return; + AutoLocalJNIFrame jniFrame(env, 0); env->CallStaticVoidMethod(mGeckoAppShellClass, jGetMessage, aMessageId, aRequestId, aProcessId); } @@ -1687,6 +1771,7 @@ AndroidBridge::DeleteMessage(PRInt32 aMessageId, PRInt32 aRequestId, PRUint64 aP if (!env) return; + AutoLocalJNIFrame jniFrame(env, 0); env->CallStaticVoidMethod(mGeckoAppShellClass, jDeleteMessage, aMessageId, aRequestId, aProcessId); } @@ -1728,6 +1813,7 @@ AndroidBridge::GetNextMessageInList(PRInt32 aListId, PRInt32 aRequestId, PRUint6 if (!env) return; + AutoLocalJNIFrame jniFrame(env, 0); env->CallStaticVoidMethod(mGeckoAppShellClass, jGetNextMessageinList, aListId, aRequestId, aProcessId); } @@ -1740,6 +1826,7 @@ AndroidBridge::ClearMessageList(PRInt32 aListId) if (!env) return; + AutoLocalJNIFrame jniFrame(env, 0); env->CallStaticVoidMethod(mGeckoAppShellClass, jClearMessageList, aListId); } @@ -1757,6 +1844,9 @@ AndroidBridge::GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInf // To prevent calling too many methods through JNI, the Java method returns // an array of double even if we actually want a double and a boolean. jobject obj = env->CallStaticObjectMethod(mGeckoAppShellClass, jGetCurrentNetworkInformation); + if (jniFrame.CheckForException()) + return; + jdoubleArray arr = static_cast(obj); if (!arr || env->GetArrayLength(arr) != 2) { return; @@ -1778,6 +1868,7 @@ AndroidBridge::EnableNetworkNotifications() if (!env) return; + AutoLocalJNIFrame jniFrame(env, 0); env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableNetworkNotifications); } @@ -1789,19 +1880,22 @@ AndroidBridge::DisableNetworkNotifications() if (!env) return; + AutoLocalJNIFrame jniFrame(env, 0); env->CallStaticVoidMethod(mGeckoAppShellClass, jDisableNetworkNotifications); } void * AndroidBridge::LockBitmap(jobject bitmap) { - int err; - void *buf; - JNIEnv *env = GetJNIEnv(); if (!env) return nsnull; + AutoLocalJNIFrame jniFrame(env); + + int err; + void *buf; + if ((err = AndroidBitmap_lockPixels(env, bitmap, &buf)) != 0) { ALOG_BRIDGE("AndroidBitmap_lockPixels failed! (error %d)", err); buf = nsnull; @@ -1813,12 +1907,14 @@ AndroidBridge::LockBitmap(jobject bitmap) void AndroidBridge::UnlockBitmap(jobject bitmap) { - int err; - JNIEnv *env = GetJNIEnv(); if (!env) return; + AutoLocalJNIFrame jniFrame(env); + + int err; + if ((err = AndroidBitmap_unlockPixels(env, bitmap)) != 0) ALOG_BRIDGE("AndroidBitmap_unlockPixels failed! (error %d)", err); } @@ -1966,7 +2062,13 @@ AndroidBridge::IsTablet() if (!env) return false; - return env->CallStaticBooleanMethod(mGeckoAppShellClass, jIsTablet); + AutoLocalJNIFrame jniFrame(env, 0); + + bool ret = env->CallStaticBooleanMethod(mGeckoAppShellClass, jIsTablet); + if (jniFrame.CheckForException()) + return false; + + return ret; } void @@ -2036,11 +2138,13 @@ NS_IMETHODIMP nsAndroidBridge::SetDrawMetadataProvider(nsIAndroidDrawMetadataPro } void -AndroidBridge::NotifyDefaultPrevented(bool aDefaultPrevented) { +AndroidBridge::NotifyDefaultPrevented(bool aDefaultPrevented) +{ JNIEnv *env = GetJNIEnv(); if (!env) return; + AutoLocalJNIFrame jniFrame(env, 0); env->CallStaticVoidMethod(mGeckoAppShellClass, jNotifyDefaultPrevented, (jboolean)aDefaultPrevented); } @@ -2097,9 +2201,12 @@ AndroidBridge::CreateSurface() if (!env) return nsnull; - AutoLocalJNIFrame frame(env); + AutoLocalJNIFrame jniFrame(env); jobject surface = env->CallStaticObjectMethod(mGeckoAppShellClass, jCreateSurface); + if (jniFrame.CheckForException()) + return nsnull; + if (surface) surface = env->NewGlobalRef(surface); @@ -2115,7 +2222,7 @@ AndroidBridge::DestroySurface(jobject surface) if (!env) return; - AutoLocalJNIFrame frame(env); + AutoLocalJNIFrame jniFrame(env); env->CallStaticVoidMethod(mGeckoAppShellClass, jDestroySurface, surface); env->DeleteGlobalRef(surface); @@ -2130,7 +2237,7 @@ AndroidBridge::ShowSurface(jobject surface, const gfxRect& aRect, bool aInverted if (!env) return; - AutoLocalJNIFrame frame(env); + AutoLocalJNIFrame jniFrame(env, 0); env->CallStaticVoidMethod(mGeckoAppShellClass, jShowSurface, surface, (int)aRect.x, (int)aRect.y, @@ -2147,7 +2254,7 @@ AndroidBridge::HideSurface(jobject surface) if (!env) return; - AutoLocalJNIFrame frame(env); + AutoLocalJNIFrame jniFrame(env, 0); env->CallStaticVoidMethod(mGeckoAppShellClass, jHideSurface, surface); #endif @@ -2157,35 +2264,65 @@ void AndroidBridge::GetScreenOrientation(dom::ScreenOrientationWrapper& aOrientation) { ALOG_BRIDGE("AndroidBridge::GetScreenOrientation"); - aOrientation.orientation = static_cast(mJNIEnv->CallStaticShortMethod(mGeckoAppShellClass, jGetScreenOrientation)); + JNIEnv* env = GetJNIEnv(); + if (!env) + return; + + AutoLocalJNIFrame jniFrame(env, 0); + + jshort orientation = env->CallStaticShortMethod(mGeckoAppShellClass, jGetScreenOrientation); + if (jniFrame.CheckForException()) + return; + + aOrientation.orientation = static_cast(orientation); } void AndroidBridge::EnableScreenOrientationNotifications() { ALOG_BRIDGE("AndroidBridge::EnableScreenOrientationNotifications"); - mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jEnableScreenOrientationNotifications); + JNIEnv* env = GetJNIEnv(); + if (!env) + return; + + AutoLocalJNIFrame jniFrame(env, 0); + env->CallStaticVoidMethod(mGeckoAppShellClass, jEnableScreenOrientationNotifications); } void AndroidBridge::DisableScreenOrientationNotifications() { ALOG_BRIDGE("AndroidBridge::DisableScreenOrientationNotifications"); - mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jDisableScreenOrientationNotifications); + JNIEnv* env = GetJNIEnv(); + if (!env) + return; + + AutoLocalJNIFrame jniFrame(env, 0); + env->CallStaticVoidMethod(mGeckoAppShellClass, jDisableScreenOrientationNotifications); } void AndroidBridge::LockScreenOrientation(const dom::ScreenOrientationWrapper& aOrientation) { ALOG_BRIDGE("AndroidBridge::LockScreenOrientation"); - mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jLockScreenOrientation, aOrientation.orientation); + JNIEnv* env = GetJNIEnv(); + if (!env) + return; + + AutoLocalJNIFrame jniFrame(env, 0); + env->CallStaticVoidMethod(mGeckoAppShellClass, jLockScreenOrientation, aOrientation.orientation); } void AndroidBridge::UnlockScreenOrientation() { ALOG_BRIDGE("AndroidBridge::UnlockScreenOrientation"); - mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jUnlockScreenOrientation); + JNIEnv* env = GetJNIEnv(); + if (!env) + return; + + AutoLocalJNIFrame jniFrame(env, 0); + env->CallStaticVoidMethod(mGeckoAppShellClass, jUnlockScreenOrientation); } void @@ -2196,7 +2333,7 @@ AndroidBridge::PumpMessageLoop() if (!env) return; - AutoLocalJNIFrame frame(env); + AutoLocalJNIFrame jniFrame(env, 0); if ((void*)pthread_self() != mThread) return; @@ -2212,6 +2349,7 @@ NS_IMETHODIMP nsAndroidBridge::GetBrowserApp(nsIAndroidBrowserApp * *aBrowserApp nsAppShell::gAppShell->GetBrowserApp(aBrowserApp); return NS_OK; } + NS_IMETHODIMP nsAndroidBridge::SetBrowserApp(nsIAndroidBrowserApp *aBrowserApp) { if (nsAppShell::gAppShell) @@ -2225,7 +2363,7 @@ AndroidBridge::AddPluginView(jobject view, const gfxRect& rect) { if (!env) return; - AutoLocalJNIFrame frame(env); + AutoLocalJNIFrame jniFrame(env); #if MOZ_JAVA_COMPOSITOR env->CallStaticVoidMethod(sBridge->mGeckoAppShellClass, @@ -2239,23 +2377,30 @@ AndroidBridge::AddPluginView(jobject view, const gfxRect& rect) { } void -AndroidBridge::RemovePluginView(jobject view) { +AndroidBridge::RemovePluginView(jobject view) +{ JNIEnv *env = GetJNIEnv(); if (!env) return; - AutoLocalJNIFrame frame(env); + AutoLocalJNIFrame jniFrame(env, 0); env->CallStaticVoidMethod(mGeckoAppShellClass, jRemovePluginView, view); } extern "C" __attribute__ ((visibility("default"))) jobject JNICALL -Java_org_mozilla_gecko_GeckoAppShell_allocateDirectBuffer(JNIEnv *jenv, jclass, jlong size); +Java_org_mozilla_gecko_GeckoAppShell_allocateDirectBuffer(JNIEnv *env, jclass, jlong size); nsresult AndroidBridge::TakeScreenshot(nsIDOMWindow *window, PRInt32 srcX, PRInt32 srcY, PRInt32 srcW, PRInt32 srcH, PRInt32 dstW, PRInt32 dstH, PRInt32 tabId, float scale, PRInt32 token) { + JNIEnv* env = GetJNIEnv(); + if (!env) + return NS_OK; + + AutoLocalJNIFrame jniFrame(env); + nsCOMPtr win = do_QueryInterface(window); if (!win) return NS_ERROR_FAILURE; @@ -2275,34 +2420,31 @@ nsresult AndroidBridge::TakeScreenshot(nsIDOMWindow *window, PRInt32 srcX, PRInt nsPresContext::CSSPixelsToAppUnits(srcW / scale), nsPresContext::CSSPixelsToAppUnits(srcH / scale)); - JNIEnv* jenv = GetJNIEnv(); - if (!jenv) - return NS_OK; - PRUint32 stride = dstW * 2; PRUint32 bufferSize = dstH * stride; - jobject buffer = Java_org_mozilla_gecko_GeckoAppShell_allocateDirectBuffer(jenv, NULL, bufferSize); + jobject buffer = Java_org_mozilla_gecko_GeckoAppShell_allocateDirectBuffer(env, NULL, bufferSize); if (!buffer) return NS_OK; - void* data = jenv->GetDirectBufferAddress(buffer); + void* data = env->GetDirectBufferAddress(buffer); memset(data, 0, bufferSize); nsRefPtr surf = new gfxImageSurface(static_cast(data), nsIntSize(dstW, dstH), stride, gfxASurface::ImageFormatRGB16_565); nsRefPtr context = new gfxContext(surf); context->Scale(scale * dstW / srcW, scale * dstH / srcH); nsresult rv = presShell->RenderDocument(r, renderDocFlags, bgColor, context); NS_ENSURE_SUCCESS(rv, rv); - AutoLocalJNIFrame jniFrame(jenv, 1); - jenv->CallStaticVoidMethod(AndroidBridge::Bridge()->mGeckoAppShellClass, AndroidBridge::Bridge()->jNotifyScreenShot, buffer, tabId, srcX * dstW / srcW , srcY * dstH / srcH, dstW, dstH, token); + env->CallStaticVoidMethod(AndroidBridge::Bridge()->mGeckoAppShellClass, AndroidBridge::Bridge()->jNotifyScreenShot, buffer, tabId, srcX * dstW / srcW , srcY * dstH / srcH, dstW, dstH, token); return NS_OK; } void AndroidBridge::NotifyPaintedRect(float top, float left, float bottom, float right) { - JNIEnv* jenv = GetJNIEnv(); - if (!jenv) + JNIEnv* env = GetJNIEnv(); + if (!env) return; - jenv->CallStaticVoidMethod(AndroidBridge::Bridge()->mGeckoAppShellClass, AndroidBridge::Bridge()->jNotifyPaintedRect, top, left, bottom, right); + + AutoLocalJNIFrame jniFrame(env, 0); + env->CallStaticVoidMethod(AndroidBridge::Bridge()->mGeckoAppShellClass, AndroidBridge::Bridge()->jNotifyPaintedRect, top, left, bottom, right); } diff --git a/widget/android/AndroidBridge.h b/widget/android/AndroidBridge.h index a8fd2a74c9c..32cedd8d551 100644 --- a/widget/android/AndroidBridge.h +++ b/widget/android/AndroidBridge.h @@ -289,68 +289,6 @@ public: void FireAndWaitForTracerEvent(); - class AutoLocalJNIFrame { - public: - AutoLocalJNIFrame(int nEntries = 128) - : mEntries(nEntries) - { - mJNIEnv = AndroidBridge::GetJNIEnv(); - Push(); - } - - AutoLocalJNIFrame(JNIEnv* aJNIEnv, int nEntries = 128) - : mEntries(nEntries) - { - mJNIEnv = aJNIEnv ? aJNIEnv : AndroidBridge::GetJNIEnv(); - - Push(); - } - - // Note! Calling Purge makes all previous local refs created in - // the AutoLocalJNIFrame's scope INVALID; be sure that you locked down - // any local refs that you need to keep around in global refs! - void Purge() { - if (mJNIEnv) { - mJNIEnv->PopLocalFrame(NULL); - Push(); - } - } - - bool CheckForException() { - jthrowable exception = mJNIEnv->ExceptionOccurred(); - if (exception) { - mJNIEnv->ExceptionDescribe(); - mJNIEnv->ExceptionClear(); - return true; - } - - return false; - } - - ~AutoLocalJNIFrame() { - if (!mJNIEnv) - return; - - CheckForException(); - - mJNIEnv->PopLocalFrame(NULL); - } - - private: - void Push() { - if (!mJNIEnv) - return; - - // Make sure there is enough space to store a local ref to the - // exception. I am not completely sure this is needed, but does - // not hurt. - mJNIEnv->PushLocalFrame(mEntries + 1); - } - - int mEntries; - JNIEnv* mJNIEnv; - }; - /* See GLHelpers.java as to why this is needed */ void *CallEglCreateWindowSurface(void *dpy, void *config, AndroidGeckoSurfaceView& surfaceView); @@ -609,6 +547,71 @@ protected: void (* Region_set)(void* region, void* rect); }; +class AutoLocalJNIFrame { +public: + AutoLocalJNIFrame(int nEntries = 128) + : mEntries(nEntries) + { + mJNIEnv = AndroidBridge::GetJNIEnv(); + Push(); + } + + AutoLocalJNIFrame(JNIEnv* aJNIEnv, int nEntries = 128) + : mEntries(nEntries) + { + mJNIEnv = aJNIEnv ? aJNIEnv : AndroidBridge::GetJNIEnv(); + + Push(); + } + + // Note! Calling Purge makes all previous local refs created in + // the AutoLocalJNIFrame's scope INVALID; be sure that you locked down + // any local refs that you need to keep around in global refs! + void Purge() { + if (mJNIEnv) { + mJNIEnv->PopLocalFrame(NULL); + Push(); + } + } + + bool CheckForException() { + if (mJNIEnv->ExceptionCheck()) { + mJNIEnv->ExceptionDescribe(); + mJNIEnv->ExceptionClear(); + return true; + } + + return false; + } + + ~AutoLocalJNIFrame() { + if (!mJNIEnv) + return; + + CheckForException(); + + mJNIEnv->PopLocalFrame(NULL); + } + +private: + void Push() { + if (!mJNIEnv) + return; + + // Make sure there is enough space to store a local ref to the + // exception. I am not completely sure this is needed, but does + // not hurt. + jint ret = mJNIEnv->PushLocalFrame(mEntries + 1); + NS_ABORT_IF_FALSE(ret == 0, "Failed to push local JNI frame"); + if (ret < 0) { + CheckForException(); + } + } + + int mEntries; + JNIEnv* mJNIEnv; +}; + } #define NS_ANDROIDBRIDGE_CID \ diff --git a/widget/android/AndroidJavaWrappers.cpp b/widget/android/AndroidJavaWrappers.cpp index 664533f59e1..4b9f349dcea 100644 --- a/widget/android/AndroidJavaWrappers.cpp +++ b/widget/android/AndroidJavaWrappers.cpp @@ -225,13 +225,22 @@ AndroidLocation::InitLocationClass(JNIEnv *jEnv) nsGeoPosition* AndroidLocation::CreateGeoPosition(JNIEnv *jenv, jobject jobj) { + AutoLocalJNIFrame jniFrame(jenv); + double latitude = jenv->CallDoubleMethod(jobj, jGetLatitudeMethod); + if (jniFrame.CheckForException()) return NULL; double longitude = jenv->CallDoubleMethod(jobj, jGetLongitudeMethod); + if (jniFrame.CheckForException()) return NULL; double altitude = jenv->CallDoubleMethod(jobj, jGetAltitudeMethod); + if (jniFrame.CheckForException()) return NULL; float accuracy = jenv->CallFloatMethod (jobj, jGetAccuracyMethod); + if (jniFrame.CheckForException()) return NULL; float bearing = jenv->CallFloatMethod (jobj, jGetBearingMethod); + if (jniFrame.CheckForException()) return NULL; float speed = jenv->CallFloatMethod (jobj, jGetSpeedMethod); + if (jniFrame.CheckForException()) return NULL; long long time = jenv->CallLongMethod (jobj, jGetTimeMethod); + if (jniFrame.CheckForException()) return NULL; return new nsGeoPosition(latitude, longitude, altitude, accuracy, @@ -631,7 +640,13 @@ AndroidGeckoSurfaceView::BeginDrawing() if (!env) return 0; - return env->CallIntMethod(wrapped_obj, jBeginDrawingMethod); + AutoLocalJNIFrame jniFrame(env, 0); + + int ret = env->CallIntMethod(wrapped_obj, jBeginDrawingMethod); + if (jniFrame.CheckForException()) + return 0; + + return ret; } void @@ -641,6 +656,7 @@ AndroidGeckoSurfaceView::EndDrawing() if (!env) return; + AutoLocalJNIFrame jniFrame(env, 0); env->CallVoidMethod(wrapped_obj, jEndDrawingMethod); } @@ -651,6 +667,7 @@ AndroidGeckoSurfaceView::Draw2D(jobject bitmap, int width, int height) if (!env) return; + AutoLocalJNIFrame jniFrame(env, 0); env->CallVoidMethod(wrapped_obj, jDraw2DBitmapMethod, bitmap, width, height); } @@ -661,6 +678,7 @@ AndroidGeckoSurfaceView::Draw2D(jobject buffer, int stride) if (!env) return; + AutoLocalJNIFrame jniFrame(env, 0); env->CallVoidMethod(wrapped_obj, jDraw2DBufferMethod, buffer, stride); } @@ -673,7 +691,7 @@ AndroidGeckoLayerClient::SetFirstPaintViewport(float aOffsetX, float aOffsetY, f if (!env) return; - AndroidBridge::AutoLocalJNIFrame jniFrame(env); + AutoLocalJNIFrame jniFrame(env, 0); return env->CallVoidMethod(wrapped_obj, jSetFirstPaintViewport, aOffsetX, aOffsetY, aZoom, aPageWidth, aPageHeight, aCssPageWidth, aCssPageHeight); } @@ -686,7 +704,7 @@ AndroidGeckoLayerClient::SetPageSize(float aZoom, float aPageWidth, float aPageH if (!env) return; - AndroidBridge::AutoLocalJNIFrame jniFrame(env); + AutoLocalJNIFrame jniFrame(env, 0); return env->CallVoidMethod(wrapped_obj, jSetPageSize, aZoom, aPageWidth, aPageHeight, aCssPageWidth, aCssPageHeight); } @@ -699,14 +717,18 @@ AndroidGeckoLayerClient::SyncViewportInfo(const nsIntRect& aDisplayPort, float a if (!env) return; - AndroidViewTransform viewTransform; - AndroidBridge::AutoLocalJNIFrame jniFrame(env); + AutoLocalJNIFrame jniFrame(env); jobject viewTransformJObj = env->CallObjectMethod(wrapped_obj, jSyncViewportInfoMethod, aDisplayPort.x, aDisplayPort.y, aDisplayPort.width, aDisplayPort.height, aDisplayResolution, aLayersUpdated); + if (jniFrame.CheckForException()) + return; + NS_ABORT_IF_FALSE(viewTransformJObj, "No view transform object!"); + + AndroidViewTransform viewTransform; viewTransform.Init(viewTransformJObj); aScrollOffset = nsIntPoint(viewTransform.GetX(env), viewTransform.GetY(env)); @@ -714,51 +736,69 @@ AndroidGeckoLayerClient::SyncViewportInfo(const nsIntRect& aDisplayPort, float a } jobject -AndroidGeckoSurfaceView::GetSoftwareDrawBitmap() +AndroidGeckoSurfaceView::GetSoftwareDrawBitmap(JNIEnv *env, AutoLocalJNIFrame *jniFrame) { - JNIEnv *env = AndroidBridge::GetJNIEnv(); - if (!env) + if (!env || !jniFrame) return nsnull; - return env->CallObjectMethod(wrapped_obj, jGetSoftwareDrawBitmapMethod); + jobject ret = env->CallObjectMethod(wrapped_obj, jGetSoftwareDrawBitmapMethod); + if (jniFrame->CheckForException()) + return nsnull; + + return ret; } jobject -AndroidGeckoSurfaceView::GetSoftwareDrawBuffer() +AndroidGeckoSurfaceView::GetSoftwareDrawBuffer(JNIEnv *env, AutoLocalJNIFrame *jniFrame) { - JNIEnv *env = AndroidBridge::GetJNIEnv(); - if (!env) + if (!env || !jniFrame) return nsnull; - return env->CallObjectMethod(wrapped_obj, jGetSoftwareDrawBufferMethod); + jobject ret = env->CallObjectMethod(wrapped_obj, jGetSoftwareDrawBufferMethod); + if (jniFrame->CheckForException()) + return nsnull; + + return ret; } jobject -AndroidGeckoSurfaceView::GetSurface() +AndroidGeckoSurfaceView::GetSurface(JNIEnv *env, AutoLocalJNIFrame *jniFrame) { - JNIEnv *env = AndroidBridge::GetJNIEnv(); - if (!env) + if (!env || !jniFrame) return nsnull; - return env->CallObjectMethod(wrapped_obj, jGetSurfaceMethod); + jobject ret = env->CallObjectMethod(wrapped_obj, jGetSurfaceMethod); + if (jniFrame->CheckForException()) + return nsnull; + + return ret; } jobject -AndroidGeckoSurfaceView::GetSurfaceHolder() +AndroidGeckoSurfaceView::GetSurfaceHolder(JNIEnv *env, AutoLocalJNIFrame *jniFrame) { - JNIEnv *env = GetJNIForThread(); - if (!env) + if (!env || !jniFrame) return nsnull; - return env->CallObjectMethod(wrapped_obj, jGetHolderMethod); + jobject ret = env->CallObjectMethod(wrapped_obj, jGetHolderMethod); + if (jniFrame->CheckForException()) + return nsnull; + + return ret; } -void +bool AndroidGeckoLayerClient::CreateFrame(JNIEnv *env, AndroidLayerRendererFrame& aFrame) { + AutoLocalJNIFrame jniFrame(env, 1); + jobject frameJObj = env->CallObjectMethod(wrapped_obj, jCreateFrameMethod); + if (jniFrame.CheckForException()) + return false; NS_ABORT_IF_FALSE(frameJObj, "No frame object!"); + aFrame.Init(env, frameJObj); + return true; } void diff --git a/widget/android/AndroidJavaWrappers.h b/widget/android/AndroidJavaWrappers.h index bcb6751fdd4..1d411f6e702 100644 --- a/widget/android/AndroidJavaWrappers.h +++ b/widget/android/AndroidJavaWrappers.h @@ -59,6 +59,7 @@ namespace mozilla { class AndroidGeckoLayerClient; +class AutoLocalJNIFrame; void InitAndroidJavaWrappers(JNIEnv *jEnv); @@ -207,7 +208,7 @@ public: void SetPageSize(float aZoom, float aPageWidth, float aPageHeight, float aCssPageWidth, float aCssPageHeight); void SyncViewportInfo(const nsIntRect& aDisplayPort, float aDisplayResolution, bool aLayersUpdated, nsIntPoint& aScrollOffset, float& aScaleX, float& aScaleY); - void CreateFrame(JNIEnv *env, AndroidLayerRendererFrame& aFrame); + bool CreateFrame(JNIEnv *env, AndroidLayerRendererFrame& aFrame); void ActivateProgram(JNIEnv *env); void DeactivateProgram(JNIEnv *env); @@ -241,17 +242,14 @@ public: }; int BeginDrawing(); - jobject GetSoftwareDrawBitmap(); - jobject GetSoftwareDrawBuffer(); + jobject GetSoftwareDrawBitmap(JNIEnv *env, AutoLocalJNIFrame *jniFrame); + jobject GetSoftwareDrawBuffer(JNIEnv *env, AutoLocalJNIFrame *jniFrame); void EndDrawing(); void Draw2D(jobject bitmap, int width, int height); void Draw2D(jobject buffer, int stride); - jobject GetSurface(); - - // must have a JNI local frame when calling this, - // and you'd better know what you're doing - jobject GetSurfaceHolder(); + jobject GetSurface(JNIEnv *env, AutoLocalJNIFrame *jniFrame); + jobject GetSurfaceHolder(JNIEnv *env, AutoLocalJNIFrame *jniFrame); protected: static jclass jGeckoSurfaceViewClass; diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index 910f31c5a65..c9ff7c79712 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -914,11 +914,15 @@ nsWindow::OnGlobalAndroidEvent(AndroidGeckoEvent *ae) if (AndroidBridge::Bridge()->HasNativeWindowAccess()) { AndroidGeckoSurfaceView& sview(AndroidBridge::Bridge()->SurfaceView()); - jobject surface = sview.GetSurface(); - if (surface) { - sNativeWindow = AndroidBridge::Bridge()->AcquireNativeWindow(AndroidBridge::GetJNIEnv(), surface); - if (sNativeWindow) { - AndroidBridge::Bridge()->SetNativeWindowFormat(sNativeWindow, 0, 0, AndroidBridge::WINDOW_FORMAT_RGB_565); + JNIEnv *env = AndroidBridge::GetJNIEnv(); + if (env) { + AutoLocalJNIFrame jniFrame(env); + jobject surface = sview.GetSurface(env, &jniFrame); + if (surface) { + sNativeWindow = AndroidBridge::Bridge()->AcquireNativeWindow(env, surface); + if (sNativeWindow) { + AndroidBridge::Bridge()->SetNativeWindowFormat(sNativeWindow, 0, 0, AndroidBridge::WINDOW_FORMAT_RGB_565); + } } } } @@ -1109,7 +1113,11 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae) nsRefPtr kungFuDeathGrip(this); - AndroidBridge::AutoLocalJNIFrame jniFrame; + JNIEnv *env = AndroidBridge::GetJNIEnv(); + if (!env) + return; + AutoLocalJNIFrame jniFrame; + #ifdef MOZ_JAVA_COMPOSITOR // We're paused, or we haven't been given a window-size yet, so do nothing if (sCompositorPaused || gAndroidBounds.width <= 0 || gAndroidBounds.height <= 0) { @@ -1173,7 +1181,7 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae) AndroidBridge::Bridge()->UnlockWindow(sNativeWindow); } else if (AndroidBridge::Bridge()->HasNativeBitmapAccess()) { - jobject bitmap = sview.GetSoftwareDrawBitmap(); + jobject bitmap = sview.GetSoftwareDrawBitmap(env, &jniFrame); if (!bitmap) { ALOG("no bitmap to draw into - skipping draw"); return; @@ -1202,16 +1210,12 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae) AndroidBridge::Bridge()->UnlockBitmap(bitmap); sview.Draw2D(bitmap, mBounds.width, mBounds.height); } else { - jobject bytebuf = sview.GetSoftwareDrawBuffer(); + jobject bytebuf = sview.GetSoftwareDrawBuffer(env, &jniFrame); if (!bytebuf) { ALOG("no buffer to draw into - skipping draw"); return; } - JNIEnv *env = AndroidBridge::GetJNIEnv(); - if (!env) - return; - void *buf = env->GetDirectBufferAddress(bytebuf); int cap = env->GetDirectBufferCapacity(bytebuf); if (!buf || cap != (mBounds.width * mBounds.height * 2)) { @@ -2219,39 +2223,50 @@ nsWindow::GetIMEUpdatePreference() #ifdef MOZ_JAVA_COMPOSITOR void -nsWindow::DrawWindowUnderlay(LayerManager* aManager, nsIntRect aRect) { +nsWindow::DrawWindowUnderlay(LayerManager* aManager, nsIntRect aRect) +{ JNIEnv *env = GetJNIForThread(); NS_ABORT_IF_FALSE(env, "No JNI environment at DrawWindowUnderlay()!"); if (!env) return; - AndroidBridge::AutoLocalJNIFrame jniFrame(env); + AutoLocalJNIFrame jniFrame(env); AndroidGeckoLayerClient& client = AndroidBridge::Bridge()->GetLayerClient(); - client.CreateFrame(env, mLayerRendererFrame); + if (!client.CreateFrame(env, mLayerRendererFrame)) + return; client.ActivateProgram(env); + if (jniFrame.CheckForException()) return; mLayerRendererFrame.BeginDrawing(env); + if (jniFrame.CheckForException()) return; mLayerRendererFrame.DrawBackground(env); + if (jniFrame.CheckForException()) return; client.DeactivateProgram(env); } void -nsWindow::DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect) { +nsWindow::DrawWindowOverlay(LayerManager* aManager, nsIntRect aRect) +{ JNIEnv *env = GetJNIForThread(); NS_ABORT_IF_FALSE(env, "No JNI environment at DrawWindowOverlay()!"); if (!env) return; - AndroidBridge::AutoLocalJNIFrame jniFrame(env); + AutoLocalJNIFrame jniFrame(env); + NS_ABORT_IF_FALSE(!mLayerRendererFrame.isNull(), "Frame should have been created in DrawWindowUnderlay()!"); AndroidGeckoLayerClient& client = AndroidBridge::Bridge()->GetLayerClient(); client.ActivateProgram(env); + if (jniFrame.CheckForException()) return; mLayerRendererFrame.DrawForeground(env); + if (jniFrame.CheckForException()) return; mLayerRendererFrame.EndDrawing(env); + if (jniFrame.CheckForException()) return; client.DeactivateProgram(env); + if (jniFrame.CheckForException()) return; mLayerRendererFrame.Dispose(env); }