Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1009)

Side by Side Diff: extensions/renderer/messaging_bindings.cc

Issue 2547753002: [Extensions] Extension Port Ids and Initialization 2.0 (Closed)
Patch Set: Rob's test Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "extensions/renderer/messaging_bindings.h" 5 #include "extensions/renderer/messaging_bindings.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 8
9 #include <map> 9 #include <map>
10 #include <string> 10 #include <string>
11 11
12 #include "base/bind.h" 12 #include "base/bind.h"
13 #include "base/bind_helpers.h" 13 #include "base/bind_helpers.h"
14 #include "base/callback.h" 14 #include "base/callback.h"
15 #include "base/callback_helpers.h" 15 #include "base/callback_helpers.h"
16 #include "base/guid.h"
16 #include "base/lazy_instance.h" 17 #include "base/lazy_instance.h"
17 #include "base/message_loop/message_loop.h" 18 #include "base/message_loop/message_loop.h"
18 #include "base/metrics/histogram_macros.h" 19 #include "base/metrics/histogram_macros.h"
19 #include "base/values.h" 20 #include "base/values.h"
20 #include "content/public/child/v8_value_converter.h" 21 #include "content/public/child/v8_value_converter.h"
21 #include "content/public/common/child_process_host.h" 22 #include "content/public/common/child_process_host.h"
22 #include "content/public/renderer/render_frame.h" 23 #include "content/public/renderer/render_frame.h"
23 #include "content/public/renderer/render_thread.h" 24 #include "content/public/renderer/render_thread.h"
24 #include "extensions/common/api/messaging/message.h" 25 #include "extensions/common/api/messaging/message.h"
26 #include "extensions/common/api/messaging/port_id.h"
25 #include "extensions/common/extension_messages.h" 27 #include "extensions/common/extension_messages.h"
26 #include "extensions/common/manifest_handlers/externally_connectable.h" 28 #include "extensions/common/manifest_handlers/externally_connectable.h"
27 #include "extensions/renderer/extension_frame_helper.h" 29 #include "extensions/renderer/extension_frame_helper.h"
28 #include "extensions/renderer/extension_port.h" 30 #include "extensions/renderer/extension_port.h"
29 #include "extensions/renderer/gc_callback.h" 31 #include "extensions/renderer/gc_callback.h"
30 #include "extensions/renderer/script_context.h" 32 #include "extensions/renderer/script_context.h"
31 #include "extensions/renderer/script_context_set.h" 33 #include "extensions/renderer/script_context_set.h"
32 #include "extensions/renderer/v8_helpers.h" 34 #include "extensions/renderer/v8_helpers.h"
33 #include "third_party/WebKit/public/web/WebDocument.h" 35 #include "third_party/WebKit/public/web/WebDocument.h"
34 #include "third_party/WebKit/public/web/WebLocalFrame.h" 36 #include "third_party/WebKit/public/web/WebLocalFrame.h"
(...skipping 13 matching lines...) Expand all
48 namespace extensions { 50 namespace extensions {
49 51
50 using v8_helpers::ToV8String; 52 using v8_helpers::ToV8String;
51 53
52 namespace { 54 namespace {
53 55
54 // A global map between ScriptContext and MessagingBindings. 56 // A global map between ScriptContext and MessagingBindings.
55 base::LazyInstance<std::map<ScriptContext*, MessagingBindings*>> 57 base::LazyInstance<std::map<ScriptContext*, MessagingBindings*>>
56 g_messaging_map = LAZY_INSTANCE_INITIALIZER; 58 g_messaging_map = LAZY_INSTANCE_INITIALIZER;
57 59
58 void HasMessagePort(int global_port_id, 60 void HasMessagePort(const PortId& port_id,
59 bool* has_port, 61 bool* has_port,
60 ScriptContext* script_context) { 62 ScriptContext* script_context) {
61 if (*has_port) 63 if (*has_port)
62 return; // Stop checking if the port was found. 64 return; // Stop checking if the port was found.
63 65
64 MessagingBindings* bindings = g_messaging_map.Get()[script_context]; 66 MessagingBindings* bindings = g_messaging_map.Get()[script_context];
65 DCHECK(bindings); 67 DCHECK(bindings);
66 if (bindings->GetPortWithGlobalId(global_port_id)) 68 // No need for |=; we know this is false right now from above.
67 *has_port = true; 69 *has_port = bindings->GetPortWithId(port_id) != nullptr;
68 } 70 }
69 71
70 void DispatchOnConnectToScriptContext( 72 void DispatchOnConnectToScriptContext(
71 int global_target_port_id, 73 const PortId& target_port_id,
72 const std::string& channel_name, 74 const std::string& channel_name,
73 const ExtensionMsg_TabConnectionInfo* source, 75 const ExtensionMsg_TabConnectionInfo* source,
74 const ExtensionMsg_ExternalConnectionInfo& info, 76 const ExtensionMsg_ExternalConnectionInfo& info,
75 const std::string& tls_channel_id, 77 const std::string& tls_channel_id,
76 bool* port_created, 78 bool* port_created,
77 ScriptContext* script_context) { 79 ScriptContext* script_context) {
78 MessagingBindings* bindings = g_messaging_map.Get()[script_context]; 80 MessagingBindings* bindings = g_messaging_map.Get()[script_context];
79 DCHECK(bindings); 81 DCHECK(bindings);
80 82
81 int opposite_port_id = global_target_port_id ^ 1; 83 if (bindings->context_id() == target_port_id.context_id)
82 if (bindings->GetPortWithGlobalId(opposite_port_id))
83 return; // The channel was opened by this same context; ignore it. 84 return; // The channel was opened by this same context; ignore it.
robwu 2016/12/02 11:58:54 I'd extend this comment with the remark that this
Devlin 2016/12/02 17:16:32 Done.
84 85
85 ExtensionPort* port = 86 ExtensionPort* port = bindings->CreateNewPortWithId(target_port_id);
86 bindings->CreateNewPortWithGlobalId(global_target_port_id);
87 int local_port_id = port->local_id();
88 // Remove the port. 87 // Remove the port.
89 base::ScopedClosureRunner remove_port( 88 base::ScopedClosureRunner remove_port(
90 base::Bind(&MessagingBindings::RemovePortWithLocalId, 89 base::Bind(&MessagingBindings::RemovePortWithJsId, bindings->GetWeakPtr(),
91 bindings->GetWeakPtr(), local_port_id)); 90 port->js_id()));
92 91
93 v8::Isolate* isolate = script_context->isolate(); 92 v8::Isolate* isolate = script_context->isolate();
94 v8::HandleScope handle_scope(isolate); 93 v8::HandleScope handle_scope(isolate);
95 94
96 95
97 const std::string& source_url_spec = info.source_url.spec(); 96 const std::string& source_url_spec = info.source_url.spec();
98 std::string target_extension_id = script_context->GetExtensionID(); 97 std::string target_extension_id = script_context->GetExtensionID();
99 const Extension* extension = script_context->extension(); 98 const Extension* extension = script_context->extension();
100 99
101 v8::Local<v8::Value> tab = v8::Null(isolate); 100 v8::Local<v8::Value> tab = v8::Null(isolate);
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
134 !ToV8String(isolate, info.source_id.c_str(), &v8_source_id) || 133 !ToV8String(isolate, info.source_id.c_str(), &v8_source_id) ||
135 !ToV8String(isolate, target_extension_id.c_str(), 134 !ToV8String(isolate, target_extension_id.c_str(),
136 &v8_target_extension_id) || 135 &v8_target_extension_id) ||
137 !ToV8String(isolate, source_url_spec.c_str(), &v8_source_url_spec)) { 136 !ToV8String(isolate, source_url_spec.c_str(), &v8_source_url_spec)) {
138 NOTREACHED() << "dispatchOnConnect() passed non-string argument"; 137 NOTREACHED() << "dispatchOnConnect() passed non-string argument";
139 return; 138 return;
140 } 139 }
141 140
142 v8::Local<v8::Value> arguments[] = { 141 v8::Local<v8::Value> arguments[] = {
143 // portId 142 // portId
144 v8::Integer::New(isolate, local_port_id), 143 v8::Integer::New(isolate, port->js_id()),
145 // channelName 144 // channelName
146 v8_channel_name, 145 v8_channel_name,
147 // sourceTab 146 // sourceTab
148 tab, 147 tab,
149 // source_frame_id 148 // source_frame_id
150 v8::Integer::New(isolate, source->frame_id), 149 v8::Integer::New(isolate, source->frame_id),
151 // guestProcessId 150 // guestProcessId
152 guest_process_id, 151 guest_process_id,
153 // guestRenderFrameRoutingId 152 // guestRenderFrameRoutingId
154 guest_render_frame_routing_id, 153 guest_render_frame_routing_id,
(...skipping 16 matching lines...) Expand all
171 bool used = retval.As<v8::Boolean>()->Value(); 170 bool used = retval.As<v8::Boolean>()->Value();
172 *port_created |= used; 171 *port_created |= used;
173 if (used) // Port was used; don't remove it. 172 if (used) // Port was used; don't remove it.
174 remove_port.ReplaceClosure(base::Closure()); 173 remove_port.ReplaceClosure(base::Closure());
175 } else { 174 } else {
176 LOG(ERROR) << "Empty return value from dispatchOnConnect."; 175 LOG(ERROR) << "Empty return value from dispatchOnConnect.";
177 } 176 }
178 } 177 }
179 178
180 void DeliverMessageToScriptContext(const Message& message, 179 void DeliverMessageToScriptContext(const Message& message,
181 int global_target_port_id, 180 const PortId& target_port_id,
182 ScriptContext* script_context) { 181 ScriptContext* script_context) {
183 MessagingBindings* bindings = g_messaging_map.Get()[script_context]; 182 MessagingBindings* bindings = g_messaging_map.Get()[script_context];
184 DCHECK(bindings); 183 DCHECK(bindings);
185 ExtensionPort* port = bindings->GetPortWithGlobalId(global_target_port_id); 184 ExtensionPort* port = bindings->GetPortWithId(target_port_id);
186 if (!port) 185 if (!port)
187 return; 186 return;
188 187
189 v8::Isolate* isolate = script_context->isolate(); 188 v8::Isolate* isolate = script_context->isolate();
190 v8::HandleScope handle_scope(isolate); 189 v8::HandleScope handle_scope(isolate);
191 190
192 v8::Local<v8::Value> port_id_handle = 191 v8::Local<v8::Value> port_id_handle =
193 v8::Integer::New(isolate, port->local_id()); 192 v8::Integer::New(isolate, port->js_id());
194 193
195 v8::Local<v8::String> v8_data; 194 v8::Local<v8::String> v8_data;
196 if (!ToV8String(isolate, message.data.c_str(), &v8_data)) 195 if (!ToV8String(isolate, message.data.c_str(), &v8_data))
197 return; 196 return;
198 std::vector<v8::Local<v8::Value>> arguments; 197 std::vector<v8::Local<v8::Value>> arguments;
199 arguments.push_back(v8_data); 198 arguments.push_back(v8_data);
200 arguments.push_back(port_id_handle); 199 arguments.push_back(port_id_handle);
201 200
202 std::unique_ptr<blink::WebScopedUserGesture> web_user_gesture; 201 std::unique_ptr<blink::WebScopedUserGesture> web_user_gesture;
203 std::unique_ptr<blink::WebScopedWindowFocusAllowedIndicator> 202 std::unique_ptr<blink::WebScopedWindowFocusAllowedIndicator>
204 allow_window_focus; 203 allow_window_focus;
205 if (message.user_gesture) { 204 if (message.user_gesture) {
206 web_user_gesture.reset( 205 web_user_gesture.reset(
207 new blink::WebScopedUserGesture(script_context->web_frame())); 206 new blink::WebScopedUserGesture(script_context->web_frame()));
208 207
209 if (script_context->web_frame()) { 208 if (script_context->web_frame()) {
210 blink::WebDocument document = script_context->web_frame()->document(); 209 blink::WebDocument document = script_context->web_frame()->document();
211 allow_window_focus.reset(new blink::WebScopedWindowFocusAllowedIndicator( 210 allow_window_focus.reset(new blink::WebScopedWindowFocusAllowedIndicator(
212 &document)); 211 &document));
213 } 212 }
214 } 213 }
215 214
216 script_context->module_system()->CallModuleMethodSafe( 215 script_context->module_system()->CallModuleMethodSafe(
217 "messaging", "dispatchOnMessage", &arguments); 216 "messaging", "dispatchOnMessage", &arguments);
218 } 217 }
219 218
220 void DispatchOnDisconnectToScriptContext(int global_port_id, 219 void DispatchOnDisconnectToScriptContext(const PortId& port_id,
221 const std::string& error_message, 220 const std::string& error_message,
222 ScriptContext* script_context) { 221 ScriptContext* script_context) {
223 MessagingBindings* bindings = g_messaging_map.Get()[script_context]; 222 MessagingBindings* bindings = g_messaging_map.Get()[script_context];
224 DCHECK(bindings); 223 DCHECK(bindings);
225 ExtensionPort* port = bindings->GetPortWithGlobalId(global_port_id); 224 ExtensionPort* port = bindings->GetPortWithId(port_id);
226 if (!port) 225 if (!port)
227 return; 226 return;
228 227
229 v8::Isolate* isolate = script_context->isolate(); 228 v8::Isolate* isolate = script_context->isolate();
230 v8::HandleScope handle_scope(isolate); 229 v8::HandleScope handle_scope(isolate);
231 230
232 std::vector<v8::Local<v8::Value>> arguments; 231 std::vector<v8::Local<v8::Value>> arguments;
233 arguments.push_back(v8::Integer::New(isolate, port->local_id())); 232 arguments.push_back(v8::Integer::New(isolate, port->js_id()));
234 v8::Local<v8::String> v8_error_message; 233 v8::Local<v8::String> v8_error_message;
235 if (!error_message.empty()) 234 if (!error_message.empty())
236 ToV8String(isolate, error_message.c_str(), &v8_error_message); 235 ToV8String(isolate, error_message.c_str(), &v8_error_message);
237 if (!v8_error_message.IsEmpty()) { 236 if (!v8_error_message.IsEmpty()) {
238 arguments.push_back(v8_error_message); 237 arguments.push_back(v8_error_message);
239 } else { 238 } else {
240 arguments.push_back(v8::Null(isolate)); 239 arguments.push_back(v8::Null(isolate));
241 } 240 }
242 241
243 script_context->module_system()->CallModuleMethodSafe( 242 script_context->module_system()->CallModuleMethodSafe(
244 "messaging", "dispatchOnDisconnect", &arguments); 243 "messaging", "dispatchOnDisconnect", &arguments);
245 } 244 }
246 245
247 } // namespace 246 } // namespace
248 247
249 MessagingBindings::MessagingBindings(ScriptContext* context) 248 MessagingBindings::MessagingBindings(ScriptContext* context)
250 : ObjectBackedNativeHandler(context), weak_ptr_factory_(this) { 249 : ObjectBackedNativeHandler(context),
250 context_id_(base::GenerateGUID()),
251 weak_ptr_factory_(this) {
251 g_messaging_map.Get()[context] = this; 252 g_messaging_map.Get()[context] = this;
252 RouteFunction("CloseChannel", base::Bind(&MessagingBindings::CloseChannel, 253 RouteFunction("CloseChannel", base::Bind(&MessagingBindings::CloseChannel,
253 base::Unretained(this))); 254 base::Unretained(this)));
254 RouteFunction("PostMessage", base::Bind(&MessagingBindings::PostMessage, 255 RouteFunction("PostMessage", base::Bind(&MessagingBindings::PostMessage,
255 base::Unretained(this))); 256 base::Unretained(this)));
256 // TODO(fsamuel, kalman): Move BindToGC out of messaging natives. 257 // TODO(fsamuel, kalman): Move BindToGC out of messaging natives.
257 RouteFunction("BindToGC", base::Bind(&MessagingBindings::BindToGC, 258 RouteFunction("BindToGC", base::Bind(&MessagingBindings::BindToGC,
258 base::Unretained(this))); 259 base::Unretained(this)));
259 RouteFunction("OpenChannelToExtension", "runtime.connect", 260 RouteFunction("OpenChannelToExtension", "runtime.connect",
260 base::Bind(&MessagingBindings::OpenChannelToExtension, 261 base::Bind(&MessagingBindings::OpenChannelToExtension,
(...skipping 18 matching lines...) Expand all
279 ports_created_in_unload_); 280 ports_created_in_unload_);
280 UMA_HISTOGRAM_COUNTS_1000( 281 UMA_HISTOGRAM_COUNTS_1000(
281 "Extensions.Messaging.ExtensionPortsCreated.Normal", 282 "Extensions.Messaging.ExtensionPortsCreated.Normal",
282 ports_created_normal_); 283 ports_created_normal_);
283 } 284 }
284 } 285 }
285 286
286 // static 287 // static
287 void MessagingBindings::ValidateMessagePort( 288 void MessagingBindings::ValidateMessagePort(
288 const ScriptContextSet& context_set, 289 const ScriptContextSet& context_set,
289 int global_port_id, 290 const PortId& port_id,
290 content::RenderFrame* render_frame) { 291 content::RenderFrame* render_frame) {
291 int routing_id = render_frame->GetRoutingID(); 292 int routing_id = render_frame->GetRoutingID();
292 293
293 bool has_port = false; 294 bool has_port = false;
294 context_set.ForEach(render_frame, 295 context_set.ForEach(render_frame,
295 base::Bind(&HasMessagePort, global_port_id, &has_port)); 296 base::Bind(&HasMessagePort, port_id, &has_port));
296 297
297 // A reply is only sent if the port is missing, because the port is assumed to 298 // A reply is only sent if the port is missing, because the port is assumed to
298 // exist unless stated otherwise. 299 // exist unless stated otherwise.
299 if (!has_port) { 300 if (!has_port) {
300 content::RenderThread::Get()->Send( 301 content::RenderThread::Get()->Send(
301 new ExtensionHostMsg_CloseMessagePort(routing_id, 302 new ExtensionHostMsg_CloseMessagePort(routing_id, port_id, false));
302 global_port_id, false));
303 } 303 }
304 } 304 }
305 305
306 // static 306 // static
307 void MessagingBindings::DispatchOnConnect( 307 void MessagingBindings::DispatchOnConnect(
308 const ScriptContextSet& context_set, 308 const ScriptContextSet& context_set,
309 int target_port_id, 309 const PortId& target_port_id,
310 const std::string& channel_name, 310 const std::string& channel_name,
311 const ExtensionMsg_TabConnectionInfo& source, 311 const ExtensionMsg_TabConnectionInfo& source,
312 const ExtensionMsg_ExternalConnectionInfo& info, 312 const ExtensionMsg_ExternalConnectionInfo& info,
313 const std::string& tls_channel_id, 313 const std::string& tls_channel_id,
314 content::RenderFrame* restrict_to_render_frame) { 314 content::RenderFrame* restrict_to_render_frame) {
315 DCHECK(!target_port_id.is_opener);
315 int routing_id = restrict_to_render_frame 316 int routing_id = restrict_to_render_frame
316 ? restrict_to_render_frame->GetRoutingID() 317 ? restrict_to_render_frame->GetRoutingID()
317 : MSG_ROUTING_NONE; 318 : MSG_ROUTING_NONE;
318 bool port_created = false; 319 bool port_created = false;
319 context_set.ForEach( 320 context_set.ForEach(
320 info.target_id, restrict_to_render_frame, 321 info.target_id, restrict_to_render_frame,
321 base::Bind(&DispatchOnConnectToScriptContext, target_port_id, 322 base::Bind(&DispatchOnConnectToScriptContext, target_port_id,
322 channel_name, &source, info, tls_channel_id, &port_created)); 323 channel_name, &source, info, tls_channel_id, &port_created));
323 // Note: |restrict_to_render_frame| may have been deleted at this point! 324 // Note: |restrict_to_render_frame| may have been deleted at this point!
324 325
325 if (port_created) { 326 if (port_created) {
326 content::RenderThread::Get()->Send( 327 content::RenderThread::Get()->Send(
327 new ExtensionHostMsg_OpenMessagePort(routing_id, target_port_id)); 328 new ExtensionHostMsg_OpenMessagePort(routing_id, target_port_id));
328 } else { 329 } else {
329 content::RenderThread::Get()->Send(new ExtensionHostMsg_CloseMessagePort( 330 content::RenderThread::Get()->Send(new ExtensionHostMsg_CloseMessagePort(
330 routing_id, target_port_id, false)); 331 routing_id, target_port_id, false));
331 } 332 }
332 } 333 }
333 334
334 // static 335 // static
335 void MessagingBindings::DeliverMessage( 336 void MessagingBindings::DeliverMessage(
336 const ScriptContextSet& context_set, 337 const ScriptContextSet& context_set,
337 int target_port_id, 338 const PortId& target_port_id,
338 const Message& message, 339 const Message& message,
339 content::RenderFrame* restrict_to_render_frame) { 340 content::RenderFrame* restrict_to_render_frame) {
340 context_set.ForEach( 341 context_set.ForEach(
341 restrict_to_render_frame, 342 restrict_to_render_frame,
342 base::Bind(&DeliverMessageToScriptContext, message, target_port_id)); 343 base::Bind(&DeliverMessageToScriptContext, message, target_port_id));
343 } 344 }
344 345
345 // static 346 // static
346 void MessagingBindings::DispatchOnDisconnect( 347 void MessagingBindings::DispatchOnDisconnect(
347 const ScriptContextSet& context_set, 348 const ScriptContextSet& context_set,
348 int port_id, 349 const PortId& port_id,
349 const std::string& error_message, 350 const std::string& error_message,
350 content::RenderFrame* restrict_to_render_frame) { 351 content::RenderFrame* restrict_to_render_frame) {
351 context_set.ForEach( 352 context_set.ForEach(
352 restrict_to_render_frame, 353 restrict_to_render_frame,
353 base::Bind(&DispatchOnDisconnectToScriptContext, port_id, error_message)); 354 base::Bind(&DispatchOnDisconnectToScriptContext, port_id, error_message));
354 } 355 }
355 356
356 ExtensionPort* MessagingBindings::GetPortWithGlobalId(int id) { 357 ExtensionPort* MessagingBindings::GetPortWithId(const PortId& id) {
357 for (const auto& key_value : ports_) { 358 for (const auto& key_value : ports_) {
358 if (key_value.second->global_id() == id) 359 if (key_value.second->id() == id)
359 return key_value.second.get(); 360 return key_value.second.get();
360 } 361 }
361 return nullptr; 362 return nullptr;
362 } 363 }
363 364
364 ExtensionPort* MessagingBindings::CreateNewPortWithGlobalId(int global_id) { 365 ExtensionPort* MessagingBindings::CreateNewPortWithId(const PortId& id) {
365 int local_id = GetNextLocalId(); 366 int js_id = GetNextJsId();
366 ExtensionPort* port = 367 auto port = base::MakeUnique<ExtensionPort>(context(), id, js_id);
367 ports_ 368 return ports_.insert(std::make_pair(js_id, std::move(port)))
368 .insert(std::make_pair( 369 .first->second.get();
369 local_id, base::MakeUnique<ExtensionPort>(context(), local_id)))
370 .first->second.get();
371 port->SetGlobalId(global_id);
372 return port;
373 } 370 }
374 371
375 void MessagingBindings::RemovePortWithLocalId(int local_id) { 372 void MessagingBindings::RemovePortWithJsId(int js_id) {
376 ports_.erase(local_id); 373 ports_.erase(js_id);
377 } 374 }
378 375
379 base::WeakPtr<MessagingBindings> MessagingBindings::GetWeakPtr() { 376 base::WeakPtr<MessagingBindings> MessagingBindings::GetWeakPtr() {
380 return weak_ptr_factory_.GetWeakPtr(); 377 return weak_ptr_factory_.GetWeakPtr();
381 } 378 }
382 379
383 void MessagingBindings::PostMessage( 380 void MessagingBindings::PostMessage(
384 const v8::FunctionCallbackInfo<v8::Value>& args) { 381 const v8::FunctionCallbackInfo<v8::Value>& args) {
385 // Arguments are (int32_t port_id, string message). 382 // Arguments are (int32_t port_id, string message).
386 CHECK(args.Length() == 2); 383 CHECK(args.Length() == 2);
387 CHECK(args[0]->IsInt32()); 384 CHECK(args[0]->IsInt32());
388 CHECK(args[1]->IsString()); 385 CHECK(args[1]->IsString());
389 386
390 int port_id = args[0].As<v8::Int32>()->Value(); 387 int js_port_id = args[0].As<v8::Int32>()->Value();
391 auto iter = ports_.find(port_id); 388 auto iter = ports_.find(js_port_id);
392 if (iter != ports_.end()) { 389 if (iter != ports_.end()) {
393 iter->second->PostExtensionMessage(base::MakeUnique<Message>( 390 iter->second->PostExtensionMessage(base::MakeUnique<Message>(
394 *v8::String::Utf8Value(args[1]), 391 *v8::String::Utf8Value(args[1]),
395 blink::WebUserGestureIndicator::isProcessingUserGesture())); 392 blink::WebUserGestureIndicator::isProcessingUserGesture()));
396 } 393 }
397 } 394 }
398 395
399 void MessagingBindings::CloseChannel( 396 void MessagingBindings::CloseChannel(
400 const v8::FunctionCallbackInfo<v8::Value>& args) { 397 const v8::FunctionCallbackInfo<v8::Value>& args) {
401 // Arguments are (int32_t port_id, bool force_close). 398 // Arguments are (int32_t port_id, bool force_close).
402 CHECK_EQ(2, args.Length()); 399 CHECK_EQ(2, args.Length());
403 CHECK(args[0]->IsInt32()); 400 CHECK(args[0]->IsInt32());
404 CHECK(args[1]->IsBoolean()); 401 CHECK(args[1]->IsBoolean());
405 402
406 int port_id = args[0].As<v8::Int32>()->Value(); 403 int js_port_id = args[0].As<v8::Int32>()->Value();
407 bool force_close = args[1].As<v8::Boolean>()->Value(); 404 bool force_close = args[1].As<v8::Boolean>()->Value();
408 ClosePort(port_id, force_close); 405 ClosePort(js_port_id, force_close);
409 } 406 }
410 407
411 void MessagingBindings::BindToGC( 408 void MessagingBindings::BindToGC(
412 const v8::FunctionCallbackInfo<v8::Value>& args) { 409 const v8::FunctionCallbackInfo<v8::Value>& args) {
413 CHECK(args.Length() == 3); 410 CHECK(args.Length() == 3);
414 CHECK(args[0]->IsObject()); 411 CHECK(args[0]->IsObject());
415 CHECK(args[1]->IsFunction()); 412 CHECK(args[1]->IsFunction());
416 CHECK(args[2]->IsInt32()); 413 CHECK(args[2]->IsInt32());
417 int local_port_id = args[2].As<v8::Int32>()->Value(); 414 int js_port_id = args[2].As<v8::Int32>()->Value();
418 base::Closure fallback = base::Bind(&base::DoNothing); 415 base::Closure fallback = base::Bind(&base::DoNothing);
419 if (local_port_id >= 0) { 416 if (js_port_id >= 0) {
420 // TODO(robwu): Falling back to closing the port shouldn't be needed. If 417 // TODO(robwu): Falling back to closing the port shouldn't be needed. If
421 // the script context is destroyed, then the frame has navigated. But that 418 // the script context is destroyed, then the frame has navigated. But that
422 // is already detected by the browser, so this logic is redundant. Remove 419 // is already detected by the browser, so this logic is redundant. Remove
423 // this fallback (and move BindToGC out of messaging because it is also 420 // this fallback (and move BindToGC out of messaging because it is also
424 // used in other places that have nothing to do with messaging...). 421 // used in other places that have nothing to do with messaging...).
425 fallback = base::Bind(&MessagingBindings::ClosePort, 422 fallback = base::Bind(&MessagingBindings::ClosePort,
426 weak_ptr_factory_.GetWeakPtr(), local_port_id, 423 weak_ptr_factory_.GetWeakPtr(), js_port_id,
427 false /* force_close */); 424 false /* force_close */);
428 } 425 }
429 // Destroys itself when the object is GC'd or context is invalidated. 426 // Destroys itself when the object is GC'd or context is invalidated.
430 new GCCallback(context(), args[0].As<v8::Object>(), 427 new GCCallback(context(), args[0].As<v8::Object>(),
431 args[1].As<v8::Function>(), fallback); 428 args[1].As<v8::Function>(), fallback);
432 } 429 }
433 430
434 void MessagingBindings::OpenChannelToExtension( 431 void MessagingBindings::OpenChannelToExtension(
435 const v8::FunctionCallbackInfo<v8::Value>& args) { 432 const v8::FunctionCallbackInfo<v8::Value>& args) {
436 content::RenderFrame* render_frame = context()->GetRenderFrame(); 433 content::RenderFrame* render_frame = context()->GetRenderFrame();
437 if (!render_frame) 434 if (!render_frame)
438 return; 435 return;
439 436
440 // The Javascript code should validate/fill the arguments. 437 // The Javascript code should validate/fill the arguments.
441 CHECK_EQ(args.Length(), 3); 438 CHECK_EQ(args.Length(), 3);
442 CHECK(args[0]->IsString()); 439 CHECK(args[0]->IsString());
443 CHECK(args[1]->IsString()); 440 CHECK(args[1]->IsString());
444 CHECK(args[2]->IsBoolean()); 441 CHECK(args[2]->IsBoolean());
445 442
446 int local_id = GetNextLocalId(); 443 int js_id = GetNextJsId();
447 ports_[local_id] = base::MakeUnique<ExtensionPort>(context(), local_id); 444 PortId port_id(context_id_, js_id, true);
445 ports_[js_id] = base::MakeUnique<ExtensionPort>(context(), port_id, js_id);
448 446
449 ExtensionMsg_ExternalConnectionInfo info; 447 ExtensionMsg_ExternalConnectionInfo info;
450 // For messaging APIs, hosted apps should be considered a web page so hide 448 // For messaging APIs, hosted apps should be considered a web page so hide
451 // its extension ID. 449 // its extension ID.
452 const Extension* extension = context()->extension(); 450 const Extension* extension = context()->extension();
453 if (extension && !extension->is_hosted_app()) 451 if (extension && !extension->is_hosted_app())
454 info.source_id = extension->id(); 452 info.source_id = extension->id();
455 453
456 info.target_id = *v8::String::Utf8Value(args[0]); 454 info.target_id = *v8::String::Utf8Value(args[0]);
457 info.source_url = context()->url(); 455 info.source_url = context()->url();
458 std::string channel_name = *v8::String::Utf8Value(args[1]); 456 std::string channel_name = *v8::String::Utf8Value(args[1]);
459 // TODO(devlin): Why is this not part of info? 457 // TODO(devlin): Why is this not part of info?
460 bool include_tls_channel_id = 458 bool include_tls_channel_id =
461 args.Length() > 2 ? args[2]->BooleanValue() : false; 459 args.Length() > 2 ? args[2]->BooleanValue() : false;
462 460
463 ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame); 461 {
464 DCHECK(frame_helper); 462 SCOPED_UMA_HISTOGRAM_TIMER(
465 463 "Extensions.Messaging.GetPortIdSyncTime.Extension");
466 blink::WebLocalFrame* web_frame = render_frame->GetWebFrame(); 464 render_frame->Send(new ExtensionHostMsg_OpenChannelToExtension(
467 // If the frame is unloading, we need to assign the port id synchronously to 465 render_frame->GetRoutingID(), info, channel_name,
468 // avoid dropping the message on the floor; see crbug.com/660706. 466 include_tls_channel_id, port_id));
469 // TODO(devlin): Investigate whether we need to continue supporting this long-
470 // term, and, if so, find an alternative that doesn't require synchronous
471 // IPCs.
472 if (!web_frame->document().isNull() &&
473 (web_frame->document().unloadStartedDoNotUse() ||
474 web_frame->document().processingBeforeUnloadDoNotUse())) {
475 ports_created_in_before_unload_ +=
476 web_frame->document().processingBeforeUnloadDoNotUse() ? 1 : 0;
477 ports_created_in_unload_ +=
478 web_frame->document().unloadStartedDoNotUse() ? 1 : 0;
479 int global_id = frame_helper->RequestSyncPortId(info, channel_name,
480 include_tls_channel_id);
481 ports_[local_id]->SetGlobalId(global_id);
482 } else {
483 ++ports_created_normal_;
484 frame_helper->RequestPortId(
485 info, channel_name, include_tls_channel_id,
486 base::Bind(&MessagingBindings::SetGlobalPortId,
487 weak_ptr_factory_.GetWeakPtr(), local_id));
488 } 467 }
489 468
490 args.GetReturnValue().Set(static_cast<int32_t>(local_id)); 469 args.GetReturnValue().Set(static_cast<int32_t>(js_id));
491 } 470 }
492 471
493 void MessagingBindings::OpenChannelToNativeApp( 472 void MessagingBindings::OpenChannelToNativeApp(
494 const v8::FunctionCallbackInfo<v8::Value>& args) { 473 const v8::FunctionCallbackInfo<v8::Value>& args) {
495 // The Javascript code should validate/fill the arguments. 474 // The Javascript code should validate/fill the arguments.
496 CHECK_EQ(args.Length(), 1); 475 CHECK_EQ(args.Length(), 1);
497 CHECK(args[0]->IsString()); 476 CHECK(args[0]->IsString());
498 // This should be checked by our function routing code. 477 // This should be checked by our function routing code.
499 CHECK(context()->GetAvailability("runtime.connectNative").is_available()); 478 CHECK(context()->GetAvailability("runtime.connectNative").is_available());
500 479
501 content::RenderFrame* render_frame = context()->GetRenderFrame(); 480 content::RenderFrame* render_frame = context()->GetRenderFrame();
502 if (!render_frame) 481 if (!render_frame)
503 return; 482 return;
504 483
505 std::string native_app_name = *v8::String::Utf8Value(args[0]); 484 std::string native_app_name = *v8::String::Utf8Value(args[0]);
506 485
507 int local_id = GetNextLocalId(); 486 int js_id = GetNextJsId();
508 ports_[local_id] = base::MakeUnique<ExtensionPort>(context(), local_id); 487 PortId port_id(context_id_, js_id, true);
488 ports_[js_id] = base::MakeUnique<ExtensionPort>(context(), port_id, js_id);
509 489
510 ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame); 490 {
511 DCHECK(frame_helper); 491 SCOPED_UMA_HISTOGRAM_TIMER(
512 frame_helper->RequestNativeAppPortId( 492 "Extensions.Messaging.GetPortIdSyncTime.NativeApp");
513 native_app_name, 493 render_frame->Send(new ExtensionHostMsg_OpenChannelToNativeApp(
514 base::Bind(&MessagingBindings::SetGlobalPortId, 494 render_frame->GetRoutingID(), native_app_name, port_id));
515 weak_ptr_factory_.GetWeakPtr(), local_id)); 495 }
516 args.GetReturnValue().Set(static_cast<int32_t>(local_id)); 496
497 args.GetReturnValue().Set(static_cast<int32_t>(js_id));
517 } 498 }
518 499
519 void MessagingBindings::OpenChannelToTab( 500 void MessagingBindings::OpenChannelToTab(
520 const v8::FunctionCallbackInfo<v8::Value>& args) { 501 const v8::FunctionCallbackInfo<v8::Value>& args) {
521 content::RenderFrame* render_frame = context()->GetRenderFrame(); 502 content::RenderFrame* render_frame = context()->GetRenderFrame();
522 if (!render_frame) 503 if (!render_frame)
523 return; 504 return;
524 505
525 // tabs_custom_bindings.js unwraps arguments to tabs.connect/sendMessage and 506 // tabs_custom_bindings.js unwraps arguments to tabs.connect/sendMessage and
526 // passes them to OpenChannelToTab, in the following order: 507 // passes them to OpenChannelToTab, in the following order:
527 // - |tab_id| - Positive number that specifies the destination of the channel. 508 // - |tab_id| - Positive number that specifies the destination of the channel.
528 // - |frame_id| - Target frame(s) in the tab where onConnect is dispatched: 509 // - |frame_id| - Target frame(s) in the tab where onConnect is dispatched:
529 // -1 for all frames, 0 for the main frame, >0 for a child frame. 510 // -1 for all frames, 0 for the main frame, >0 for a child frame.
530 // - |extension_id| - ID of the initiating extension. 511 // - |extension_id| - ID of the initiating extension.
531 // - |channel_name| - A user-defined channel name. 512 // - |channel_name| - A user-defined channel name.
532 CHECK(args.Length() == 4); 513 CHECK(args.Length() == 4);
533 CHECK(args[0]->IsInt32()); 514 CHECK(args[0]->IsInt32());
534 CHECK(args[1]->IsInt32()); 515 CHECK(args[1]->IsInt32());
535 CHECK(args[2]->IsString()); 516 CHECK(args[2]->IsString());
536 CHECK(args[3]->IsString()); 517 CHECK(args[3]->IsString());
537 518
538 int local_id = GetNextLocalId(); 519 int js_id = GetNextJsId();
539 ports_[local_id] = base::MakeUnique<ExtensionPort>(context(), local_id); 520 PortId port_id(context_id_, js_id, true);
521 ports_[js_id] = base::MakeUnique<ExtensionPort>(context(), port_id, js_id);
540 522
541 ExtensionMsg_TabTargetConnectionInfo info; 523 ExtensionMsg_TabTargetConnectionInfo info;
542 info.tab_id = args[0]->Int32Value(); 524 info.tab_id = args[0]->Int32Value();
543 info.frame_id = args[1]->Int32Value(); 525 info.frame_id = args[1]->Int32Value();
544 // TODO(devlin): Why is this not part of info? 526 // TODO(devlin): Why is this not part of info?
545 std::string extension_id = *v8::String::Utf8Value(args[2]); 527 std::string extension_id = *v8::String::Utf8Value(args[2]);
546 std::string channel_name = *v8::String::Utf8Value(args[3]); 528 std::string channel_name = *v8::String::Utf8Value(args[3]);
547 529
548 ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame); 530 ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame);
549 DCHECK(frame_helper); 531 DCHECK(frame_helper);
550 frame_helper->RequestTabPortId(
551 info, extension_id, channel_name,
552 base::Bind(&MessagingBindings::SetGlobalPortId,
553 weak_ptr_factory_.GetWeakPtr(), local_id));
554 532
555 args.GetReturnValue().Set(static_cast<int32_t>(local_id)); 533 {
534 SCOPED_UMA_HISTOGRAM_TIMER("Extensions.Messaging.GetPortIdSyncTime.Tab");
535 render_frame->Send(new ExtensionHostMsg_OpenChannelToTab(
536 render_frame->GetRoutingID(), info, extension_id, channel_name,
537 port_id));
538 }
539
540 args.GetReturnValue().Set(static_cast<int32_t>(js_id));
556 } 541 }
557 542
558 void MessagingBindings::ClosePort(int local_port_id, bool force_close) { 543 void MessagingBindings::ClosePort(int js_port_id, bool force_close) {
559 // TODO(robwu): Merge this logic with CloseChannel once the TODO in BindToGC 544 // TODO(robwu): Merge this logic with CloseChannel once the TODO in BindToGC
560 // has been addressed. 545 // has been addressed.
561 auto iter = ports_.find(local_port_id); 546 auto iter = ports_.find(js_port_id);
562 if (iter != ports_.end()) { 547 if (iter != ports_.end()) {
563 std::unique_ptr<ExtensionPort> port = std::move(iter->second); 548 std::unique_ptr<ExtensionPort> port = std::move(iter->second);
564 ports_.erase(iter); 549 ports_.erase(iter);
565 port->Close(force_close); 550 port->Close(force_close);
566 // If the port hasn't been initialized, we can't delete it just yet, because
567 // we need to wait for it to send any pending messages. This is important
568 // to support the flow:
569 // var port = chrome.runtime.connect();
570 // port.postMessage({message});
571 // port.disconnect();
572 if (!port->initialized())
573 disconnected_ports_[port->local_id()] = std::move(port);
574 } 551 }
575 } 552 }
576 553
577 void MessagingBindings::SetGlobalPortId(int local_id, int global_id) { 554 int MessagingBindings::GetNextJsId() { return next_js_id_++; }
578 auto iter = ports_.find(local_id);
579 if (iter != ports_.end()) {
580 iter->second->SetGlobalId(global_id);
581 return;
582 }
583
584 iter = disconnected_ports_.find(local_id);
585 DCHECK(iter != disconnected_ports_.end());
586 iter->second->SetGlobalId(global_id);
587 // Setting the global id dispatches pending messages, so we can delete the
588 // port now.
589 disconnected_ports_.erase(iter);
590 }
591
592 int MessagingBindings::GetNextLocalId() { return next_local_id_++; }
593 555
594 } // namespace extensions 556 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698