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_method_invocation_helper.h"
7 #include "base/android/jni_android.h"
8 #include "content/browser/android/java/jni_helper.h"
9 #include "content/common/android/gin_java_bridge_value.h"
10 #include "testing/gtest/include/gtest/gtest.h"
16 class NullObjectDelegate
17 : public GinJavaMethodInvocationHelper::ObjectDelegate
{
19 NullObjectDelegate() {}
21 ~NullObjectDelegate() override
{}
23 base::android::ScopedJavaLocalRef
<jobject
> GetLocalRef(JNIEnv
* env
) override
{
24 return base::android::ScopedJavaLocalRef
<jobject
>();
27 base::android::ScopedJavaLocalRef
<jclass
> GetLocalClassRef(
28 JNIEnv
* env
) override
{
29 return base::android::ScopedJavaLocalRef
<jclass
>();
32 const JavaMethod
* FindMethod(const std::string
& method_name
,
33 size_t num_parameters
) override
{
37 bool IsObjectGetClassMethod(const JavaMethod
* method
) override
{
41 const base::android::JavaRef
<jclass
>& GetSafeAnnotationClass() override
{
42 return safe_annotation_class_
;
46 base::android::ScopedJavaLocalRef
<jclass
> safe_annotation_class_
;
48 DISALLOW_COPY_AND_ASSIGN(NullObjectDelegate
);
51 class NullDispatcherDelegate
52 : public GinJavaMethodInvocationHelper::DispatcherDelegate
{
54 NullDispatcherDelegate() {}
56 ~NullDispatcherDelegate() override
{}
58 JavaObjectWeakGlobalRef
GetObjectWeakRef(
59 GinJavaBoundObject::ObjectID object_id
) override
{
60 return JavaObjectWeakGlobalRef();
63 DISALLOW_COPY_AND_ASSIGN(NullDispatcherDelegate
);
68 class GinJavaMethodInvocationHelperTest
: public testing::Test
{
73 class CountingDispatcherDelegate
74 : public GinJavaMethodInvocationHelper::DispatcherDelegate
{
76 CountingDispatcherDelegate() {}
78 ~CountingDispatcherDelegate() override
{}
80 JavaObjectWeakGlobalRef
GetObjectWeakRef(
81 GinJavaBoundObject::ObjectID object_id
) override
{
82 counters_
[object_id
]++;
83 return JavaObjectWeakGlobalRef();
86 void AssertInvocationsCount(GinJavaBoundObject::ObjectID begin_object_id
,
87 GinJavaBoundObject::ObjectID end_object_id
) {
88 EXPECT_EQ(end_object_id
- begin_object_id
,
89 static_cast<int>(counters_
.size()));
90 for (GinJavaBoundObject::ObjectID i
= begin_object_id
;
91 i
< end_object_id
; ++i
) {
92 EXPECT_LT(0, counters_
[i
]) << "ObjectID: " << i
;
97 typedef std::map
<GinJavaBoundObject::ObjectID
, int> Counters
;
100 DISALLOW_COPY_AND_ASSIGN(CountingDispatcherDelegate
);
105 TEST_F(GinJavaMethodInvocationHelperTest
, RetrievalOfObjectsNoObjects
) {
106 base::ListValue no_objects
;
107 for (int i
= 0; i
< 10; ++i
) {
108 no_objects
.AppendInteger(i
);
111 scoped_refptr
<GinJavaMethodInvocationHelper
> helper
=
112 new GinJavaMethodInvocationHelper(
113 scoped_ptr
<GinJavaMethodInvocationHelper::ObjectDelegate
>(
114 new NullObjectDelegate()),
117 CountingDispatcherDelegate counter
;
118 helper
->Init(&counter
);
119 counter
.AssertInvocationsCount(0, 0);
122 TEST_F(GinJavaMethodInvocationHelperTest
, RetrievalOfObjectsHaveObjects
) {
123 base::ListValue objects
;
124 objects
.AppendInteger(100);
125 objects
.Append(GinJavaBridgeValue::CreateObjectIDValue(1).release());
126 base::ListValue
* sub_list
= new base::ListValue();
127 sub_list
->AppendInteger(200);
128 sub_list
->Append(GinJavaBridgeValue::CreateObjectIDValue(2).release());
129 objects
.Append(sub_list
);
130 base::DictionaryValue
* sub_dict
= new base::DictionaryValue();
131 sub_dict
->SetInteger("1", 300);
132 sub_dict
->Set("2", GinJavaBridgeValue::CreateObjectIDValue(3).release());
133 objects
.Append(sub_dict
);
134 base::ListValue
* sub_list_with_dict
= new base::ListValue();
135 base::DictionaryValue
* sub_sub_dict
= new base::DictionaryValue();
136 sub_sub_dict
->Set("1", GinJavaBridgeValue::CreateObjectIDValue(4).release());
137 sub_list_with_dict
->Append(sub_sub_dict
);
138 objects
.Append(sub_list_with_dict
);
139 base::DictionaryValue
* sub_dict_with_list
= new base::DictionaryValue();
140 base::ListValue
* sub_sub_list
= new base::ListValue();
141 sub_sub_list
->Append(GinJavaBridgeValue::CreateObjectIDValue(5).release());
142 sub_dict_with_list
->Set("1", sub_sub_list
);
143 objects
.Append(sub_dict_with_list
);
145 scoped_refptr
<GinJavaMethodInvocationHelper
> helper
=
146 new GinJavaMethodInvocationHelper(
147 scoped_ptr
<GinJavaMethodInvocationHelper::ObjectDelegate
>(
148 new NullObjectDelegate()),
151 CountingDispatcherDelegate counter
;
152 helper
->Init(&counter
);
153 counter
.AssertInvocationsCount(1, 6);
158 class ObjectIsGoneObjectDelegate
: public NullObjectDelegate
{
160 ObjectIsGoneObjectDelegate() :
161 get_local_ref_called_(false) {
162 // We need a Java Method object to create a valid JavaMethod instance.
163 JNIEnv
* env
= base::android::AttachCurrentThread();
164 jmethodID method_id
=
165 GetMethodIDFromClassName(env
, "java/lang/Object", "hashCode", "()I");
166 EXPECT_TRUE(method_id
);
167 base::android::ScopedJavaLocalRef
<jobject
> method_obj(
169 env
->ToReflectedMethod(
170 base::android::GetClass(env
, "java/lang/Object").obj(),
173 EXPECT_TRUE(method_obj
.obj());
174 method_
.reset(new JavaMethod(method_obj
));
177 ~ObjectIsGoneObjectDelegate() override
{}
179 base::android::ScopedJavaLocalRef
<jobject
> GetLocalRef(JNIEnv
* env
) override
{
180 get_local_ref_called_
= true;
181 return NullObjectDelegate::GetLocalRef(env
);
184 const JavaMethod
* FindMethod(const std::string
& method_name
,
185 size_t num_parameters
) override
{
186 return method_
.get();
189 bool get_local_ref_called() { return get_local_ref_called_
; }
191 const std::string
& get_method_name() { return method_
->name(); }
194 scoped_ptr
<JavaMethod
> method_
;
195 bool get_local_ref_called_
;
198 DISALLOW_COPY_AND_ASSIGN(ObjectIsGoneObjectDelegate
);
203 TEST_F(GinJavaMethodInvocationHelperTest
, HandleObjectIsGone
) {
204 base::ListValue no_objects
;
205 ObjectIsGoneObjectDelegate
* object_delegate
=
206 new ObjectIsGoneObjectDelegate();
207 scoped_refptr
<GinJavaMethodInvocationHelper
> helper
=
208 new GinJavaMethodInvocationHelper(
209 scoped_ptr
<GinJavaMethodInvocationHelper::ObjectDelegate
>(
211 object_delegate
->get_method_name(),
213 NullDispatcherDelegate dispatcher
;
214 helper
->Init(&dispatcher
);
215 EXPECT_FALSE(object_delegate
->get_local_ref_called());
216 EXPECT_EQ(kGinJavaBridgeNoError
, helper
->GetInvocationError());
218 EXPECT_TRUE(object_delegate
->get_local_ref_called());
219 EXPECT_TRUE(helper
->HoldsPrimitiveResult());
220 EXPECT_TRUE(helper
->GetPrimitiveResult().empty());
221 EXPECT_EQ(kGinJavaBridgeObjectIsGone
, helper
->GetInvocationError());
226 class MethodNotFoundObjectDelegate
: public NullObjectDelegate
{
228 MethodNotFoundObjectDelegate() : find_method_called_(false) {}
230 ~MethodNotFoundObjectDelegate() override
{}
232 base::android::ScopedJavaLocalRef
<jobject
> GetLocalRef(JNIEnv
* env
) override
{
233 return base::android::ScopedJavaLocalRef
<jobject
>(
234 env
, static_cast<jobject
>(env
->FindClass("java/lang/String")));
237 const JavaMethod
* FindMethod(const std::string
& method_name
,
238 size_t num_parameters
) override
{
239 find_method_called_
= true;
243 bool find_method_called() const { return find_method_called_
; }
246 bool find_method_called_
;
249 DISALLOW_COPY_AND_ASSIGN(MethodNotFoundObjectDelegate
);
254 TEST_F(GinJavaMethodInvocationHelperTest
, HandleMethodNotFound
) {
255 base::ListValue no_objects
;
256 MethodNotFoundObjectDelegate
* object_delegate
=
257 new MethodNotFoundObjectDelegate();
258 scoped_refptr
<GinJavaMethodInvocationHelper
> helper
=
259 new GinJavaMethodInvocationHelper(
260 scoped_ptr
<GinJavaMethodInvocationHelper::ObjectDelegate
>(
264 NullDispatcherDelegate dispatcher
;
265 helper
->Init(&dispatcher
);
266 EXPECT_FALSE(object_delegate
->find_method_called());
267 EXPECT_EQ(kGinJavaBridgeNoError
, helper
->GetInvocationError());
269 EXPECT_TRUE(object_delegate
->find_method_called());
270 EXPECT_TRUE(helper
->HoldsPrimitiveResult());
271 EXPECT_TRUE(helper
->GetPrimitiveResult().empty());
272 EXPECT_EQ(kGinJavaBridgeMethodNotFound
, helper
->GetInvocationError());
277 class GetClassObjectDelegate
: public MethodNotFoundObjectDelegate
{
279 GetClassObjectDelegate() : get_class_called_(false) {}
281 ~GetClassObjectDelegate() override
{}
283 const JavaMethod
* FindMethod(const std::string
& method_name
,
284 size_t num_parameters
) override
{
285 find_method_called_
= true;
286 return kFakeGetClass
;
289 bool IsObjectGetClassMethod(const JavaMethod
* method
) override
{
290 get_class_called_
= true;
291 return kFakeGetClass
== method
;
294 bool get_class_called() const { return get_class_called_
; }
297 static const JavaMethod
* kFakeGetClass
;
298 bool get_class_called_
;
300 DISALLOW_COPY_AND_ASSIGN(GetClassObjectDelegate
);
303 // We don't expect GinJavaMethodInvocationHelper to actually invoke the
304 // method, since the point of the test is to verify whether calls to
305 // 'getClass' get blocked.
306 const JavaMethod
* GetClassObjectDelegate::kFakeGetClass
=
307 (JavaMethod
*)0xdeadbeef;
311 TEST_F(GinJavaMethodInvocationHelperTest
, HandleGetClassInvocation
) {
312 base::ListValue no_objects
;
313 GetClassObjectDelegate
* object_delegate
=
314 new GetClassObjectDelegate();
315 scoped_refptr
<GinJavaMethodInvocationHelper
> helper
=
316 new GinJavaMethodInvocationHelper(
317 scoped_ptr
<GinJavaMethodInvocationHelper::ObjectDelegate
>(
321 NullDispatcherDelegate dispatcher
;
322 helper
->Init(&dispatcher
);
323 EXPECT_FALSE(object_delegate
->find_method_called());
324 EXPECT_FALSE(object_delegate
->get_class_called());
325 EXPECT_EQ(kGinJavaBridgeNoError
, helper
->GetInvocationError());
327 EXPECT_TRUE(object_delegate
->find_method_called());
328 EXPECT_TRUE(object_delegate
->get_class_called());
329 EXPECT_TRUE(helper
->HoldsPrimitiveResult());
330 EXPECT_TRUE(helper
->GetPrimitiveResult().empty());
331 EXPECT_EQ(kGinJavaBridgeAccessToObjectGetClassIsBlocked
,
332 helper
->GetInvocationError());
335 } // namespace content