summaryrefslogtreecommitdiffstats
path: root/chromium/content/browser/renderer_host/java/gin_java_bound_object.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/content/browser/renderer_host/java/gin_java_bound_object.cc')
-rw-r--r--chromium/content/browser/renderer_host/java/gin_java_bound_object.cc192
1 files changed, 192 insertions, 0 deletions
diff --git a/chromium/content/browser/renderer_host/java/gin_java_bound_object.cc b/chromium/content/browser/renderer_host/java/gin_java_bound_object.cc
new file mode 100644
index 00000000000..70abba842c9
--- /dev/null
+++ b/chromium/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