1 // Copyright 2017 Samsung Electronics. 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 "browser/javascript_interface/gin_native_bridge_dispatcher_host.h"
7 #include "base/logging.h"
8 #include "base/task/task_runner_util.h"
9 #include "browser/javascript_interface/gin_native_bridge_message_filter.h"
10 #include "common/gin_native_bridge_messages.h"
11 #include "common/gin_native_bridge_value.h"
12 #include "content/browser/renderer_host/render_frame_host_impl.h"
13 #include "content/browser/web_contents/web_contents_impl.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "content/public/browser/render_frame_host.h"
16 #include "content/public/browser/render_process_host.h"
17 #include "content/public/browser/web_contents.h"
18 #include "ipc/ipc_message_utils.h"
22 GinNativeBridgeDispatcherHost::GinNativeBridgeDispatcherHost(
23 WebContents* web_contents)
24 : WebContentsObserver(web_contents), next_object_id_(1) {}
26 GinNativeBridgeDispatcherHost::~GinNativeBridgeDispatcherHost() {}
28 void GinNativeBridgeDispatcherHost::InstallFilterAndRegisterAllRoutingIds() {
29 DCHECK_CURRENTLY_ON(BrowserThread::UI);
30 if (!web_contents()->GetPrimaryMainFrame()->GetProcess()->GetChannel()) {
34 web_contents()->GetPrimaryMainFrame()->ForEachRenderFrameHost(
35 [this](RenderFrameHostImpl* frame) {
36 auto filter = GinNativeBridgeMessageFilter::FromHost(this, true);
37 filter->AddRoutingIdForHost(this, frame);
41 void GinNativeBridgeDispatcherHost::RenderFrameCreated(
42 RenderFrameHost* render_frame_host) {
43 DCHECK_CURRENTLY_ON(BrowserThread::UI);
45 if (auto filter = GinNativeBridgeMessageFilter::FromHost(this, false)) {
46 filter->AddRoutingIdForHost(
47 this, static_cast<RenderFrameHostImpl*>(render_frame_host));
49 InstallFilterAndRegisterAllRoutingIds();
51 for (NamedObjectMap::const_iterator iter = named_objects_.begin();
52 iter != named_objects_.end(); ++iter) {
53 render_frame_host->Send(new GinNativeBridgeMsg_AddNamedObject(
54 render_frame_host->GetRoutingID(), iter->first, iter->second));
58 void GinNativeBridgeDispatcherHost::WebContentsDestroyed() {
59 scoped_refptr<GinNativeBridgeMessageFilter> filter =
60 GinNativeBridgeMessageFilter::FromHost(this, false);
62 filter->RemoveHost(this);
65 WebContentsImpl* GinNativeBridgeDispatcherHost::web_contents() const {
66 return static_cast<WebContentsImpl*>(WebContentsObserver::web_contents());
69 bool GinNativeBridgeDispatcherHost::AddNamedObject(
71 Ewk_View_Script_Message_Cb callback,
72 const std::string& name) {
73 LOG(INFO) << __FUNCTION__;
74 DCHECK_CURRENTLY_ON(BrowserThread::UI);
75 GinNativeBoundObject::ObjectID object_id;
76 NamedObjectMap::iterator iter = named_objects_.find(name);
77 if (iter != named_objects_.end())
80 object_id = AddObject(view, callback, name, true, 0);
81 named_objects_[name] = object_id;
83 InstallFilterAndRegisterAllRoutingIds();
86 ->GetPrimaryMainFrame()
87 ->ForEachRenderFrameHostIncludingSpeculative(
88 [&name, object_id](RenderFrameHostImpl* render_frame_host) {
89 render_frame_host->Send(new GinNativeBridgeMsg_AddNamedObject(
90 render_frame_host->GetRoutingID(), name, object_id));
96 void GinNativeBridgeDispatcherHost::RemoveNamedObject(const std::string& name) {
97 DCHECK_CURRENTLY_ON(BrowserThread::UI);
98 NamedObjectMap::iterator iter = named_objects_.find(name);
99 if (iter == named_objects_.end())
102 // |name| may come from |named_objects_|. Make a copy of name so that if
103 // |name| is from |named_objects_| it'll be valid after the remove below.
104 const std::string copied_name(name);
106 base::AutoLock locker(objects_lock_);
107 objects_[iter->second]->RemoveName();
109 named_objects_.erase(iter);
111 // As the object isn't going to be removed from the JavaScript side until the
112 // next page reload, calls to it must still work, thus we should continue to
113 // hold it. All the transient objects and removed named objects will be purged
114 // during the cleansing caused by DocumentAvailableInMainFrame event.
116 ->GetPrimaryMainFrame()
117 ->ForEachRenderFrameHostIncludingSpeculative(
118 [&copied_name](RenderFrameHostImpl* render_frame_host) {
119 render_frame_host->Send(new GinNativeBridgeMsg_RemoveNamedObject(
120 render_frame_host->GetRoutingID(), copied_name));
124 GinNativeBoundObject::ObjectID GinNativeBridgeDispatcherHost::AddObject(
126 Ewk_View_Script_Message_Cb callback,
127 const std::string& name,
130 scoped_refptr<GinNativeBoundObject> new_object =
132 ? GinNativeBoundObject::CreateNamed(view, callback, name)
133 : GinNativeBoundObject::CreateTransient(view, callback, name, holder);
134 // Note that we are abusing the fact that StaticAtomicSequenceNumber
135 // uses Atomic32 as a counter, so it is guaranteed that it will not
136 // overflow our int32_t IDs. IDs start from 1.
137 GinNativeBoundObject::ObjectID object_id = next_object_id_++;
139 base::AutoLock locker(objects_lock_);
140 objects_[object_id] = new_object;
145 void GinNativeBridgeDispatcherHost::PrimaryMainDocumentElementAvailable() {
146 DCHECK_CURRENTLY_ON(BrowserThread::UI);
147 // Called when the window object has been cleared in the main frame.
148 // That means, all sub-frames have also been cleared, so only named
154 scoped_refptr<GinNativeBoundObject> GinNativeBridgeDispatcherHost::FindObject(
155 GinNativeBoundObject::ObjectID object_id) {
156 // Can be called on any thread.
157 base::AutoLock locker(objects_lock_);
158 auto iter = objects_.find(object_id);
159 if (iter != objects_.end())
161 LOG(ERROR) << "WebView: Unknown object: " << object_id;
165 void GinNativeBridgeDispatcherHost::OnHasMethod(
166 GinNativeBoundObject::ObjectID object_id,
167 const std::string& method_name,
169 scoped_refptr<GinNativeBoundObject> object = FindObject(object_id);
171 *result = (object.get()) ? true : false;
174 void GinNativeBridgeDispatcherHost::OnInvokeMethod(
176 GinNativeBoundObject::ObjectID object_id,
177 const std::string& method_name,
178 const base::Value::List& arguments,
179 base::Value::List* wrapped_result,
180 content::GinNativeBridgeError* error_code) {
181 LOG(INFO) << __FUNCTION__;
182 DCHECK(routing_id != MSG_ROUTING_NONE);
183 if (method_name != "postMessage") {
184 LOG(ERROR) << __FUNCTION__ << " : kGinNativeBridgeMethodNotFound";
185 wrapped_result->Append(base::Value());
186 *error_code = kGinNativeBridgeMethodNotFound;
190 scoped_refptr<GinNativeBoundObject> object = FindObject(object_id);
192 LOG(ERROR) << "WebView: Unknown object: " << object_id;
193 wrapped_result->Append(base::Value());
194 *error_code = kGinNativeBridgeUnknownObjectId;
198 Ewk_Script_Message msg;
199 msg.name = object->Name();
201 if (named_objects_.find(msg.name) == named_objects_.end()) {
202 LOG(ERROR) << __FUNCTION__ << " : kGinNativeBridgeMessageNameIsWrong";
203 wrapped_result->Append(base::Value());
204 *error_code = kGinNativeBridgeMessageNameIsWrong;
208 JavaScript_Values values;
209 values.bool_buf = EINA_FALSE;
211 values.double_buf = -1;
214 bool bool_buf = false;
215 bool should_free = false;
217 base::Value::List::const_iterator iter = arguments.begin();
219 switch (iter->type()) {
220 case base::Value::Type::BOOLEAN:
221 bool_buf = iter->GetBool();
222 (bool_buf) ? values.bool_buf = EINA_TRUE : values.bool_buf = EINA_FALSE;
223 msg.body = &values.bool_buf;
225 case base::Value::Type::INTEGER:
226 values.int_buf = iter->GetInt();
227 msg.body = &values.int_buf;
229 case base::Value::Type::DOUBLE:
230 values.double_buf = iter->GetDouble();
231 msg.body = &values.double_buf;
233 case base::Value::Type::STRING:
234 values.str_buf = iter->GetString();
235 msg.body = strdup(values.str_buf.c_str());
238 case base::Value::Type::DICTIONARY:
239 values.str_buf = ConvertDictionaryValueToString(iter->GetDict());
240 msg.body = strdup(values.str_buf.c_str());
243 case base::Value::Type::LIST:
244 values.str_buf = ConvertListValueToString(iter->GetList());
245 msg.body = strdup(values.str_buf.c_str());
248 case base::Value::Type::BINARY:
249 values.str_buf.assign(iter->GetBlob().begin(), iter->GetBlob().end());
250 msg.body = (void*)values.str_buf.data();
253 LOG(ERROR) << __FUNCTION__ << " : kGinNativeBridgeNotSupportedTypes";
254 wrapped_result->Append(base::Value());
255 *error_code = kGinNativeBridgeNotSupportedTypes;
259 object->CallBack()(object->GetView(), msg);
260 wrapped_result->Append(base::Value::FromUniquePtrValue(
261 GinNativeBridgeValue::CreateObjectIDValue(object_id)));
269 std::string GinNativeBridgeDispatcherHost::ConvertListValueToString(
270 const base::Value::List& list) {
272 bool bool_buf = false;
274 double double_buf = -1;
275 std::string str_buf = "";
276 std::string token = "";
279 for (base::Value::List::const_iterator iter_list = list.begin();
280 iter_list != list.end(); ++iter_list) {
284 switch (iter_list->type()) {
285 case base::Value::Type::BOOLEAN:
287 bool_buf = iter_list->GetBool();
288 (bool_buf) ? str_buf += "true" : str_buf += "false";
290 case base::Value::Type::INTEGER:
292 int_buf = iter_list->GetInt();
293 str_buf += std::to_string(int_buf);
295 case base::Value::Type::DOUBLE:
297 double_buf = iter_list->GetDouble();
298 str_buf += std::to_string(double_buf);
300 case base::Value::Type::STRING:
302 token = iter_list->GetString();
307 case base::Value::Type::DICTIONARY:
308 str_buf += ConvertDictionaryValueToString(iter_list->GetDict());
310 case base::Value::Type::LIST:
311 str_buf += ConvertListValueToString(iter_list->GetList());
324 std::string GinNativeBridgeDispatcherHost::ConvertDictionaryValueToString(
325 const base::Value::Dict& dict) {
327 bool bool_buf = false;
329 double double_buf = -1;
330 std::string str_buf = "";
331 std::string token = "";
334 for (const auto item : dict) {
338 str_buf += item.first;
341 switch (item.second.type()) {
342 case base::Value::Type::BOOLEAN:
344 bool_buf = item.second.GetBool();
345 (bool_buf) ? str_buf += "true" : str_buf += "false";
347 case base::Value::Type::INTEGER:
349 int_buf = item.second.GetInt();
350 str_buf += std::to_string(int_buf);
352 case base::Value::Type::DOUBLE:
354 double_buf = item.second.GetDouble();
355 str_buf += std::to_string(double_buf);
357 case base::Value::Type::STRING:
359 token = item.second.GetString();
364 case base::Value::Type::DICTIONARY:
365 str_buf += ConvertDictionaryValueToString(item.second.GetDict());
367 case base::Value::Type::LIST:
368 str_buf += ConvertListValueToString(item.second.GetList());
381 } // namespace content