| Index: content/browser/renderer_host/java/gin_java_bound_object.cc
|
| diff --git a/content/browser/renderer_host/java/gin_java_bound_object.cc b/content/browser/renderer_host/java/gin_java_bound_object.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..70abba842c90bbc2497cc50cec74512abc0a56de
|
| --- /dev/null
|
| +++ b/content/browser/renderer_host/java/gin_java_bound_object.cc
|
| @@ -0,0 +1,192 @@
|
| +// Copyright 2014 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/gin_java_bound_object.h"
|
| +
|
| +#include "base/android/jni_android.h"
|
| +#include "base/android/jni_string.h"
|
| +#include "base/android/scoped_java_ref.h"
|
| +#include "base/strings/utf_string_conversions.h"
|
| +#include "content/browser/renderer_host/java/jni_helper.h"
|
| +
|
| +using base::android::AttachCurrentThread;
|
| +using base::android::ScopedJavaLocalRef;
|
| +
|
| +namespace content {
|
| +
|
| +namespace {
|
| +
|
| +const char kJavaLangClass[] = "java/lang/Class";
|
| +const char kJavaLangObject[] = "java/lang/Object";
|
| +const char kJavaLangReflectMethod[] = "java/lang/reflect/Method";
|
| +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";
|
| +
|
| +} // namespace
|
| +
|
| +
|
| +// static
|
| +GinJavaBoundObject* GinJavaBoundObject::CreateNamed(
|
| + const JavaObjectWeakGlobalRef& ref,
|
| + const base::android::JavaRef<jclass>& safe_annotation_clazz) {
|
| + return new GinJavaBoundObject(ref, safe_annotation_clazz);
|
| +}
|
| +
|
| +// static
|
| +GinJavaBoundObject* GinJavaBoundObject::CreateTransient(
|
| + const JavaObjectWeakGlobalRef& ref,
|
| + const base::android::JavaRef<jclass>& safe_annotation_clazz,
|
| + RenderFrameHost* holder) {
|
| + std::set<RenderFrameHost*> holders;
|
| + holders.insert(holder);
|
| + return new GinJavaBoundObject(ref, safe_annotation_clazz, holders);
|
| +}
|
| +
|
| +GinJavaBoundObject::GinJavaBoundObject(
|
| + const JavaObjectWeakGlobalRef& ref,
|
| + const base::android::JavaRef<jclass>& safe_annotation_clazz)
|
| + : ref_(ref),
|
| + names_count_(1),
|
| + object_get_class_method_id_(NULL),
|
| + are_methods_set_up_(false),
|
| + safe_annotation_clazz_(safe_annotation_clazz) {
|
| +}
|
| +
|
| +GinJavaBoundObject::GinJavaBoundObject(
|
| + const JavaObjectWeakGlobalRef& ref,
|
| + const base::android::JavaRef<jclass>& safe_annotation_clazz,
|
| + const std::set<RenderFrameHost*> holders)
|
| + : ref_(ref),
|
| + names_count_(0),
|
| + holders_(holders),
|
| + object_get_class_method_id_(NULL),
|
| + are_methods_set_up_(false),
|
| + safe_annotation_clazz_(safe_annotation_clazz) {
|
| +}
|
| +
|
| +GinJavaBoundObject::~GinJavaBoundObject() {
|
| +}
|
| +
|
| +std::set<std::string> GinJavaBoundObject::GetMethodNames() {
|
| + EnsureMethodsAreSetUp();
|
| + std::set<std::string> result;
|
| + for (JavaMethodMap::const_iterator it = methods_.begin();
|
| + it != methods_.end();
|
| + ++it) {
|
| + result.insert(it->first);
|
| + }
|
| + return result;
|
| +}
|
| +
|
| +bool GinJavaBoundObject::HasMethod(const std::string& method_name) {
|
| + EnsureMethodsAreSetUp();
|
| + return methods_.find(method_name) != methods_.end();
|
| +}
|
| +
|
| +const JavaMethod* GinJavaBoundObject::FindMethod(
|
| + const std::string& method_name,
|
| + size_t num_parameters) {
|
| + EnsureMethodsAreSetUp();
|
| +
|
| + // Get all methods with the correct name.
|
| + std::pair<JavaMethodMap::const_iterator, JavaMethodMap::const_iterator>
|
| + iters = methods_.equal_range(method_name);
|
| + if (iters.first == iters.second) {
|
| + return NULL;
|
| + }
|
| +
|
| + // LIVECONNECT_COMPLIANCE: We just take the first method with the correct
|
| + // number of arguments, while the spec proposes using cost-based algorithm:
|
| + // https://jdk6.java.net/plugin2/liveconnect/#OVERLOADED_METHODS
|
| + for (JavaMethodMap::const_iterator iter = iters.first; iter != iters.second;
|
| + ++iter) {
|
| + if (iter->second->num_parameters() == num_parameters) {
|
| + return iter->second.get();
|
| + }
|
| + }
|
| +
|
| + return NULL;
|
| +}
|
| +
|
| +bool GinJavaBoundObject::IsObjectGetClassMethod(const JavaMethod* method) {
|
| + EnsureMethodsAreSetUp();
|
| + // As java.lang.Object.getClass is declared to be final, it is sufficient to
|
| + // compare methodIDs.
|
| + return method->id() == object_get_class_method_id_;
|
| +}
|
| +
|
| +const base::android::JavaRef<jclass>&
|
| +GinJavaBoundObject::GetSafeAnnotationClass() {
|
| + return safe_annotation_clazz_;
|
| +}
|
| +
|
| +base::android::ScopedJavaLocalRef<jclass> GinJavaBoundObject::GetLocalClassRef(
|
| + JNIEnv* env) {
|
| + if (!object_get_class_method_id_) {
|
| + object_get_class_method_id_ = GetMethodIDFromClassName(
|
| + env, kJavaLangObject, kGetClass, kReturningJavaLangClass);
|
| + }
|
| + ScopedJavaLocalRef<jobject> obj = GetLocalRef(env);
|
| + if (obj.obj()) {
|
| + return base::android::ScopedJavaLocalRef<jclass>(
|
| + env,
|
| + static_cast<jclass>(
|
| + env->CallObjectMethod(obj.obj(), object_get_class_method_id_)));
|
| + } else {
|
| + return base::android::ScopedJavaLocalRef<jclass>();
|
| + }
|
| +}
|
| +
|
| +void GinJavaBoundObject::EnsureMethodsAreSetUp() {
|
| + 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));
|
| + }
|
| +}
|
| +
|
| +} // namespace content
|
|
|