Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1531)

Unified Diff: content/browser/renderer_host/java/java_bound_object.cc

Issue 336313018: [Android] Move content/browser/{renderer_host => android}/java/* (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Updated paths for unit tests, rebased Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/browser/renderer_host/java/java_bound_object.cc
diff --git a/content/browser/renderer_host/java/java_bound_object.cc b/content/browser/renderer_host/java/java_bound_object.cc
deleted file mode 100644
index f812c4296838eb5efe5fdeb15e9f2d584aea7953..0000000000000000000000000000000000000000
--- a/content/browser/renderer_host/java/java_bound_object.cc
+++ /dev/null
@@ -1,1040 +0,0 @@
-// Copyright (c) 2012 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 "content/browser/renderer_host/java/java_bound_object.h"
-
-#include "base/android/jni_android.h"
-#include "base/android/jni_string.h"
-#include "base/memory/singleton.h"
-#include "base/numerics/safe_conversions.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/stringprintf.h"
-#include "content/browser/renderer_host/java/java_bridge_dispatcher_host_manager.h"
-#include "content/browser/renderer_host/java/java_type.h"
-#include "content/browser/renderer_host/java/jni_helper.h"
-#include "content/public/browser/browser_thread.h"
-#include "third_party/WebKit/public/web/WebBindings.h"
-
-using base::StringPrintf;
-using base::android::AttachCurrentThread;
-using base::android::ConvertUTF8ToJavaString;
-using base::android::GetClass;
-using base::android::JavaRef;
-using base::android::ScopedJavaGlobalRef;
-using base::android::ScopedJavaLocalRef;
-using blink::WebBindings;
-
-// The conversion between JavaScript and Java types is based on the Live
-// Connect 2 spec. See
-// http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_CONVERSIONS.
-
-// Note that in some cases, we differ from from the spec in order to maintain
-// existing behavior. These areas are marked LIVECONNECT_COMPLIANCE. We may
-// revisit this decision in the future.
-
-namespace content {
-namespace {
-
-const char kJavaLangClass[] = "java/lang/Class";
-const char kJavaLangObject[] = "java/lang/Object";
-const char kJavaLangReflectMethod[] = "java/lang/reflect/Method";
-const char kJavaLangSecurityExceptionClass[] = "java/lang/SecurityException";
-const char kGetClass[] = "getClass";
-const char kGetMethods[] = "getMethods";
-const char kIsAnnotationPresent[] = "isAnnotationPresent";
-const char kReturningJavaLangClass[] = "()Ljava/lang/Class;";
-const char kReturningJavaLangReflectMethodArray[] =
- "()[Ljava/lang/reflect/Method;";
-const char kTakesJavaLangClassReturningBoolean[] = "(Ljava/lang/Class;)Z";
-// This is an exception message, so no need to localize.
-const char kAccessToObjectGetClassIsBlocked[] =
- "Access to java.lang.Object.getClass is blocked";
-
-// Our special NPObject type. We extend an NPObject with a pointer to a
-// JavaBoundObject. We also add static methods for each of the NPObject
-// callbacks, which are registered by our NPClass. These methods simply
-// delegate to the private implementation methods of JavaBoundObject.
-struct JavaNPObject : public NPObject {
- JavaBoundObject* bound_object;
-
- static const NPClass kNPClass;
-
- static NPObject* Allocate(NPP npp, NPClass* np_class);
- static void Deallocate(NPObject* np_object);
- static bool HasMethod(NPObject* np_object, NPIdentifier np_identifier);
- static bool Invoke(NPObject* np_object, NPIdentifier np_identifier,
- const NPVariant *args, uint32_t arg_count,
- NPVariant *result);
- static bool HasProperty(NPObject* np_object, NPIdentifier np_identifier);
- static bool GetProperty(NPObject* np_object, NPIdentifier np_identifier,
- NPVariant *result);
- static bool Enumerate(NPObject* object, NPIdentifier** values,
- uint32_t* count);
-};
-
-const NPClass JavaNPObject::kNPClass = {
- NP_CLASS_STRUCT_VERSION,
- JavaNPObject::Allocate,
- JavaNPObject::Deallocate,
- NULL, // NPInvalidate
- JavaNPObject::HasMethod,
- JavaNPObject::Invoke,
- NULL, // NPInvokeDefault
- JavaNPObject::HasProperty,
- JavaNPObject::GetProperty,
- NULL, // NPSetProperty,
- NULL, // NPRemoveProperty
- JavaNPObject::Enumerate,
- NULL,
-};
-
-NPObject* JavaNPObject::Allocate(NPP npp, NPClass* np_class) {
- JavaNPObject* obj = new JavaNPObject();
- return obj;
-}
-
-void JavaNPObject::Deallocate(NPObject* np_object) {
- JavaNPObject* obj = reinterpret_cast<JavaNPObject*>(np_object);
- delete obj->bound_object;
- delete obj;
-}
-
-bool JavaNPObject::HasMethod(NPObject* np_object, NPIdentifier np_identifier) {
- std::string name(WebBindings::utf8FromIdentifier(np_identifier));
- JavaNPObject* obj = reinterpret_cast<JavaNPObject*>(np_object);
- return obj->bound_object->HasMethod(name);
-}
-
-bool JavaNPObject::Invoke(NPObject* np_object, NPIdentifier np_identifier,
- const NPVariant* args, uint32_t arg_count,
- NPVariant* result) {
- std::string name(WebBindings::utf8FromIdentifier(np_identifier));
- JavaNPObject* obj = reinterpret_cast<JavaNPObject*>(np_object);
- return obj->bound_object->Invoke(name, args, arg_count, result);
-}
-
-bool JavaNPObject::HasProperty(NPObject* np_object,
- NPIdentifier np_identifier) {
- // LIVECONNECT_COMPLIANCE: Existing behavior is to return false to indicate
- // that the property is not present. Spec requires supporting this correctly.
- return false;
-}
-
-bool JavaNPObject::GetProperty(NPObject* np_object,
- NPIdentifier np_identifier,
- NPVariant* result) {
- // LIVECONNECT_COMPLIANCE: Existing behavior is to return false to indicate
- // that the property is undefined. Spec requires supporting this correctly.
- return false;
-}
-
-bool JavaNPObject::Enumerate(NPObject* np_object, NPIdentifier** values,
- uint32_t* count) {
- JavaNPObject* obj = reinterpret_cast<JavaNPObject*>(np_object);
- if (!obj->bound_object->CanEnumerateMethods()) return false;
- std::vector<std::string> method_names = obj->bound_object->GetMethodNames();
- *count = base::saturated_cast<uint32_t>(method_names.size());
- *values = static_cast<NPIdentifier*>(calloc(*count, sizeof(NPIdentifier)));
- for (uint32_t i = 0; i < *count; ++i) {
- (*values)[i] = WebBindings::getStringIdentifier(method_names[i].c_str());
- }
- return true;
-}
-
-// 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,
- jclass clazz,
- const JavaType& return_type,
- jmethodID id,
- jvalue* parameters,
- NPVariant* result,
- const JavaRef<jclass>& safe_annotation_clazz,
- const base::WeakPtr<JavaBridgeDispatcherHostManager>& manager,
- bool can_enumerate_methods) {
- DCHECK(object || clazz);
- JNIEnv* env = AttachCurrentThread();
- switch (return_type.type) {
- case JavaType::TypeBoolean:
- BOOLEAN_TO_NPVARIANT(
- object ? env->CallBooleanMethodA(object, id, parameters)
- : env->CallStaticBooleanMethodA(clazz, id, parameters),
- *result);
- break;
- case JavaType::TypeByte:
- INT32_TO_NPVARIANT(
- object ? env->CallByteMethodA(object, id, parameters)
- : env->CallStaticByteMethodA(clazz, id, parameters),
- *result);
- break;
- case JavaType::TypeChar:
- INT32_TO_NPVARIANT(
- object ? env->CallCharMethodA(object, id, parameters)
- : env->CallStaticCharMethodA(clazz, id, parameters),
- *result);
- break;
- case JavaType::TypeShort:
- INT32_TO_NPVARIANT(
- object ? env->CallShortMethodA(object, id, parameters)
- : env->CallStaticShortMethodA(clazz, id, parameters),
- *result);
- break;
- case JavaType::TypeInt:
- INT32_TO_NPVARIANT(object
- ? env->CallIntMethodA(object, id, parameters)
- : env->CallStaticIntMethodA(clazz, id, parameters),
- *result);
- break;
- case JavaType::TypeLong:
- DOUBLE_TO_NPVARIANT(
- object ? env->CallLongMethodA(object, id, parameters)
- : env->CallStaticLongMethodA(clazz, id, parameters),
- *result);
- break;
- case JavaType::TypeFloat:
- DOUBLE_TO_NPVARIANT(
- object ? env->CallFloatMethodA(object, id, parameters)
- : env->CallStaticFloatMethodA(clazz, id, parameters),
- *result);
- break;
- case JavaType::TypeDouble:
- DOUBLE_TO_NPVARIANT(
- object ? env->CallDoubleMethodA(object, id, parameters)
- : env->CallStaticDoubleMethodA(clazz, id, parameters),
- *result);
- break;
- case JavaType::TypeVoid:
- if (object)
- env->CallVoidMethodA(object, id, parameters);
- else
- env->CallStaticVoidMethodA(clazz, id, parameters);
- 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);
- break;
- case JavaType::TypeString: {
- jstring java_string = static_cast<jstring>(
- object ? env->CallObjectMethodA(object, id, parameters)
- : env->CallStaticObjectMethodA(clazz, 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);
- break;
- }
- std::string str =
- base::android::ConvertJavaStringToUTF8(scoped_java_string);
- size_t length = str.length();
- // This pointer is freed in _NPN_ReleaseVariantValue in
- // third_party/WebKit/Source/WebCore/bindings/v8/npruntime.cpp.
- char* buffer = static_cast<char*>(malloc(length));
- str.copy(buffer, length, 0);
- STRINGN_TO_NPVARIANT(buffer, length, *result);
- break;
- }
- case JavaType::TypeObject: {
- // 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 =
- object ? env->CallObjectMethodA(object, id, parameters)
- : env->CallStaticObjectMethodA(clazz, 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(scoped_java_object,
- safe_annotation_clazz,
- manager,
- can_enumerate_methods),
- *result);
- break;
- }
- }
- return !base::android::ClearException(env);
-}
-
-double RoundDoubleTowardsZero(const double& x) {
- if (std::isnan(x)) {
- return 0.0;
- }
- return x > 0.0 ? floor(x) : ceil(x);
-}
-
-// Rounds to jlong using Java's type conversion rules.
-jlong RoundDoubleToLong(const double& x) {
- double intermediate = RoundDoubleTowardsZero(x);
- // The int64 limits can not be converted exactly to double values, so we
- // compare to custom constants. kint64max is 2^63 - 1, but the spacing
- // between double values in the the range 2^62 to 2^63 is 2^10. The cast is
- // required to silence a spurious gcc warning for integer overflow.
- const int64 limit = (GG_INT64_C(1) << 63) - static_cast<uint64>(1 << 10);
- DCHECK(limit > 0);
- const double kLargestDoubleLessThanInt64Max = limit;
- const double kSmallestDoubleGreaterThanInt64Min = -limit;
- if (intermediate > kLargestDoubleLessThanInt64Max) {
- return kint64max;
- }
- if (intermediate < kSmallestDoubleGreaterThanInt64Min) {
- return kint64min;
- }
- return static_cast<jlong>(intermediate);
-}
-
-// Rounds to jint using Java's type conversion rules.
-jint RoundDoubleToInt(const double& x) {
- double intermediate = RoundDoubleTowardsZero(x);
- // The int32 limits cast exactly to double values.
- intermediate = std::min(intermediate, static_cast<double>(kint32max));
- intermediate = std::max(intermediate, static_cast<double>(kint32min));
- return static_cast<jint>(intermediate);
-}
-
-jvalue CoerceJavaScriptNumberToJavaValue(const NPVariant& variant,
- const JavaType& target_type,
- bool coerce_to_string) {
- // See http://jdk6.java.net/plugin2/liveconnect/#JS_NUMBER_VALUES.
-
- // For conversion to numeric types, we need to replicate Java's type
- // conversion rules. This requires that for integer values, we simply discard
- // all but the lowest n buts, where n is the number of bits in the target
- // type. For double values, the logic is more involved.
- jvalue result;
- DCHECK(variant.type == NPVariantType_Int32 ||
- variant.type == NPVariantType_Double);
- bool is_double = variant.type == NPVariantType_Double;
- switch (target_type.type) {
- case JavaType::TypeByte:
- result.b = is_double ?
- static_cast<jbyte>(RoundDoubleToInt(NPVARIANT_TO_DOUBLE(variant))) :
- static_cast<jbyte>(NPVARIANT_TO_INT32(variant));
- break;
- case JavaType::TypeChar:
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert double to 0.
- // Spec requires converting doubles similarly to how we convert doubles to
- // other numeric types.
- result.c = is_double ? 0 :
- static_cast<jchar>(NPVARIANT_TO_INT32(variant));
- break;
- case JavaType::TypeShort:
- result.s = is_double ?
- static_cast<jshort>(RoundDoubleToInt(NPVARIANT_TO_DOUBLE(variant))) :
- static_cast<jshort>(NPVARIANT_TO_INT32(variant));
- break;
- case JavaType::TypeInt:
- result.i = is_double ? RoundDoubleToInt(NPVARIANT_TO_DOUBLE(variant)) :
- NPVARIANT_TO_INT32(variant);
- break;
- case JavaType::TypeLong:
- result.j = is_double ? RoundDoubleToLong(NPVARIANT_TO_DOUBLE(variant)) :
- NPVARIANT_TO_INT32(variant);
- break;
- case JavaType::TypeFloat:
- result.f = is_double ? static_cast<jfloat>(NPVARIANT_TO_DOUBLE(variant)) :
- NPVARIANT_TO_INT32(variant);
- break;
- case JavaType::TypeDouble:
- result.d = is_double ? NPVARIANT_TO_DOUBLE(variant) :
- NPVARIANT_TO_INT32(variant);
- break;
- case JavaType::TypeObject:
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to null. Spec
- // requires handling object equivalents of primitive types.
- result.l = NULL;
- break;
- case JavaType::TypeString:
- result.l = coerce_to_string ?
- ConvertUTF8ToJavaString(
- AttachCurrentThread(),
- is_double ?
- base::StringPrintf("%.6lg", NPVARIANT_TO_DOUBLE(variant)) :
- base::Int64ToString(NPVARIANT_TO_INT32(variant))).Release() :
- NULL;
- break;
- case JavaType::TypeBoolean:
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to false. Spec
- // requires converting to false for 0 or NaN, true otherwise.
- result.z = JNI_FALSE;
- break;
- case JavaType::TypeArray:
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to null. Spec
- // requires raising a JavaScript exception.
- result.l = NULL;
- break;
- case JavaType::TypeVoid:
- // Conversion to void must never happen.
- NOTREACHED();
- break;
- }
- return result;
-}
-
-jvalue CoerceJavaScriptBooleanToJavaValue(const NPVariant& variant,
- const JavaType& target_type,
- bool coerce_to_string) {
- // See http://jdk6.java.net/plugin2/liveconnect/#JS_BOOLEAN_VALUES.
- DCHECK_EQ(NPVariantType_Bool, variant.type);
- bool boolean_value = NPVARIANT_TO_BOOLEAN(variant);
- jvalue result;
- switch (target_type.type) {
- case JavaType::TypeBoolean:
- result.z = boolean_value ? JNI_TRUE : JNI_FALSE;
- break;
- case JavaType::TypeObject:
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to NULL. Spec
- // requires handling java.lang.Boolean and java.lang.Object.
- result.l = NULL;
- break;
- case JavaType::TypeString:
- result.l = coerce_to_string ?
- ConvertUTF8ToJavaString(AttachCurrentThread(),
- boolean_value ? "true" : "false").Release() :
- NULL;
- break;
- case JavaType::TypeByte:
- case JavaType::TypeChar:
- case JavaType::TypeShort:
- case JavaType::TypeInt:
- case JavaType::TypeLong:
- case JavaType::TypeFloat:
- case JavaType::TypeDouble: {
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to 0. Spec
- // requires converting to 0 or 1.
- jvalue null_value = {0};
- result = null_value;
- break;
- }
- case JavaType::TypeArray:
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to NULL. Spec
- // requires raising a JavaScript exception.
- result.l = NULL;
- break;
- case JavaType::TypeVoid:
- // Conversion to void must never happen.
- NOTREACHED();
- break;
- }
- return result;
-}
-
-jvalue CoerceJavaScriptStringToJavaValue(const NPVariant& variant,
- const JavaType& target_type) {
- // See http://jdk6.java.net/plugin2/liveconnect/#JS_STRING_VALUES.
- DCHECK_EQ(NPVariantType_String, variant.type);
- jvalue result;
- switch (target_type.type) {
- case JavaType::TypeString:
- result.l = ConvertUTF8ToJavaString(
- AttachCurrentThread(),
- base::StringPiece(NPVARIANT_TO_STRING(variant).UTF8Characters,
- NPVARIANT_TO_STRING(variant).UTF8Length)).Release();
- break;
- case JavaType::TypeObject:
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to NULL. Spec
- // requires handling java.lang.Object.
- result.l = NULL;
- break;
- case JavaType::TypeByte:
- case JavaType::TypeShort:
- case JavaType::TypeInt:
- case JavaType::TypeLong:
- case JavaType::TypeFloat:
- case JavaType::TypeDouble: {
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to 0. Spec
- // requires using valueOf() method of corresponding object type.
- jvalue null_value = {0};
- result = null_value;
- break;
- }
- case JavaType::TypeChar:
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to 0. Spec
- // requires using java.lang.Short.decode().
- result.c = 0;
- break;
- case JavaType::TypeBoolean:
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to false. Spec
- // requires converting the empty string to false, otherwise true.
- result.z = JNI_FALSE;
- break;
- case JavaType::TypeArray:
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to NULL. Spec
- // requires raising a JavaScript exception.
- result.l = NULL;
- break;
- case JavaType::TypeVoid:
- // Conversion to void must never happen.
- NOTREACHED();
- break;
- }
- return result;
-}
-
-// Note that this only handles primitive types and strings.
-jobject CreateJavaArray(const JavaType& type, jsize length) {
- JNIEnv* env = AttachCurrentThread();
- switch (type.type) {
- case JavaType::TypeBoolean:
- return env->NewBooleanArray(length);
- case JavaType::TypeByte:
- return env->NewByteArray(length);
- case JavaType::TypeChar:
- return env->NewCharArray(length);
- case JavaType::TypeShort:
- return env->NewShortArray(length);
- case JavaType::TypeInt:
- return env->NewIntArray(length);
- case JavaType::TypeLong:
- return env->NewLongArray(length);
- case JavaType::TypeFloat:
- return env->NewFloatArray(length);
- case JavaType::TypeDouble:
- return env->NewDoubleArray(length);
- case JavaType::TypeString: {
- ScopedJavaLocalRef<jclass> clazz(GetClass(env, "java/lang/String"));
- return env->NewObjectArray(length, clazz.obj(), NULL);
- }
- case JavaType::TypeVoid:
- // Conversion to void must never happen.
- case JavaType::TypeArray:
- case JavaType::TypeObject:
- // Not handled.
- NOTREACHED();
- }
- return NULL;
-}
-
-// Sets the specified element of the supplied array to the value of the
-// supplied jvalue. Requires that the type of the array matches that of the
-// jvalue. Handles only primitive types and strings. Note that in the case of a
-// string, the array takes a new reference to the string object.
-void SetArrayElement(jobject array,
- const JavaType& type,
- jsize index,
- const jvalue& value) {
- JNIEnv* env = AttachCurrentThread();
- switch (type.type) {
- case JavaType::TypeBoolean:
- env->SetBooleanArrayRegion(static_cast<jbooleanArray>(array), index, 1,
- &value.z);
- break;
- case JavaType::TypeByte:
- env->SetByteArrayRegion(static_cast<jbyteArray>(array), index, 1,
- &value.b);
- break;
- case JavaType::TypeChar:
- env->SetCharArrayRegion(static_cast<jcharArray>(array), index, 1,
- &value.c);
- break;
- case JavaType::TypeShort:
- env->SetShortArrayRegion(static_cast<jshortArray>(array), index, 1,
- &value.s);
- break;
- case JavaType::TypeInt:
- env->SetIntArrayRegion(static_cast<jintArray>(array), index, 1,
- &value.i);
- break;
- case JavaType::TypeLong:
- env->SetLongArrayRegion(static_cast<jlongArray>(array), index, 1,
- &value.j);
- break;
- case JavaType::TypeFloat:
- env->SetFloatArrayRegion(static_cast<jfloatArray>(array), index, 1,
- &value.f);
- break;
- case JavaType::TypeDouble:
- env->SetDoubleArrayRegion(static_cast<jdoubleArray>(array), index, 1,
- &value.d);
- break;
- case JavaType::TypeString:
- env->SetObjectArrayElement(static_cast<jobjectArray>(array), index,
- value.l);
- break;
- case JavaType::TypeVoid:
- // Conversion to void must never happen.
- case JavaType::TypeArray:
- case JavaType::TypeObject:
- // Not handled.
- NOTREACHED();
- }
- base::android::CheckException(env);
-}
-
-void ReleaseJavaValueIfRequired(JNIEnv* env,
- jvalue* value,
- const JavaType& type) {
- if (type.type == JavaType::TypeString ||
- type.type == JavaType::TypeObject ||
- type.type == JavaType::TypeArray) {
- env->DeleteLocalRef(value->l);
- value->l = NULL;
- }
-}
-
-jvalue CoerceJavaScriptValueToJavaValue(const NPVariant& variant,
- const JavaType& target_type,
- bool coerce_to_string);
-
-// Returns a new local reference to a Java array.
-jobject CoerceJavaScriptObjectToArray(const NPVariant& variant,
- const JavaType& target_type) {
- DCHECK_EQ(JavaType::TypeArray, target_type.type);
- NPObject* object = NPVARIANT_TO_OBJECT(variant);
- DCHECK_NE(&JavaNPObject::kNPClass, object->_class);
-
- const JavaType& target_inner_type = *target_type.inner_type.get();
- // LIVECONNECT_COMPLIANCE: Existing behavior is to return null for
- // multi-dimensional arrays. Spec requires handling multi-demensional arrays.
- if (target_inner_type.type == JavaType::TypeArray) {
- return NULL;
- }
-
- // LIVECONNECT_COMPLIANCE: Existing behavior is to return null for object
- // arrays. Spec requires handling object arrays.
- if (target_inner_type.type == JavaType::TypeObject) {
- return NULL;
- }
-
- // If the object does not have a length property, return null.
- NPVariant length_variant;
- if (!WebBindings::getProperty(0, object,
- WebBindings::getStringIdentifier("length"),
- &length_variant)) {
- WebBindings::releaseVariantValue(&length_variant);
- return NULL;
- }
-
- // If the length property does not have numeric type, or is outside the valid
- // range for a Java array length, return null.
- jsize length = -1;
- if (NPVARIANT_IS_INT32(length_variant)
- && NPVARIANT_TO_INT32(length_variant) >= 0) {
- length = NPVARIANT_TO_INT32(length_variant);
- } else if (NPVARIANT_IS_DOUBLE(length_variant)
- && NPVARIANT_TO_DOUBLE(length_variant) >= 0.0
- && NPVARIANT_TO_DOUBLE(length_variant) <= kint32max) {
- length = static_cast<jsize>(NPVARIANT_TO_DOUBLE(length_variant));
- }
- WebBindings::releaseVariantValue(&length_variant);
- if (length == -1) {
- return NULL;
- }
-
- // Create the Java array.
- // TODO(steveblock): Handle failure to create the array.
- jobject result = CreateJavaArray(target_inner_type, length);
- NPVariant value_variant;
- JNIEnv* env = AttachCurrentThread();
- for (jsize i = 0; i < length; ++i) {
- // It seems that getProperty() will set the variant to type void on failure,
- // but this doesn't seem to be documented, so do it explicitly here for
- // safety.
- VOID_TO_NPVARIANT(value_variant);
- // If this fails, for example due to a missing element, we simply treat the
- // value as JavaScript undefined.
- WebBindings::getProperty(0, object, WebBindings::getIntIdentifier(i),
- &value_variant);
- jvalue element = CoerceJavaScriptValueToJavaValue(value_variant,
- target_inner_type,
- false);
- SetArrayElement(result, target_inner_type, i, element);
- // CoerceJavaScriptValueToJavaValue() creates new local references to
- // strings, objects and arrays. Of these, only strings can occur here.
- // SetArrayElement() causes the array to take its own reference to the
- // string, so we can now release the local reference.
- DCHECK_NE(JavaType::TypeObject, target_inner_type.type);
- DCHECK_NE(JavaType::TypeArray, target_inner_type.type);
- ReleaseJavaValueIfRequired(env, &element, target_inner_type);
- WebBindings::releaseVariantValue(&value_variant);
- }
-
- return result;
-}
-
-jvalue CoerceJavaScriptObjectToJavaValue(const NPVariant& variant,
- const JavaType& target_type,
- bool coerce_to_string) {
- // This covers both JavaScript objects (including arrays) and Java objects.
- // See http://jdk6.java.net/plugin2/liveconnect/#JS_OTHER_OBJECTS,
- // http://jdk6.java.net/plugin2/liveconnect/#JS_ARRAY_VALUES and
- // http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_OBJECTS
- DCHECK_EQ(NPVariantType_Object, variant.type);
-
- NPObject* object = NPVARIANT_TO_OBJECT(variant);
- bool is_java_object = &JavaNPObject::kNPClass == object->_class;
-
- jvalue result;
- switch (target_type.type) {
- case JavaType::TypeObject:
- if (is_java_object) {
- // LIVECONNECT_COMPLIANCE: Existing behavior is to pass all Java
- // objects. Spec requires passing only Java objects which are
- // assignment-compatibile.
- result.l = AttachCurrentThread()->NewLocalRef(
- JavaBoundObject::GetJavaObject(object).obj());
- } else {
- // LIVECONNECT_COMPLIANCE: Existing behavior is to pass null. Spec
- // requires converting if the target type is
- // netscape.javascript.JSObject, otherwise raising a JavaScript
- // exception.
- result.l = NULL;
- }
- break;
- case JavaType::TypeString:
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to
- // "undefined". Spec requires calling toString() on the Java object.
- result.l = coerce_to_string ?
- ConvertUTF8ToJavaString(AttachCurrentThread(), "undefined").
- Release() :
- NULL;
- break;
- case JavaType::TypeByte:
- case JavaType::TypeShort:
- case JavaType::TypeInt:
- case JavaType::TypeLong:
- case JavaType::TypeFloat:
- case JavaType::TypeDouble:
- case JavaType::TypeChar: {
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to 0. Spec
- // requires raising a JavaScript exception.
- jvalue null_value = {0};
- result = null_value;
- break;
- }
- case JavaType::TypeBoolean:
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to false. Spec
- // requires raising a JavaScript exception.
- result.z = JNI_FALSE;
- break;
- case JavaType::TypeArray:
- if (is_java_object) {
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to NULL. Spec
- // requires raising a JavaScript exception.
- result.l = NULL;
- } else {
- result.l = CoerceJavaScriptObjectToArray(variant, target_type);
- }
- break;
- case JavaType::TypeVoid:
- // Conversion to void must never happen.
- NOTREACHED();
- break;
- }
- return result;
-}
-
-jvalue CoerceJavaScriptNullOrUndefinedToJavaValue(const NPVariant& variant,
- const JavaType& target_type,
- bool coerce_to_string) {
- // See http://jdk6.java.net/plugin2/liveconnect/#JS_NULL.
- DCHECK(variant.type == NPVariantType_Null ||
- variant.type == NPVariantType_Void);
- jvalue result;
- switch (target_type.type) {
- case JavaType::TypeObject:
- result.l = NULL;
- break;
- case JavaType::TypeString:
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert undefined to
- // "undefined". Spec requires converting undefined to NULL.
- result.l = (coerce_to_string && variant.type == NPVariantType_Void) ?
- ConvertUTF8ToJavaString(AttachCurrentThread(), "undefined").
- Release() :
- NULL;
- break;
- case JavaType::TypeByte:
- case JavaType::TypeChar:
- case JavaType::TypeShort:
- case JavaType::TypeInt:
- case JavaType::TypeLong:
- case JavaType::TypeFloat:
- case JavaType::TypeDouble: {
- jvalue null_value = {0};
- result = null_value;
- break;
- }
- case JavaType::TypeBoolean:
- result.z = JNI_FALSE;
- break;
- case JavaType::TypeArray:
- // LIVECONNECT_COMPLIANCE: Existing behavior is to convert to NULL. Spec
- // requires raising a JavaScript exception.
- result.l = NULL;
- break;
- case JavaType::TypeVoid:
- // Conversion to void must never happen.
- NOTREACHED();
- break;
- }
- return result;
-}
-
-// coerce_to_string means that we should try to coerce all JavaScript values to
-// strings when required, rather than simply converting to NULL. This is used
-// to maintain current behaviour, which differs slightly depending upon whether
-// or not the coercion in question is for an array element.
-//
-// Note that the jvalue returned by this method may contain a new local
-// reference to an object (string, object or array). This must be released by
-// the caller.
-jvalue CoerceJavaScriptValueToJavaValue(const NPVariant& variant,
- const JavaType& target_type,
- bool coerce_to_string) {
- // Note that in all these conversions, the relevant field of the jvalue must
- // always be explicitly set, as jvalue does not initialize its fields.
-
- switch (variant.type) {
- case NPVariantType_Int32:
- case NPVariantType_Double:
- return CoerceJavaScriptNumberToJavaValue(variant, target_type,
- coerce_to_string);
- case NPVariantType_Bool:
- return CoerceJavaScriptBooleanToJavaValue(variant, target_type,
- coerce_to_string);
- case NPVariantType_String:
- return CoerceJavaScriptStringToJavaValue(variant, target_type);
- case NPVariantType_Object:
- return CoerceJavaScriptObjectToJavaValue(variant, target_type,
- coerce_to_string);
- case NPVariantType_Null:
- case NPVariantType_Void:
- return CoerceJavaScriptNullOrUndefinedToJavaValue(variant, target_type,
- coerce_to_string);
- }
- NOTREACHED();
- return jvalue();
-}
-
-} // namespace
-
-NPObject* JavaBoundObject::Create(
- const JavaRef<jobject>& object,
- const JavaRef<jclass>& safe_annotation_clazz,
- const base::WeakPtr<JavaBridgeDispatcherHostManager>& manager,
- bool can_enumerate_methods) {
- // The first argument (a plugin's instance handle) is passed through to the
- // allocate function directly, and we don't use it, so it's ok to be 0.
- // The object is created with a ref count of one.
- NPObject* np_object = WebBindings::createObject(0, const_cast<NPClass*>(
- &JavaNPObject::kNPClass));
- // The NPObject takes ownership of the JavaBoundObject.
- reinterpret_cast<JavaNPObject*>(np_object)->bound_object =
- new JavaBoundObject(
- object, safe_annotation_clazz, manager, can_enumerate_methods);
- return np_object;
-}
-
-JavaBoundObject::JavaBoundObject(
- const JavaRef<jobject>& object,
- const JavaRef<jclass>& safe_annotation_clazz,
- const base::WeakPtr<JavaBridgeDispatcherHostManager>& manager,
- bool can_enumerate_methods)
- : java_object_(AttachCurrentThread(), object.obj()),
- manager_(manager),
- are_methods_set_up_(false),
- object_get_class_method_id_(NULL),
- can_enumerate_methods_(can_enumerate_methods),
- safe_annotation_clazz_(safe_annotation_clazz) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&JavaBridgeDispatcherHostManager::JavaBoundObjectCreated,
- manager_,
- base::android::ScopedJavaGlobalRef<jobject>(object)));
- // Other than informing the JavaBridgeDispatcherHostManager that a java bound
- // object has been created (above), we don't do anything else with our Java
- // object when first created. We do it all lazily when a method is first
- // invoked.
-}
-
-JavaBoundObject::~JavaBoundObject() {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&JavaBridgeDispatcherHostManager::JavaBoundObjectDestroyed,
- manager_,
- base::android::ScopedJavaGlobalRef<jobject>(
- java_object_.get(AttachCurrentThread()))));
-}
-
-ScopedJavaLocalRef<jobject> JavaBoundObject::GetJavaObject(NPObject* object) {
- DCHECK_EQ(&JavaNPObject::kNPClass, object->_class);
- JavaBoundObject* jbo = reinterpret_cast<JavaNPObject*>(object)->bound_object;
- return jbo->java_object_.get(AttachCurrentThread());
-}
-
-std::vector<std::string> JavaBoundObject::GetMethodNames() const {
- EnsureMethodsAreSetUp();
- std::vector<std::string> result;
- for (JavaMethodMap::const_iterator it = methods_.begin();
- it != methods_.end();
- it = methods_.upper_bound(it->first)) {
- result.push_back(it->first);
- }
- return result;
-}
-
-bool JavaBoundObject::HasMethod(const std::string& name) const {
- EnsureMethodsAreSetUp();
- return methods_.find(name) != methods_.end();
-}
-
-bool JavaBoundObject::Invoke(const std::string& name, const NPVariant* args,
- size_t arg_count, NPVariant* result) {
- EnsureMethodsAreSetUp();
-
- // Get all methods with the correct name.
- std::pair<JavaMethodMap::const_iterator, JavaMethodMap::const_iterator>
- iters = methods_.equal_range(name);
- if (iters.first == iters.second) {
- return false;
- }
-
- // Take the first method with the correct number of arguments.
- JavaMethod* method = NULL;
- for (JavaMethodMap::const_iterator iter = iters.first; iter != iters.second;
- ++iter) {
- if (iter->second->num_parameters() == arg_count) {
- method = iter->second.get();
- break;
- }
- }
- if (!method) {
- return false;
- }
-
- // Block access to java.lang.Object.getClass.
- // As it is declared to be final, it is sufficient to compare methodIDs.
- if (method->id() == object_get_class_method_id_) {
- BrowserThread::PostTask(
- BrowserThread::UI, FROM_HERE,
- base::Bind(&JavaBoundObject::ThrowSecurityException,
- kAccessToObjectGetClassIsBlocked));
- return false;
- }
-
- // Coerce
- std::vector<jvalue> parameters(arg_count);
- for (size_t i = 0; i < arg_count; ++i) {
- parameters[i] = CoerceJavaScriptValueToJavaValue(args[i],
- method->parameter_type(i),
- true);
- }
-
- JNIEnv* env = AttachCurrentThread();
-
- ScopedJavaLocalRef<jobject> obj;
- ScopedJavaLocalRef<jclass> cls;
- bool ok = false;
- if (method->is_static()) {
- cls = GetLocalClassRef(env);
- } else {
- obj = java_object_.get(env);
- }
- if (!obj.is_null() || !cls.is_null()) {
- // Call
- ok = CallJNIMethod(obj.obj(), cls.obj(), method->return_type(),
- method->id(), &parameters[0], result,
- safe_annotation_clazz_,
- manager_,
- can_enumerate_methods_);
- }
-
- // Now that we're done with the jvalue, release any local references created
- // by CoerceJavaScriptValueToJavaValue().
- for (size_t i = 0; i < arg_count; ++i) {
- ReleaseJavaValueIfRequired(env, &parameters[i], method->parameter_type(i));
- }
-
- return ok;
-}
-
-ScopedJavaLocalRef<jclass> JavaBoundObject::GetLocalClassRef(
- JNIEnv* env) const {
- if (!object_get_class_method_id_) {
- object_get_class_method_id_ = GetMethodIDFromClassName(
- env, kJavaLangObject, kGetClass, kReturningJavaLangClass);
- }
-
- ScopedJavaLocalRef<jobject> obj = java_object_.get(env);
- if (!obj.is_null()) {
- return ScopedJavaLocalRef<jclass>(env, static_cast<jclass>(
- env->CallObjectMethod(obj.obj(), object_get_class_method_id_)));
- } else {
- return ScopedJavaLocalRef<jclass>();
- }
-}
-
-void JavaBoundObject::EnsureMethodsAreSetUp() const {
- if (are_methods_set_up_)
- return;
- are_methods_set_up_ = true;
-
- JNIEnv* env = AttachCurrentThread();
-
- ScopedJavaLocalRef<jclass> clazz = GetLocalClassRef(env);
- if (clazz.is_null()) {
- return;
- }
-
- ScopedJavaLocalRef<jobjectArray> methods(env, static_cast<jobjectArray>(
- env->CallObjectMethod(clazz.obj(), GetMethodIDFromClassName(
- env,
- kJavaLangClass,
- kGetMethods,
- kReturningJavaLangReflectMethodArray))));
-
- size_t num_methods = env->GetArrayLength(methods.obj());
- // Java objects always have public methods.
- DCHECK(num_methods);
-
- for (size_t i = 0; i < num_methods; ++i) {
- ScopedJavaLocalRef<jobject> java_method(
- env,
- env->GetObjectArrayElement(methods.obj(), i));
-
- if (!safe_annotation_clazz_.is_null()) {
- jboolean safe = env->CallBooleanMethod(java_method.obj(),
- GetMethodIDFromClassName(
- env,
- kJavaLangReflectMethod,
- kIsAnnotationPresent,
- kTakesJavaLangClassReturningBoolean),
- safe_annotation_clazz_.obj());
-
- if (!safe)
- continue;
- }
-
- JavaMethod* method = new JavaMethod(java_method);
- methods_.insert(std::make_pair(method->name(), method));
- }
-}
-
-// static
-void JavaBoundObject::ThrowSecurityException(const char* message) {
- DCHECK_CURRENTLY_ON(BrowserThread::UI);
- JNIEnv* env = AttachCurrentThread();
- base::android::ScopedJavaLocalRef<jclass> clazz(
- env, env->FindClass(kJavaLangSecurityExceptionClass));
- env->ThrowNew(clazz.obj(), message);
-}
-
-} // namespace content
« no previous file with comments | « content/browser/renderer_host/java/java_bound_object.h ('k') | content/browser/renderer_host/java/java_bridge_channel_host.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698