1f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// found in the LICENSE file.
4f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
5116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/browser/android/java/gin_java_method_invocation_helper.h"
6f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
7f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <unistd.h>
8f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
9f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "base/android/event_log.h"
10f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "base/android/jni_android.h"
11f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "base/float_util.h"
12116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/browser/android/java/gin_java_script_to_java_types_coercion.h"
13116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/browser/android/java/java_method.h"
14116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "content/browser/android/java/jni_helper.h"
15f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "content/common/android/gin_java_bridge_value.h"
16f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
17116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "third_party/WebKit/public/platform/WebString.h"
18f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
19f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)using base::android::AttachCurrentThread;
20f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)using base::android::ScopedJavaLocalRef;
21f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
22f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)namespace content {
23f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
24f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)namespace {
25f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
26f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// See frameworks/base/core/java/android/webkit/EventLogTags.logtags
27f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)const int kObjectGetClassInvocationAttemptLogTag = 70151;
28f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
29116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// This is an intermediate solution until we fix http://crbug.com/391492.
30116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstd::string ConvertJavaStringToUTF8(JNIEnv* env, jstring str) {
31116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const jchar* chars = env->GetStringChars(str, NULL);
32116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  DCHECK(chars);
33116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  blink::WebString utf16(chars, env->GetStringLength(str));
34116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  env->ReleaseStringChars(str, chars);
35116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return utf16.utf8();
36116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
37116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
38f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}  // namespace
39f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
40f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)GinJavaMethodInvocationHelper::GinJavaMethodInvocationHelper(
41f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    scoped_ptr<ObjectDelegate> object,
42f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::string& method_name,
43f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const base::ListValue& arguments)
44f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    : object_(object.Pass()),
45f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      method_name_(method_name),
46116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      arguments_(arguments.DeepCopy()),
47116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      invocation_error_(kGinJavaBridgeNoError) {
48f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
49f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
50f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)GinJavaMethodInvocationHelper::~GinJavaMethodInvocationHelper() {}
51f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
52f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void GinJavaMethodInvocationHelper::Init(DispatcherDelegate* dispatcher) {
53f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Build on the UI thread a map of object_id -> WeakRef for Java objects from
54f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // |arguments_|.  Then we can use this map on the background thread without
55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // accessing |dispatcher|.
56f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  BuildObjectRefsFromListValue(dispatcher, arguments_.get());
57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
59f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// As V8ValueConverter has finite recursion depth when serializing
60f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// JavaScript values, we don't bother about having a recursion threshold here.
61f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void GinJavaMethodInvocationHelper::BuildObjectRefsFromListValue(
62f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    DispatcherDelegate* dispatcher,
63f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const base::Value* list_value) {
64f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(list_value->IsType(base::Value::TYPE_LIST));
65f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const base::ListValue* list;
66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  list_value->GetAsList(&list);
67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  for (base::ListValue::const_iterator iter = list->begin();
68f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)       iter != list->end();
69f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)       ++iter) {
70f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (AppendObjectRef(dispatcher, *iter))
71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      continue;
72f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if ((*iter)->IsType(base::Value::TYPE_LIST)) {
73f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      BuildObjectRefsFromListValue(dispatcher, *iter);
74f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    } else if ((*iter)->IsType(base::Value::TYPE_DICTIONARY)) {
75f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      BuildObjectRefsFromDictionaryValue(dispatcher, *iter);
76f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
77f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
78f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
79f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
80f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void GinJavaMethodInvocationHelper::BuildObjectRefsFromDictionaryValue(
81f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    DispatcherDelegate* dispatcher,
82f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const base::Value* dict_value) {
83f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  DCHECK(dict_value->IsType(base::Value::TYPE_DICTIONARY));
84f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const base::DictionaryValue* dict;
85f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  dict_value->GetAsDictionary(&dict);
86f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  for (base::DictionaryValue::Iterator iter(*dict);
87f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)       !iter.IsAtEnd();
88f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)       iter.Advance()) {
89f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (AppendObjectRef(dispatcher, &iter.value()))
90f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      continue;
91f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (iter.value().IsType(base::Value::TYPE_LIST)) {
92f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      BuildObjectRefsFromListValue(dispatcher, &iter.value());
93f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    } else if (iter.value().IsType(base::Value::TYPE_DICTIONARY)) {
94f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      BuildObjectRefsFromDictionaryValue(dispatcher, &iter.value());
95f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
96f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
97f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
98f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
99f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool GinJavaMethodInvocationHelper::AppendObjectRef(
100f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    DispatcherDelegate* dispatcher,
101f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const base::Value* raw_value) {
102f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!GinJavaBridgeValue::ContainsGinJavaBridgeValue(raw_value))
103f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return false;
104f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  scoped_ptr<const GinJavaBridgeValue> value(
105f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      GinJavaBridgeValue::FromValue(raw_value));
106f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!value->IsType(GinJavaBridgeValue::TYPE_OBJECT_ID))
107f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return false;
108f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  GinJavaBoundObject::ObjectID object_id;
109f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (value->GetAsObjectID(&object_id)) {
110f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    ObjectRefs::iterator iter = object_refs_.find(object_id);
111f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    if (iter == object_refs_.end()) {
112f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      JavaObjectWeakGlobalRef object_ref(
113f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          dispatcher->GetObjectWeakRef(object_id));
114f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      if (!object_ref.is_empty()) {
115f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        object_refs_.insert(std::make_pair(object_id, object_ref));
116f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      }
117f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
118f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
119f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return true;
120f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
121f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
122f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void GinJavaMethodInvocationHelper::Invoke() {
123f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  JNIEnv* env = AttachCurrentThread();
124f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  const JavaMethod* method =
125f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      object_->FindMethod(method_name_, arguments_->GetSize());
126f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!method) {
127116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    SetInvocationError(kGinJavaBridgeMethodNotFound);
128f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return;
129f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
130f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
131f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (object_->IsObjectGetClassMethod(method)) {
132f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    base::android::EventLogWriteInt(kObjectGetClassInvocationAttemptLogTag,
133f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                    getuid());
134116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    SetInvocationError(kGinJavaBridgeAccessToObjectGetClassIsBlocked);
135f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    return;
136f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
137f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
1386d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  ScopedJavaLocalRef<jobject> obj;
1396d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  ScopedJavaLocalRef<jclass> cls;
1406d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (method->is_static()) {
1416d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    cls = object_->GetLocalClassRef(env);
1426d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  } else {
1436d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    obj = object_->GetLocalRef(env);
1446d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
1456d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  if (obj.is_null() && cls.is_null()) {
146116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    SetInvocationError(kGinJavaBridgeObjectIsGone);
1476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)    return;
1486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
1496d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)
150116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  GinJavaBridgeError coercion_error = kGinJavaBridgeNoError;
151f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  std::vector<jvalue> parameters(method->num_parameters());
152f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  for (size_t i = 0; i < method->num_parameters(); ++i) {
153f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const base::Value* argument;
154f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    arguments_->Get(i, &argument);
155116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    parameters[i] = CoerceJavaScriptValueToJavaValue(env,
156116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                                     argument,
157116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                                     method->parameter_type(i),
158116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                                     true,
159116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                                     object_refs_,
160116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                                                     &coercion_error);
161f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
162116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
163116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (coercion_error == kGinJavaBridgeNoError) {
164116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (method->is_static()) {
165116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      InvokeMethod(
166116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          NULL, cls.obj(), method->return_type(), method->id(), &parameters[0]);
167116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    } else {
168116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      InvokeMethod(
169116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          obj.obj(), NULL, method->return_type(), method->id(), &parameters[0]);
170116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    }
1716d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  } else {
172116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    SetInvocationError(coercion_error);
1736d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  }
174f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
175f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Now that we're done with the jvalue, release any local references created
176f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // by CoerceJavaScriptValueToJavaValue().
177f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  for (size_t i = 0; i < method->num_parameters(); ++i) {
178f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    ReleaseJavaValueIfRequired(env, &parameters[i], method->parameter_type(i));
179f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
180f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
181f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
182116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid GinJavaMethodInvocationHelper::SetInvocationError(
183116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    GinJavaBridgeError error) {
184f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  holds_primitive_result_ = true;
185f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  primitive_result_.reset(new base::ListValue());
186116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  invocation_error_ = error;
187f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
188f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
189f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void GinJavaMethodInvocationHelper::SetPrimitiveResult(
190f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const base::ListValue& result_wrapper) {
191f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  holds_primitive_result_ = true;
192f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  primitive_result_.reset(result_wrapper.DeepCopy());
193f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
194f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
195f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void GinJavaMethodInvocationHelper::SetObjectResult(
196f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const base::android::JavaRef<jobject>& object,
197f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const base::android::JavaRef<jclass>& safe_annotation_clazz) {
198f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  holds_primitive_result_ = false;
199f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  object_result_.Reset(object);
200f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  safe_annotation_clazz_.Reset(safe_annotation_clazz);
201f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
202f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
203f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)bool GinJavaMethodInvocationHelper::HoldsPrimitiveResult() {
204f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return holds_primitive_result_;
205f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
206f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
207f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)const base::ListValue& GinJavaMethodInvocationHelper::GetPrimitiveResult() {
208f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return *primitive_result_.get();
209f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
210f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
211f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)const base::android::JavaRef<jobject>&
212f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)GinJavaMethodInvocationHelper::GetObjectResult() {
213f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return object_result_;
214f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
215f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
216f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)const base::android::JavaRef<jclass>&
217f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)GinJavaMethodInvocationHelper::GetSafeAnnotationClass() {
218f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  return safe_annotation_clazz_;
219f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
220f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
221116680a4aac90f2aa7413d9095a592090648e557Ben Murdochconst GinJavaBridgeError GinJavaMethodInvocationHelper::GetInvocationError() {
222116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return invocation_error_;
223f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
224f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
225f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void GinJavaMethodInvocationHelper::InvokeMethod(jobject object,
2266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                                                 jclass clazz,
227f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                                 const JavaType& return_type,
228f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                                 jmethodID id,
229f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                                 jvalue* parameters) {
2306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  DCHECK(object || clazz);
231f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  JNIEnv* env = AttachCurrentThread();
232f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  base::ListValue result_wrapper;
233f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  switch (return_type.type) {
234f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case JavaType::TypeBoolean:
235f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      result_wrapper.AppendBoolean(
2366d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          object ? env->CallBooleanMethodA(object, id, parameters)
2376d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                 : env->CallStaticBooleanMethodA(clazz, id, parameters));
238f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
239f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case JavaType::TypeByte:
240f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      result_wrapper.AppendInteger(
2416d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          object ? env->CallByteMethodA(object, id, parameters)
2426d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                 : env->CallStaticByteMethodA(clazz, id, parameters));
243f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
244f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case JavaType::TypeChar:
245f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      result_wrapper.AppendInteger(
2466d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          object ? env->CallCharMethodA(object, id, parameters)
2476d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                 : env->CallStaticCharMethodA(clazz, id, parameters));
248f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
249f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case JavaType::TypeShort:
250f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      result_wrapper.AppendInteger(
2516d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          object ? env->CallShortMethodA(object, id, parameters)
2526d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                 : env->CallStaticShortMethodA(clazz, id, parameters));
253f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
254f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case JavaType::TypeInt:
255f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      result_wrapper.AppendInteger(
2566d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          object ? env->CallIntMethodA(object, id, parameters)
2576d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                 : env->CallStaticIntMethodA(clazz, id, parameters));
258f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
259f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case JavaType::TypeLong:
260f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      result_wrapper.AppendDouble(
2616d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          object ? env->CallLongMethodA(object, id, parameters)
2626d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                 : env->CallStaticLongMethodA(clazz, id, parameters));
263f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
264f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case JavaType::TypeFloat: {
2656d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      float result = object
2666d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                         ? env->CallFloatMethodA(object, id, parameters)
2676d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                         : env->CallStaticFloatMethodA(clazz, id, parameters);
268f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      if (base::IsFinite(result)) {
269f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        result_wrapper.AppendDouble(result);
270f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      } else {
271f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        result_wrapper.Append(
272f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            GinJavaBridgeValue::CreateNonFiniteValue(result).release());
273f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      }
274f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
275f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
276f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case JavaType::TypeDouble: {
2776d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      double result = object
2786d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                          ? env->CallDoubleMethodA(object, id, parameters)
2796d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                          : env->CallStaticDoubleMethodA(clazz, id, parameters);
280f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      if (base::IsFinite(result)) {
281f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        result_wrapper.AppendDouble(result);
282f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      } else {
283f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        result_wrapper.Append(
284f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            GinJavaBridgeValue::CreateNonFiniteValue(result).release());
285f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      }
286f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
287f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
288f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case JavaType::TypeVoid:
2896d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      if (object)
2906d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        env->CallVoidMethodA(object, id, parameters);
2916d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      else
2926d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)        env->CallStaticVoidMethodA(clazz, id, parameters);
293f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      result_wrapper.Append(
294f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          GinJavaBridgeValue::CreateUndefinedValue().release());
295f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
296f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case JavaType::TypeArray:
297f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      // LIVECONNECT_COMPLIANCE: Existing behavior is to not call methods that
298f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      // return arrays. Spec requires calling the method and converting the
299f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      // result to a JavaScript array.
300f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      result_wrapper.Append(
301f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          GinJavaBridgeValue::CreateUndefinedValue().release());
302f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
303f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case JavaType::TypeString: {
304f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      jstring java_string = static_cast<jstring>(
3056d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          object ? env->CallObjectMethodA(object, id, parameters)
3066d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                 : env->CallStaticObjectMethodA(clazz, id, parameters));
307f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      // If an exception was raised, we must clear it before calling most JNI
308f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      // methods. ScopedJavaLocalRef is liable to make such calls, so we test
309f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      // first.
310f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      if (base::android::ClearException(env)) {
311116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        SetInvocationError(kGinJavaBridgeJavaExceptionRaised);
312f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        return;
313f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      }
314f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      ScopedJavaLocalRef<jstring> scoped_java_string(env, java_string);
315f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      if (!scoped_java_string.obj()) {
316f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        // LIVECONNECT_COMPLIANCE: Existing behavior is to return undefined.
317f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        // Spec requires returning a null string.
318f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        result_wrapper.Append(
319f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)            GinJavaBridgeValue::CreateUndefinedValue().release());
320f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        break;
321f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      }
322f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      result_wrapper.AppendString(
323116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          ConvertJavaStringToUTF8(env, scoped_java_string.obj()));
324f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
325f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
326f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case JavaType::TypeObject: {
327f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      // If an exception was raised, we must clear it before calling most JNI
328f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      // methods. ScopedJavaLocalRef is liable to make such calls, so we test
329f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      // first.
3306d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)      jobject java_object =
3316d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)          object ? env->CallObjectMethodA(object, id, parameters)
3326d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                 : env->CallStaticObjectMethodA(clazz, id, parameters);
333f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      if (base::android::ClearException(env)) {
334116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        SetInvocationError(kGinJavaBridgeJavaExceptionRaised);
335f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        return;
336f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      }
337f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      ScopedJavaLocalRef<jobject> scoped_java_object(env, java_object);
338f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      if (!scoped_java_object.obj()) {
339f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        result_wrapper.Append(base::Value::CreateNullValue());
340f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        break;
341f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      }
342f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      SetObjectResult(scoped_java_object, object_->GetSafeAnnotationClass());
343f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      return;
344f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    }
345f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
346f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // This is for all cases except JavaType::TypeObject.
347f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  if (!base::android::ClearException(env)) {
348f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    SetPrimitiveResult(result_wrapper);
349f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  } else {
350116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    SetInvocationError(kGinJavaBridgeJavaExceptionRaised);
351f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  }
352f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}
353f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
354f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}  // namespace content
355