1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/android/java/gin_java_bound_object.h"
7 #include "base/android/jni_android.h"
8 #include "base/android/jni_string.h"
9 #include "base/android/scoped_java_ref.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "content/browser/android/java/jni_helper.h"
13 using base::android::AttachCurrentThread
;
14 using base::android::ScopedJavaLocalRef
;
20 const char kJavaLangClass
[] = "java/lang/Class";
21 const char kJavaLangObject
[] = "java/lang/Object";
22 const char kJavaLangReflectMethod
[] = "java/lang/reflect/Method";
23 const char kGetClass
[] = "getClass";
24 const char kGetMethods
[] = "getMethods";
25 const char kIsAnnotationPresent
[] = "isAnnotationPresent";
26 const char kReturningJavaLangClass
[] = "()Ljava/lang/Class;";
27 const char kReturningJavaLangReflectMethodArray
[] =
28 "()[Ljava/lang/reflect/Method;";
29 const char kTakesJavaLangClassReturningBoolean
[] = "(Ljava/lang/Class;)Z";
35 GinJavaBoundObject
* GinJavaBoundObject::CreateNamed(
36 const JavaObjectWeakGlobalRef
& ref
,
37 const base::android::JavaRef
<jclass
>& safe_annotation_clazz
) {
38 return new GinJavaBoundObject(ref
, safe_annotation_clazz
);
42 GinJavaBoundObject
* GinJavaBoundObject::CreateTransient(
43 const JavaObjectWeakGlobalRef
& ref
,
44 const base::android::JavaRef
<jclass
>& safe_annotation_clazz
,
46 std::set
<int32
> holders
;
47 holders
.insert(holder
);
48 return new GinJavaBoundObject(ref
, safe_annotation_clazz
, holders
);
51 GinJavaBoundObject::GinJavaBoundObject(
52 const JavaObjectWeakGlobalRef
& ref
,
53 const base::android::JavaRef
<jclass
>& safe_annotation_clazz
)
56 object_get_class_method_id_(NULL
),
57 are_methods_set_up_(false),
58 safe_annotation_clazz_(safe_annotation_clazz
) {
61 GinJavaBoundObject::GinJavaBoundObject(
62 const JavaObjectWeakGlobalRef
& ref
,
63 const base::android::JavaRef
<jclass
>& safe_annotation_clazz
,
64 const std::set
<int32
>& holders
)
68 object_get_class_method_id_(NULL
),
69 are_methods_set_up_(false),
70 safe_annotation_clazz_(safe_annotation_clazz
) {
73 GinJavaBoundObject::~GinJavaBoundObject() {
76 std::set
<std::string
> GinJavaBoundObject::GetMethodNames() {
77 EnsureMethodsAreSetUp();
78 std::set
<std::string
> result
;
79 for (JavaMethodMap::const_iterator it
= methods_
.begin();
82 result
.insert(it
->first
);
87 bool GinJavaBoundObject::HasMethod(const std::string
& method_name
) {
88 EnsureMethodsAreSetUp();
89 return methods_
.find(method_name
) != methods_
.end();
92 const JavaMethod
* GinJavaBoundObject::FindMethod(
93 const std::string
& method_name
,
94 size_t num_parameters
) {
95 EnsureMethodsAreSetUp();
97 // Get all methods with the correct name.
98 std::pair
<JavaMethodMap::const_iterator
, JavaMethodMap::const_iterator
>
99 iters
= methods_
.equal_range(method_name
);
100 if (iters
.first
== iters
.second
) {
104 // LIVECONNECT_COMPLIANCE: We just take the first method with the correct
105 // number of arguments, while the spec proposes using cost-based algorithm:
106 // https://jdk6.java.net/plugin2/liveconnect/#OVERLOADED_METHODS
107 for (JavaMethodMap::const_iterator iter
= iters
.first
; iter
!= iters
.second
;
109 if (iter
->second
->num_parameters() == num_parameters
) {
110 return iter
->second
.get();
117 bool GinJavaBoundObject::IsObjectGetClassMethod(const JavaMethod
* method
) {
118 EnsureMethodsAreSetUp();
119 // As java.lang.Object.getClass is declared to be final, it is sufficient to
120 // compare methodIDs.
121 return method
->id() == object_get_class_method_id_
;
124 const base::android::JavaRef
<jclass
>&
125 GinJavaBoundObject::GetSafeAnnotationClass() {
126 return safe_annotation_clazz_
;
129 base::android::ScopedJavaLocalRef
<jclass
> GinJavaBoundObject::GetLocalClassRef(
131 if (!object_get_class_method_id_
) {
132 object_get_class_method_id_
= GetMethodIDFromClassName(
133 env
, kJavaLangObject
, kGetClass
, kReturningJavaLangClass
);
135 ScopedJavaLocalRef
<jobject
> obj
= GetLocalRef(env
);
137 return base::android::ScopedJavaLocalRef
<jclass
>(
140 env
->CallObjectMethod(obj
.obj(), object_get_class_method_id_
)));
142 return base::android::ScopedJavaLocalRef
<jclass
>();
146 void GinJavaBoundObject::EnsureMethodsAreSetUp() {
147 if (are_methods_set_up_
)
149 are_methods_set_up_
= true;
151 JNIEnv
* env
= AttachCurrentThread();
153 ScopedJavaLocalRef
<jclass
> clazz
= GetLocalClassRef(env
);
154 if (clazz
.is_null()) {
158 ScopedJavaLocalRef
<jobjectArray
> methods(env
, static_cast<jobjectArray
>(
159 env
->CallObjectMethod(clazz
.obj(), GetMethodIDFromClassName(
163 kReturningJavaLangReflectMethodArray
))));
165 size_t num_methods
= env
->GetArrayLength(methods
.obj());
166 // Java objects always have public methods.
169 for (size_t i
= 0; i
< num_methods
; ++i
) {
170 ScopedJavaLocalRef
<jobject
> java_method(
172 env
->GetObjectArrayElement(methods
.obj(), i
));
174 if (!safe_annotation_clazz_
.is_null()) {
175 jboolean safe
= env
->CallBooleanMethod(java_method
.obj(),
176 GetMethodIDFromClassName(
178 kJavaLangReflectMethod
,
179 kIsAnnotationPresent
,
180 kTakesJavaLangClassReturningBoolean
),
181 safe_annotation_clazz_
.obj());
187 JavaMethod
* method
= new JavaMethod(java_method
);
188 methods_
.insert(std::make_pair(method
->name(), make_linked_ptr(method
)));
192 } // namespace content