| Index: content/browser/renderer_host/java/java_method.cc
|
| diff --git a/content/browser/renderer_host/java/java_method.cc b/content/browser/renderer_host/java/java_method.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..d65bd0c7276233a8c8841b5a4f2b867cb2736cad
|
| --- /dev/null
|
| +++ b/content/browser/renderer_host/java/java_method.cc
|
| @@ -0,0 +1,258 @@
|
| +// Copyright (c) 2011 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_method.h"
|
| +
|
| +#include "base/android/jni_android.h"
|
| +#include "base/android/jni_string.h"
|
| +#include "base/memory/singleton.h"
|
| +#include "base/string_util.h" // For ReplaceSubstringsAfterOffset
|
| +
|
| +using base::android::AttachCurrentThread;
|
| +using base::android::ConvertJavaStringToUTF8;
|
| +using base::android::MethodID;
|
| +using base::android::ScopedJavaLocalRef;
|
| +
|
| +namespace {
|
| +
|
| +// Java's reflection API represents types as a string using an extended 'binary
|
| +// name'. This converts to an enum which we store in place of the binary name
|
| +// for simplicity.
|
| +JavaType::Type BinaryNameToType(const std::string& binary_name) {
|
| + if (binary_name == "boolean") {
|
| + return JavaType::TypeBoolean;
|
| + } else if (binary_name == "byte") {
|
| + return JavaType::TypeByte;
|
| + } else if (binary_name == "char") {
|
| + return JavaType::TypeChar;
|
| + } else if (binary_name == "short") {
|
| + return JavaType::TypeShort;
|
| + } else if (binary_name == "int") {
|
| + return JavaType::TypeInt;
|
| + } else if (binary_name == "long") {
|
| + return JavaType::TypeLong;
|
| + } else if (binary_name == "float") {
|
| + return JavaType::TypeFloat;
|
| + } else if (binary_name == "double") {
|
| + return JavaType::TypeDouble;
|
| + } else if (binary_name == "void") {
|
| + return JavaType::TypeVoid;
|
| + } else if (binary_name[0] == '[') {
|
| + return JavaType::TypeArray;
|
| + } else if (binary_name == "java.lang.String") {
|
| + return JavaType::TypeString;
|
| + }
|
| + return JavaType::TypeObject;
|
| +}
|
| +
|
| +std::string BinaryNameToJNIName(const std::string& binary_name,
|
| + JavaType::Type* type) {
|
| + DCHECK(type);
|
| + *type = BinaryNameToType(binary_name);
|
| + switch (*type) {
|
| + case JavaType::TypeBoolean:
|
| + return "Z";
|
| + case JavaType::TypeByte:
|
| + return "B";
|
| + case JavaType::TypeChar:
|
| + return "C";
|
| + case JavaType::TypeShort:
|
| + return "S";
|
| + case JavaType::TypeInt:
|
| + return "I";
|
| + case JavaType::TypeLong:
|
| + return "J";
|
| + case JavaType::TypeFloat:
|
| + return "F";
|
| + case JavaType::TypeDouble:
|
| + return "D";
|
| + case JavaType::TypeVoid:
|
| + return "V";
|
| + case JavaType::TypeArray:
|
| + return "[";
|
| + default:
|
| + DCHECK (*type == JavaType::TypeString || *type == JavaType::TypeObject);
|
| + std::string jni_name = "L" + binary_name + ";";
|
| + ReplaceSubstringsAfterOffset(&jni_name, 0, ".", "/");
|
| + return jni_name;
|
| + }
|
| +}
|
| +
|
| +class MethodGetParameterTypesID : public MethodID {
|
| + public:
|
| + static MethodGetParameterTypesID* GetInstance() {
|
| + return Singleton<MethodGetParameterTypesID>::get();
|
| + }
|
| + private:
|
| + friend struct DefaultSingletonTraits<MethodGetParameterTypesID>;
|
| + MethodGetParameterTypesID()
|
| + : MethodID(AttachCurrentThread(), "java/lang/reflect/Method",
|
| + "getParameterTypes", "()[Ljava/lang/Class;") {
|
| + }
|
| + DISALLOW_COPY_AND_ASSIGN(MethodGetParameterTypesID);
|
| +};
|
| +
|
| +class MethodGetNameID : public MethodID {
|
| + public:
|
| + static MethodGetNameID* GetInstance() {
|
| + return Singleton<MethodGetNameID>::get();
|
| + }
|
| + private:
|
| + friend struct DefaultSingletonTraits<MethodGetNameID>;
|
| + MethodGetNameID()
|
| + : MethodID(AttachCurrentThread(), "java/lang/reflect/Method",
|
| + "getName", "()Ljava/lang/String;") {
|
| + }
|
| + DISALLOW_COPY_AND_ASSIGN(MethodGetNameID);
|
| +};
|
| +
|
| +class MethodGetReturnTypeID : public MethodID {
|
| + public:
|
| + static MethodGetReturnTypeID* GetInstance() {
|
| + return Singleton<MethodGetReturnTypeID>::get();
|
| + }
|
| + private:
|
| + friend struct DefaultSingletonTraits<MethodGetReturnTypeID>;
|
| + MethodGetReturnTypeID()
|
| + : MethodID(AttachCurrentThread(), "java/lang/reflect/Method",
|
| + "getReturnType", "()Ljava/lang/Class;") {
|
| + }
|
| + DISALLOW_COPY_AND_ASSIGN(MethodGetReturnTypeID);
|
| +};
|
| +
|
| +class MethodGetDeclaringClassID : public MethodID {
|
| + public:
|
| + static MethodGetDeclaringClassID* GetInstance() {
|
| + return Singleton<MethodGetDeclaringClassID>::get();
|
| + }
|
| + private:
|
| + friend struct DefaultSingletonTraits<MethodGetDeclaringClassID>;
|
| + MethodGetDeclaringClassID()
|
| + : MethodID(AttachCurrentThread(), "java/lang/reflect/Method",
|
| + "getDeclaringClass", "()Ljava/lang/Class;") {
|
| + }
|
| + DISALLOW_COPY_AND_ASSIGN(MethodGetDeclaringClassID);
|
| +};
|
| +
|
| +class ClassGetNameID : public MethodID {
|
| + public:
|
| + static ClassGetNameID* GetInstance() {
|
| + return Singleton<ClassGetNameID>::get();
|
| + }
|
| + private:
|
| + friend struct DefaultSingletonTraits<ClassGetNameID>;
|
| + ClassGetNameID()
|
| + : MethodID(AttachCurrentThread(), "java/lang/Class", "getName",
|
| + "()Ljava/lang/String;") {
|
| + }
|
| + DISALLOW_COPY_AND_ASSIGN(ClassGetNameID);
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +JavaMethod::JavaMethod(const base::android::JavaRef<jobject>& method)
|
| + : java_method_(method),
|
| + have_calculated_num_parameters_(false),
|
| + id_(NULL) {
|
| + JNIEnv* env = java_method_.env();
|
| + // On construction, we do nothing except get the name. Everything else is
|
| + // done lazily.
|
| + ScopedJavaLocalRef<jstring> name(env, static_cast<jstring>(
|
| + env->CallObjectMethod(java_method_.obj(),
|
| + MethodGetNameID::GetInstance()->id())));
|
| + name_ = ConvertJavaStringToUTF8(env, name.obj());
|
| +}
|
| +
|
| +JavaMethod::~JavaMethod() {
|
| +}
|
| +
|
| +size_t JavaMethod::num_parameters() const {
|
| + EnsureNumParametersIsSetUp();
|
| + return num_parameters_;
|
| +}
|
| +
|
| +JavaType::Type JavaMethod::parameter_type(size_t index) const {
|
| + EnsureTypesAndIDAreSetUp();
|
| + return parameter_types_[index];
|
| +}
|
| +
|
| +JavaType::Type JavaMethod::return_type() const {
|
| + EnsureTypesAndIDAreSetUp();
|
| + return return_type_;
|
| +}
|
| +
|
| +jmethodID JavaMethod::id() const {
|
| + EnsureTypesAndIDAreSetUp();
|
| + return id_;
|
| +}
|
| +
|
| +void JavaMethod::EnsureNumParametersIsSetUp() const {
|
| + if (have_calculated_num_parameters_) {
|
| + return;
|
| + }
|
| + have_calculated_num_parameters_ = true;
|
| +
|
| + // The number of parameters will be used frequently when determining
|
| + // whether to call this method. We don't get the ID etc until actually
|
| + // required.
|
| + JNIEnv* env = java_method_.env();
|
| + ScopedJavaLocalRef<jarray> parameters(env, static_cast<jarray>(
|
| + env->CallObjectMethod(java_method_.obj(),
|
| + MethodGetParameterTypesID::GetInstance()->id())));
|
| + num_parameters_ = env->GetArrayLength(parameters.obj());
|
| +}
|
| +
|
| +void JavaMethod::EnsureTypesAndIDAreSetUp() const {
|
| + if (id_) {
|
| + return;
|
| + }
|
| +
|
| + // Get the parameters
|
| + JNIEnv* env = java_method_.env();
|
| + ScopedJavaLocalRef<jobjectArray> parameters(env, static_cast<jobjectArray>(
|
| + env->CallObjectMethod(java_method_.obj(),
|
| + MethodGetParameterTypesID::GetInstance()->id())));
|
| + // Usually, this will already have been called.
|
| + EnsureNumParametersIsSetUp();
|
| + DCHECK_EQ(num_parameters_,
|
| + static_cast<size_t>(env->GetArrayLength(parameters.obj())));
|
| +
|
| + // Java gives us the argument type using an extended version of the 'binary
|
| + // name'. See
|
| + // http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Class.html#getName().
|
| + // If we build the signature now, there's no need to store the binary name
|
| + // of the arguments. We just store the simple type.
|
| + std::string signature("(");
|
| +
|
| + // Form the signature and record the parameter types.
|
| + parameter_types_.resize(num_parameters_);
|
| + for (size_t i = 0; i < num_parameters_; ++i) {
|
| + ScopedJavaLocalRef<jobject> parameter(env, env->GetObjectArrayElement(
|
| + parameters.obj(), i));
|
| + ScopedJavaLocalRef<jstring> name(env, static_cast<jstring>(
|
| + env->CallObjectMethod(parameter.obj(),
|
| + ClassGetNameID::GetInstance()->id())));
|
| + std::string name_utf8 = ConvertJavaStringToUTF8(env, name.obj());
|
| + signature += BinaryNameToJNIName(name_utf8, ¶meter_types_[i]);
|
| + }
|
| + signature += ")";
|
| +
|
| + // Get the return type
|
| + ScopedJavaLocalRef<jclass> clazz(env, static_cast<jclass>(
|
| + env->CallObjectMethod(java_method_.obj(),
|
| + MethodGetReturnTypeID::GetInstance()->id())));
|
| + ScopedJavaLocalRef<jstring> name(env, static_cast<jstring>(
|
| + env->CallObjectMethod(clazz.obj(), ClassGetNameID::GetInstance()->id())));
|
| + signature += BinaryNameToJNIName(ConvertJavaStringToUTF8(env, name.obj()),
|
| + &return_type_);
|
| +
|
| + // Get the ID for this method.
|
| + ScopedJavaLocalRef<jclass> declaring_class(env, static_cast<jclass>(
|
| + env->CallObjectMethod(java_method_.obj(),
|
| + MethodGetDeclaringClassID::GetInstance()->id())));
|
| + id_ = base::android::GetMethodID(env, declaring_class.obj(), name_.c_str(),
|
| + signature.c_str());
|
| +
|
| + java_method_.Reset();
|
| +}
|
|
|