diff options
author | steveblock@chromium.org <steveblock@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-26 23:22:23 +0000 |
---|---|---|
committer | steveblock@chromium.org <steveblock@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-04-26 23:22:23 +0000 |
commit | d71a168fea36a3003e24da6b8223de83b0643691 (patch) | |
tree | e0a4a528f8eaa6c79f7082a256663aaabae9c7e3 /content/browser/renderer_host/java | |
parent | ec8ee1ff175f1b212d691cc225289d6d59b8017a (diff) | |
download | chromium_src-d71a168fea36a3003e24da6b8223de83b0643691.zip chromium_src-d71a168fea36a3003e24da6b8223de83b0643691.tar.gz chromium_src-d71a168fea36a3003e24da6b8223de83b0643691.tar.bz2 |
Handle uncaught exceptions from methods called through the Java Bridge
If a method called on a Java object through the Java Bridge throws an uncaught
exception, handle it native-side by clearing the exception to prevent a crash,
and throwing a JavaScript exception.
BUG=125194
Review URL: http://codereview.chromium.org/10239009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@134176 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/browser/renderer_host/java')
-rw-r--r-- | content/browser/renderer_host/java/java_bound_object.cc | 80 |
1 files changed, 48 insertions, 32 deletions
diff --git a/content/browser/renderer_host/java/java_bound_object.cc b/content/browser/renderer_host/java/java_bound_object.cc index c0d1aa5..ca2eb1a 100644 --- a/content/browser/renderer_host/java/java_bound_object.cc +++ b/content/browser/renderer_host/java/java_bound_object.cc @@ -114,82 +114,98 @@ bool JavaNPObject::GetProperty(NPObject* np_object, return false; } -// Calls a Java method through JNI and returns the result as an NPVariant. Note -// that this method does not do any type coercion. The Java return value is -// simply converted to the corresponding NPAPI type. -NPVariant CallJNIMethod(jobject object, const JavaType& return_type, - jmethodID id, jvalue* parameters) { +// Calls a Java method through JNI. If the Java method raises an uncaught +// exception, it is cleared and this method returns false. Otherwise, this +// method returns true and the Java method's return value is provided as an +// NPVariant. Note that this method does not do any type coercion. The Java +// return value is simply converted to the corresponding NPAPI type. +bool CallJNIMethod(jobject object, const JavaType& return_type, jmethodID id, + jvalue* parameters, NPVariant* result) { JNIEnv* env = AttachCurrentThread(); - NPVariant result; switch (return_type.type) { case JavaType::TypeBoolean: BOOLEAN_TO_NPVARIANT(env->CallBooleanMethodA(object, id, parameters), - result); + *result); break; case JavaType::TypeByte: - INT32_TO_NPVARIANT(env->CallByteMethodA(object, id, parameters), result); + INT32_TO_NPVARIANT(env->CallByteMethodA(object, id, parameters), *result); break; case JavaType::TypeChar: - INT32_TO_NPVARIANT(env->CallCharMethodA(object, id, parameters), result); + INT32_TO_NPVARIANT(env->CallCharMethodA(object, id, parameters), *result); break; case JavaType::TypeShort: - INT32_TO_NPVARIANT(env->CallShortMethodA(object, id, parameters), result); + INT32_TO_NPVARIANT(env->CallShortMethodA(object, id, parameters), + *result); break; case JavaType::TypeInt: - INT32_TO_NPVARIANT(env->CallIntMethodA(object, id, parameters), result); + INT32_TO_NPVARIANT(env->CallIntMethodA(object, id, parameters), *result); break; case JavaType::TypeLong: - DOUBLE_TO_NPVARIANT(env->CallLongMethodA(object, id, parameters), result); + DOUBLE_TO_NPVARIANT(env->CallLongMethodA(object, id, parameters), + *result); break; case JavaType::TypeFloat: DOUBLE_TO_NPVARIANT(env->CallFloatMethodA(object, id, parameters), - result); + *result); break; case JavaType::TypeDouble: DOUBLE_TO_NPVARIANT(env->CallDoubleMethodA(object, id, parameters), - result); + *result); break; case JavaType::TypeVoid: env->CallVoidMethodA(object, id, parameters); - VOID_TO_NPVARIANT(result); + VOID_TO_NPVARIANT(*result); break; case JavaType::TypeArray: // LIVECONNECT_COMPLIANCE: Existing behavior is to not call methods that // return arrays. Spec requires calling the method and converting the // result to a JavaScript array. - VOID_TO_NPVARIANT(result); + VOID_TO_NPVARIANT(*result); break; case JavaType::TypeString: { - ScopedJavaLocalRef<jstring> java_string(env, static_cast<jstring>( - env->CallObjectMethodA(object, id, parameters))); - if (!java_string.obj()) { + jstring java_string = static_cast<jstring>( + env->CallObjectMethodA(object, id, parameters)); + // If an exception was raised, we must clear it before calling most JNI + // methods. ScopedJavaLocalRef is liable to make such calls, so we test + // first. + if (base::android::ClearException(env)) { + return false; + } + ScopedJavaLocalRef<jstring> scoped_java_string(env, java_string); + if (!scoped_java_string.obj()) { // LIVECONNECT_COMPLIANCE: Existing behavior is to return undefined. // Spec requires returning a null string. - VOID_TO_NPVARIANT(result); + VOID_TO_NPVARIANT(*result); break; } - std::string str = base::android::ConvertJavaStringToUTF8(java_string); + std::string str = + base::android::ConvertJavaStringToUTF8(scoped_java_string); // Take a copy and pass ownership to the variant. We must allocate using // NPN_MemAlloc, to match NPN_ReleaseVariant, which uses NPN_MemFree. size_t length = str.length(); char* buffer = static_cast<char*>(NPN_MemAlloc(length)); str.copy(buffer, length, 0); - STRINGN_TO_NPVARIANT(buffer, length, result); + STRINGN_TO_NPVARIANT(buffer, length, *result); break; } case JavaType::TypeObject: { - ScopedJavaLocalRef<jobject> java_object( - env, - env->CallObjectMethodA(object, id, parameters)); - if (!java_object.obj()) { - NULL_TO_NPVARIANT(result); + // If an exception was raised, we must clear it before calling most JNI + // methods. ScopedJavaLocalRef is liable to make such calls, so we test + // first. + jobject java_object = env->CallObjectMethodA(object, id, parameters); + if (base::android::ClearException(env)) { + return false; + } + ScopedJavaLocalRef<jobject> scoped_java_object(env, java_object); + if (!scoped_java_object.obj()) { + NULL_TO_NPVARIANT(*result); break; } - OBJECT_TO_NPVARIANT(JavaBoundObject::Create(java_object), result); + OBJECT_TO_NPVARIANT(JavaBoundObject::Create(scoped_java_object), *result); break; } } - return result; + return !base::android::ClearException(env); } jvalue CoerceJavaScriptNumberToJavaValue(const NPVariant& variant, @@ -766,8 +782,8 @@ bool JavaBoundObject::Invoke(const std::string& name, const NPVariant* args, } // Call - *result = CallJNIMethod(java_object_.obj(), method->return_type(), - method->id(), ¶meters[0]); + bool ok = CallJNIMethod(java_object_.obj(), method->return_type(), + method->id(), ¶meters[0], result); // Now that we're done with the jvalue, release any local references created // by CoerceJavaScriptValueToJavaValue(). @@ -776,7 +792,7 @@ bool JavaBoundObject::Invoke(const std::string& name, const NPVariant* args, ReleaseJavaValueIfRequired(env, ¶meters[i], method->parameter_type(i)); } - return true; + return ok; } void JavaBoundObject::EnsureMethodsAreSetUp() const { |