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

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

Issue 2547753002: [Extensions] Extension Port Ids and Initialization 2.0 (Closed)
Patch Set: Rob's 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 the channel was opened by this same context, ignore it. This should only
82 if (bindings->GetPortWithGlobalId(opposite_port_id)) 84 // happen when messages are sent to an entire process (rather than a single
85 // frame) as an optimization; otherwise the browser process filters this out.
86 if (bindings->context_id() == target_port_id.context_id)
83 return; // The channel was opened by this same context; ignore it. 87 return; // The channel was opened by this same context; ignore it.
84 88
85 ExtensionPort* port = 89 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. 90 // Remove the port.
89 base::ScopedClosureRunner remove_port( 91 base::ScopedClosureRunner remove_port(
90 base::Bind(&MessagingBindings::RemovePortWithLocalId, 92 base::Bind(&MessagingBindings::RemovePortWithJsId, bindings->GetWeakPtr(),
91 bindings->GetWeakPtr(), local_port_id)); 93 port->js_id()));
92 94
93 v8::Isolate* isolate = script_context->isolate(); 95 v8::Isolate* isolate = script_context->isolate();
94 v8::HandleScope handle_scope(isolate); 96 v8::HandleScope handle_scope(isolate);
95 97
96 98
97 const std::string& source_url_spec = info.source_url.spec(); 99 const std::string& source_url_spec = info.source_url.spec();
98 std::string target_extension_id = script_context->GetExtensionID(); 100 std::string target_extension_id = script_context->GetExtensionID();
99 const Extension* extension = script_context->extension(); 101 const Extension* extension = script_context->extension();
100 102
101 v8::Local<v8::Value> tab = v8::Null(isolate); 103 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) || 136 !ToV8String(isolate, info.source_id.c_str(), &v8_source_id) ||
135 !ToV8String(isolate, target_extension_id.c_str(), 137 !ToV8String(isolate, target_extension_id.c_str(),
136 &v8_target_extension_id) || 138 &v8_target_extension_id) ||
137 !ToV8String(isolate, source_url_spec.c_str(), &v8_source_url_spec)) { 139 !ToV8String(isolate, source_url_spec.c_str(), &v8_source_url_spec)) {
138 NOTREACHED() << "dispatchOnConnect() passed non-string argument"; 140 NOTREACHED() << "dispatchOnConnect() passed non-string argument";
139 return; 141 return;
140 } 142 }
141 143
142 v8::Local<v8::Value> arguments[] = { 144 v8::Local<v8::Value> arguments[] = {
143 // portId 145 // portId
144 v8::Integer::New(isolate, local_port_id), 146 v8::Integer::New(isolate, port->js_id()),
145 // channelName 147 // channelName
146 v8_channel_name, 148 v8_channel_name,
147 // sourceTab 149 // sourceTab
148 tab, 150 tab,
149 // source_frame_id 151 // source_frame_id
150 v8::Integer::New(isolate, source->frame_id), 152 v8::Integer::New(isolate, source->frame_id),
151 // guestProcessId 153 // guestProcessId
152 guest_process_id, 154 guest_process_id,
153 // guestRenderFrameRoutingId 155 // guestRenderFrameRoutingId
154 guest_render_frame_routing_id, 156 guest_render_frame_routing_id,
(...skipping 16 matching lines...) Expand all
171 bool used = retval.As<v8::Boolean>()->Value(); 173 bool used = retval.As<v8::Boolean>()->Value();
172 *port_created |= used; 174 *port_created |= used;
173 if (used) // Port was used; don't remove it. 175 if (used) // Port was used; don't remove it.
174 remove_port.ReplaceClosure(base::Closure()); 176 remove_port.ReplaceClosure(base::Closure());
175 } else { 177 } else {
176 LOG(ERROR) << "Empty return value from dispatchOnConnect."; 178 LOG(ERROR) << "Empty return value from dispatchOnConnect.";
177 } 179 }
178 } 180 }
179 181
180 void DeliverMessageToScriptContext(const Message& message, 182 void DeliverMessageToScriptContext(const Message& message,
181 int global_target_port_id, 183 const PortId& target_port_id,
182 ScriptContext* script_context) { 184 ScriptContext* script_context) {
183 MessagingBindings* bindings = g_messaging_map.Get()[script_context]; 185 MessagingBindings* bindings = g_messaging_map.Get()[script_context];
184 DCHECK(bindings); 186 DCHECK(bindings);
185 ExtensionPort* port = bindings->GetPortWithGlobalId(global_target_port_id); 187 ExtensionPort* port = bindings->GetPortWithId(target_port_id);
186 if (!port) 188 if (!port)
187 return; 189 return;
188 190
189 v8::Isolate* isolate = script_context->isolate(); 191 v8::Isolate* isolate = script_context->isolate();
190 v8::HandleScope handle_scope(isolate); 192 v8::HandleScope handle_scope(isolate);
191 193
192 v8::Local<v8::Value> port_id_handle = 194 v8::Local<v8::Value> port_id_handle =
193 v8::Integer::New(isolate, port->local_id()); 195 v8::Integer::New(isolate, port->js_id());
194 196
195 v8::Local<v8::String> v8_data; 197 v8::Local<v8::String> v8_data;
196 if (!ToV8String(isolate, message.data.c_str(), &v8_data)) 198 if (!ToV8String(isolate, message.data.c_str(), &v8_data))
197 return; 199 return;
198 std::vector<v8::Local<v8::Value>> arguments; 200 std::vector<v8::Local<v8::Value>> arguments;
199 arguments.push_back(v8_data); 201 arguments.push_back(v8_data);
200 arguments.push_back(port_id_handle); 202 arguments.push_back(port_id_handle);
201 203
202 std::unique_ptr<blink::WebScopedUserGesture> web_user_gesture; 204 std::unique_ptr<blink::WebScopedUserGesture> web_user_gesture;
203 std::unique_ptr<blink::WebScopedWindowFocusAllowedIndicator> 205 std::unique_ptr<blink::WebScopedWindowFocusAllowedIndicator>
204 allow_window_focus; 206 allow_window_focus;
205 if (message.user_gesture) { 207 if (message.user_gesture) {
206 web_user_gesture.reset( 208 web_user_gesture.reset(
207 new blink::WebScopedUserGesture(script_context->web_frame())); 209 new blink::WebScopedUserGesture(script_context->web_frame()));
208 210
209 if (script_context->web_frame()) { 211 if (script_context->web_frame()) {
210 blink::WebDocument document = script_context->web_frame()->document(); 212 blink::WebDocument document = script_context->web_frame()->document();
211 allow_window_focus.reset(new blink::WebScopedWindowFocusAllowedIndicator( 213 allow_window_focus.reset(new blink::WebScopedWindowFocusAllowedIndicator(
212 &document)); 214 &document));
213 } 215 }
214 } 216 }
215 217
216 script_context->module_system()->CallModuleMethodSafe( 218 script_context->module_system()->CallModuleMethodSafe(
217 "messaging", "dispatchOnMessage", &arguments); 219 "messaging", "dispatchOnMessage", &arguments);
218 } 220 }
219 221
220 void DispatchOnDisconnectToScriptContext(int global_port_id, 222 void DispatchOnDisconnectToScriptContext(const PortId& port_id,
221 const std::string& error_message, 223 const std::string& error_message,
222 ScriptContext* script_context) { 224 ScriptContext* script_context) {
223 MessagingBindings* bindings = g_messaging_map.Get()[script_context]; 225 MessagingBindings* bindings = g_messaging_map.Get()[script_context];
224 DCHECK(bindings); 226 DCHECK(bindings);
225 ExtensionPort* port = bindings->GetPortWithGlobalId(global_port_id); 227 ExtensionPort* port = bindings->GetPortWithId(port_id);
226 if (!port) 228 if (!port)
227 return; 229 return;
228 230
229 v8::Isolate* isolate = script_context->isolate(); 231 v8::Isolate* isolate = script_context->isolate();
230 v8::HandleScope handle_scope(isolate); 232 v8::HandleScope handle_scope(isolate);
231 233
232 std::vector<v8::Local<v8::Value>> arguments; 234 std::vector<v8::Local<v8::Value>> arguments;
233 arguments.push_back(v8::Integer::New(isolate, port->local_id())); 235 arguments.push_back(v8::Integer::New(isolate, port->js_id()));
234 v8::Local<v8::String> v8_error_message; 236 v8::Local<v8::String> v8_error_message;
235 if (!error_message.empty()) 237 if (!error_message.empty())
236 ToV8String(isolate, error_message.c_str(), &v8_error_message); 238 ToV8String(isolate, error_message.c_str(), &v8_error_message);
237 if (!v8_error_message.IsEmpty()) { 239 if (!v8_error_message.IsEmpty()) {
238 arguments.push_back(v8_error_message); 240 arguments.push_back(v8_error_message);
239 } else { 241 } else {
240 arguments.push_back(v8::Null(isolate)); 242 arguments.push_back(v8::Null(isolate));
241 } 243 }
242 244
243 script_context->module_system()->CallModuleMethodSafe( 245 script_context->module_system()->CallModuleMethodSafe(
244 "messaging", "dispatchOnDisconnect", &arguments); 246 "messaging", "dispatchOnDisconnect", &arguments);
245 } 247 }
246 248
247 } // namespace 249 } // namespace
248 250
249 MessagingBindings::MessagingBindings(ScriptContext* context) 251 MessagingBindings::MessagingBindings(ScriptContext* context)
250 : ObjectBackedNativeHandler(context), weak_ptr_factory_(this) { 252 : ObjectBackedNativeHandler(context),
253 context_id_(base::GenerateGUID()),
254 weak_ptr_factory_(this) {
251 g_messaging_map.Get()[context] = this; 255 g_messaging_map.Get()[context] = this;
252 RouteFunction("CloseChannel", base::Bind(&MessagingBindings::CloseChannel, 256 RouteFunction("CloseChannel", base::Bind(&MessagingBindings::CloseChannel,
253 base::Unretained(this))); 257 base::Unretained(this)));
254 RouteFunction("PostMessage", base::Bind(&MessagingBindings::PostMessage, 258 RouteFunction("PostMessage", base::Bind(&MessagingBindings::PostMessage,
255 base::Unretained(this))); 259 base::Unretained(this)));
256 // TODO(fsamuel, kalman): Move BindToGC out of messaging natives. 260 // TODO(fsamuel, kalman): Move BindToGC out of messaging natives.
257 RouteFunction("BindToGC", base::Bind(&MessagingBindings::BindToGC, 261 RouteFunction("BindToGC", base::Bind(&MessagingBindings::BindToGC,
258 base::Unretained(this))); 262 base::Unretained(this)));
259 RouteFunction("OpenChannelToExtension", "runtime.connect", 263 RouteFunction("OpenChannelToExtension", "runtime.connect",
260 base::Bind(&MessagingBindings::OpenChannelToExtension, 264 base::Bind(&MessagingBindings::OpenChannelToExtension,
(...skipping 18 matching lines...) Expand all
279 ports_created_in_unload_); 283 ports_created_in_unload_);
280 UMA_HISTOGRAM_COUNTS_1000( 284 UMA_HISTOGRAM_COUNTS_1000(
281 "Extensions.Messaging.ExtensionPortsCreated.Normal", 285 "Extensions.Messaging.ExtensionPortsCreated.Normal",
282 ports_created_normal_); 286 ports_created_normal_);
283 } 287 }
284 } 288 }
285 289
286 // static 290 // static
287 void MessagingBindings::ValidateMessagePort( 291 void MessagingBindings::ValidateMessagePort(
288 const ScriptContextSet& context_set, 292 const ScriptContextSet& context_set,
289 int global_port_id, 293 const PortId& port_id,
290 content::RenderFrame* render_frame) { 294 content::RenderFrame* render_frame) {
291 int routing_id = render_frame->GetRoutingID(); 295 int routing_id = render_frame->GetRoutingID();
292 296
293 bool has_port = false; 297 bool has_port = false;
294 context_set.ForEach(render_frame, 298 context_set.ForEach(render_frame,
295 base::Bind(&HasMessagePort, global_port_id, &has_port)); 299 base::Bind(&HasMessagePort, port_id, &has_port));
296 300
297 // A reply is only sent if the port is missing, because the port is assumed to 301 // A reply is only sent if the port is missing, because the port is assumed to
298 // exist unless stated otherwise. 302 // exist unless stated otherwise.
299 if (!has_port) { 303 if (!has_port) {
300 content::RenderThread::Get()->Send( 304 content::RenderThread::Get()->Send(
301 new ExtensionHostMsg_CloseMessagePort(routing_id, 305 new ExtensionHostMsg_CloseMessagePort(routing_id, port_id, false));
302 global_port_id, false));
303 } 306 }
304 } 307 }
305 308
306 // static 309 // static
307 void MessagingBindings::DispatchOnConnect( 310 void MessagingBindings::DispatchOnConnect(
308 const ScriptContextSet& context_set, 311 const ScriptContextSet& context_set,
309 int target_port_id, 312 const PortId& target_port_id,
310 const std::string& channel_name, 313 const std::string& channel_name,
311 const ExtensionMsg_TabConnectionInfo& source, 314 const ExtensionMsg_TabConnectionInfo& source,
312 const ExtensionMsg_ExternalConnectionInfo& info, 315 const ExtensionMsg_ExternalConnectionInfo& info,
313 const std::string& tls_channel_id, 316 const std::string& tls_channel_id,
314 content::RenderFrame* restrict_to_render_frame) { 317 content::RenderFrame* restrict_to_render_frame) {
318 DCHECK(!target_port_id.is_opener);
315 int routing_id = restrict_to_render_frame 319 int routing_id = restrict_to_render_frame
316 ? restrict_to_render_frame->GetRoutingID() 320 ? restrict_to_render_frame->GetRoutingID()
317 : MSG_ROUTING_NONE; 321 : MSG_ROUTING_NONE;
318 bool port_created = false; 322 bool port_created = false;
319 context_set.ForEach( 323 context_set.ForEach(
320 info.target_id, restrict_to_render_frame, 324 info.target_id, restrict_to_render_frame,
321 base::Bind(&DispatchOnConnectToScriptContext, target_port_id, 325 base::Bind(&DispatchOnConnectToScriptContext, target_port_id,
322 channel_name, &source, info, tls_channel_id, &port_created)); 326 channel_name, &source, info, tls_channel_id, &port_created));
323 // Note: |restrict_to_render_frame| may have been deleted at this point! 327 // Note: |restrict_to_render_frame| may have been deleted at this point!
324 328
325 if (port_created) { 329 if (port_created) {
326 content::RenderThread::Get()->Send( 330 content::RenderThread::Get()->Send(
327 new ExtensionHostMsg_OpenMessagePort(routing_id, target_port_id)); 331 new ExtensionHostMsg_OpenMessagePort(routing_id, target_port_id));
328 } else { 332 } else {
329 content::RenderThread::Get()->Send(new ExtensionHostMsg_CloseMessagePort( 333 content::RenderThread::Get()->Send(new ExtensionHostMsg_CloseMessagePort(
330 routing_id, target_port_id, false)); 334 routing_id, target_port_id, false));
331 } 335 }
332 } 336 }
333 337
334 // static 338 // static
335 void MessagingBindings::DeliverMessage( 339 void MessagingBindings::DeliverMessage(
336 const ScriptContextSet& context_set, 340 const ScriptContextSet& context_set,
337 int target_port_id, 341 const PortId& target_port_id,
338 const Message& message, 342 const Message& message,
339 content::RenderFrame* restrict_to_render_frame) { 343 content::RenderFrame* restrict_to_render_frame) {
340 context_set.ForEach( 344 context_set.ForEach(
341 restrict_to_render_frame, 345 restrict_to_render_frame,
342 base::Bind(&DeliverMessageToScriptContext, message, target_port_id)); 346 base::Bind(&DeliverMessageToScriptContext, message, target_port_id));
343 } 347 }
344 348
345 // static 349 // static
346 void MessagingBindings::DispatchOnDisconnect( 350 void MessagingBindings::DispatchOnDisconnect(
347 const ScriptContextSet& context_set, 351 const ScriptContextSet& context_set,
348 int port_id, 352 const PortId& port_id,
349 const std::string& error_message, 353 const std::string& error_message,
350 content::RenderFrame* restrict_to_render_frame) { 354 content::RenderFrame* restrict_to_render_frame) {
351 context_set.ForEach( 355 context_set.ForEach(
352 restrict_to_render_frame, 356 restrict_to_render_frame,
353 base::Bind(&DispatchOnDisconnectToScriptContext, port_id, error_message)); 357 base::Bind(&DispatchOnDisconnectToScriptContext, port_id, error_message));
354 } 358 }
355 359
356 ExtensionPort* MessagingBindings::GetPortWithGlobalId(int id) { 360 ExtensionPort* MessagingBindings::GetPortWithId(const PortId& id) {
357 for (const auto& key_value : ports_) { 361 for (const auto& key_value : ports_) {
358 if (key_value.second->global_id() == id) 362 if (key_value.second->id() == id)
359 return key_value.second.get(); 363 return key_value.second.get();
360 } 364 }
361 return nullptr; 365 return nullptr;
362 } 366 }
363 367
364 ExtensionPort* MessagingBindings::CreateNewPortWithGlobalId(int global_id) { 368 ExtensionPort* MessagingBindings::CreateNewPortWithId(const PortId& id) {
365 int local_id = GetNextLocalId(); 369 int js_id = GetNextJsId();
366 ExtensionPort* port = 370 auto port = base::MakeUnique<ExtensionPort>(context(), id, js_id);
367 ports_ 371 return ports_.insert(std::make_pair(js_id, std::move(port)))
368 .insert(std::make_pair( 372 .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 } 373 }
374 374
375 void MessagingBindings::RemovePortWithLocalId(int local_id) { 375 void MessagingBindings::RemovePortWithJsId(int js_id) {
376 ports_.erase(local_id); 376 ports_.erase(js_id);
377 } 377 }
378 378
379 base::WeakPtr<MessagingBindings> MessagingBindings::GetWeakPtr() { 379 base::WeakPtr<MessagingBindings> MessagingBindings::GetWeakPtr() {
380 return weak_ptr_factory_.GetWeakPtr(); 380 return weak_ptr_factory_.GetWeakPtr();
381 } 381 }
382 382
383 void MessagingBindings::PostMessage( 383 void MessagingBindings::PostMessage(
384 const v8::FunctionCallbackInfo<v8::Value>& args) { 384 const v8::FunctionCallbackInfo<v8::Value>& args) {
385 // Arguments are (int32_t port_id, string message). 385 // Arguments are (int32_t port_id, string message).
386 CHECK(args.Length() == 2); 386 CHECK(args.Length() == 2);
387 CHECK(args[0]->IsInt32()); 387 CHECK(args[0]->IsInt32());
388 CHECK(args[1]->IsString()); 388 CHECK(args[1]->IsString());
389 389
390 int port_id = args[0].As<v8::Int32>()->Value(); 390 int js_port_id = args[0].As<v8::Int32>()->Value();
391 auto iter = ports_.find(port_id); 391 auto iter = ports_.find(js_port_id);
392 if (iter != ports_.end()) { 392 if (iter != ports_.end()) {
393 iter->second->PostExtensionMessage(base::MakeUnique<Message>( 393 iter->second->PostExtensionMessage(base::MakeUnique<Message>(
394 *v8::String::Utf8Value(args[1]), 394 *v8::String::Utf8Value(args[1]),
395 blink::WebUserGestureIndicator::isProcessingUserGesture())); 395 blink::WebUserGestureIndicator::isProcessingUserGesture()));
396 } 396 }
397 } 397 }
398 398
399 void MessagingBindings::CloseChannel( 399 void MessagingBindings::CloseChannel(
400 const v8::FunctionCallbackInfo<v8::Value>& args) { 400 const v8::FunctionCallbackInfo<v8::Value>& args) {
401 // Arguments are (int32_t port_id, bool force_close). 401 // Arguments are (int32_t port_id, bool force_close).
402 CHECK_EQ(2, args.Length()); 402 CHECK_EQ(2, args.Length());
403 CHECK(args[0]->IsInt32()); 403 CHECK(args[0]->IsInt32());
404 CHECK(args[1]->IsBoolean()); 404 CHECK(args[1]->IsBoolean());
405 405
406 int port_id = args[0].As<v8::Int32>()->Value(); 406 int js_port_id = args[0].As<v8::Int32>()->Value();
407 bool force_close = args[1].As<v8::Boolean>()->Value(); 407 bool force_close = args[1].As<v8::Boolean>()->Value();
408 ClosePort(port_id, force_close); 408 ClosePort(js_port_id, force_close);
409 } 409 }
410 410
411 void MessagingBindings::BindToGC( 411 void MessagingBindings::BindToGC(
412 const v8::FunctionCallbackInfo<v8::Value>& args) { 412 const v8::FunctionCallbackInfo<v8::Value>& args) {
413 CHECK(args.Length() == 3); 413 CHECK(args.Length() == 3);
414 CHECK(args[0]->IsObject()); 414 CHECK(args[0]->IsObject());
415 CHECK(args[1]->IsFunction()); 415 CHECK(args[1]->IsFunction());
416 CHECK(args[2]->IsInt32()); 416 CHECK(args[2]->IsInt32());
417 int local_port_id = args[2].As<v8::Int32>()->Value(); 417 int js_port_id = args[2].As<v8::Int32>()->Value();
418 base::Closure fallback = base::Bind(&base::DoNothing); 418 base::Closure fallback = base::Bind(&base::DoNothing);
419 if (local_port_id >= 0) { 419 if (js_port_id >= 0) {
420 // TODO(robwu): Falling back to closing the port shouldn't be needed. If 420 // 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 421 // 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 422 // 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 423 // this fallback (and move BindToGC out of messaging because it is also
424 // used in other places that have nothing to do with messaging...). 424 // used in other places that have nothing to do with messaging...).
425 fallback = base::Bind(&MessagingBindings::ClosePort, 425 fallback = base::Bind(&MessagingBindings::ClosePort,
426 weak_ptr_factory_.GetWeakPtr(), local_port_id, 426 weak_ptr_factory_.GetWeakPtr(), js_port_id,
427 false /* force_close */); 427 false /* force_close */);
428 } 428 }
429 // Destroys itself when the object is GC'd or context is invalidated. 429 // Destroys itself when the object is GC'd or context is invalidated.
430 new GCCallback(context(), args[0].As<v8::Object>(), 430 new GCCallback(context(), args[0].As<v8::Object>(),
431 args[1].As<v8::Function>(), fallback); 431 args[1].As<v8::Function>(), fallback);
432 } 432 }
433 433
434 void MessagingBindings::OpenChannelToExtension( 434 void MessagingBindings::OpenChannelToExtension(
435 const v8::FunctionCallbackInfo<v8::Value>& args) { 435 const v8::FunctionCallbackInfo<v8::Value>& args) {
436 content::RenderFrame* render_frame = context()->GetRenderFrame(); 436 content::RenderFrame* render_frame = context()->GetRenderFrame();
437 if (!render_frame) 437 if (!render_frame)
438 return; 438 return;
439 439
440 // The Javascript code should validate/fill the arguments. 440 // The Javascript code should validate/fill the arguments.
441 CHECK_EQ(args.Length(), 3); 441 CHECK_EQ(args.Length(), 3);
442 CHECK(args[0]->IsString()); 442 CHECK(args[0]->IsString());
443 CHECK(args[1]->IsString()); 443 CHECK(args[1]->IsString());
444 CHECK(args[2]->IsBoolean()); 444 CHECK(args[2]->IsBoolean());
445 445
446 int local_id = GetNextLocalId(); 446 int js_id = GetNextJsId();
447 ports_[local_id] = base::MakeUnique<ExtensionPort>(context(), local_id); 447 PortId port_id(context_id_, js_id, true);
448 ports_[js_id] = base::MakeUnique<ExtensionPort>(context(), port_id, js_id);
448 449
449 ExtensionMsg_ExternalConnectionInfo info; 450 ExtensionMsg_ExternalConnectionInfo info;
450 // For messaging APIs, hosted apps should be considered a web page so hide 451 // For messaging APIs, hosted apps should be considered a web page so hide
451 // its extension ID. 452 // its extension ID.
452 const Extension* extension = context()->extension(); 453 const Extension* extension = context()->extension();
453 if (extension && !extension->is_hosted_app()) 454 if (extension && !extension->is_hosted_app())
454 info.source_id = extension->id(); 455 info.source_id = extension->id();
455 456
456 info.target_id = *v8::String::Utf8Value(args[0]); 457 info.target_id = *v8::String::Utf8Value(args[0]);
457 info.source_url = context()->url(); 458 info.source_url = context()->url();
458 std::string channel_name = *v8::String::Utf8Value(args[1]); 459 std::string channel_name = *v8::String::Utf8Value(args[1]);
459 // TODO(devlin): Why is this not part of info? 460 // TODO(devlin): Why is this not part of info?
460 bool include_tls_channel_id = 461 bool include_tls_channel_id =
461 args.Length() > 2 ? args[2]->BooleanValue() : false; 462 args.Length() > 2 ? args[2]->BooleanValue() : false;
462 463
463 ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame); 464 {
464 DCHECK(frame_helper); 465 SCOPED_UMA_HISTOGRAM_TIMER(
465 466 "Extensions.Messaging.GetPortIdSyncTime.Extension");
466 blink::WebLocalFrame* web_frame = render_frame->GetWebFrame(); 467 render_frame->Send(new ExtensionHostMsg_OpenChannelToExtension(
467 // If the frame is unloading, we need to assign the port id synchronously to 468 render_frame->GetRoutingID(), info, channel_name,
468 // avoid dropping the message on the floor; see crbug.com/660706. 469 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 } 470 }
489 471
490 args.GetReturnValue().Set(static_cast<int32_t>(local_id)); 472 args.GetReturnValue().Set(static_cast<int32_t>(js_id));
491 } 473 }
492 474
493 void MessagingBindings::OpenChannelToNativeApp( 475 void MessagingBindings::OpenChannelToNativeApp(
494 const v8::FunctionCallbackInfo<v8::Value>& args) { 476 const v8::FunctionCallbackInfo<v8::Value>& args) {
495 // The Javascript code should validate/fill the arguments. 477 // The Javascript code should validate/fill the arguments.
496 CHECK_EQ(args.Length(), 1); 478 CHECK_EQ(args.Length(), 1);
497 CHECK(args[0]->IsString()); 479 CHECK(args[0]->IsString());
498 // This should be checked by our function routing code. 480 // This should be checked by our function routing code.
499 CHECK(context()->GetAvailability("runtime.connectNative").is_available()); 481 CHECK(context()->GetAvailability("runtime.connectNative").is_available());
500 482
501 content::RenderFrame* render_frame = context()->GetRenderFrame(); 483 content::RenderFrame* render_frame = context()->GetRenderFrame();
502 if (!render_frame) 484 if (!render_frame)
503 return; 485 return;
504 486
505 std::string native_app_name = *v8::String::Utf8Value(args[0]); 487 std::string native_app_name = *v8::String::Utf8Value(args[0]);
506 488
507 int local_id = GetNextLocalId(); 489 int js_id = GetNextJsId();
508 ports_[local_id] = base::MakeUnique<ExtensionPort>(context(), local_id); 490 PortId port_id(context_id_, js_id, true);
491 ports_[js_id] = base::MakeUnique<ExtensionPort>(context(), port_id, js_id);
509 492
510 ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame); 493 {
511 DCHECK(frame_helper); 494 SCOPED_UMA_HISTOGRAM_TIMER(
512 frame_helper->RequestNativeAppPortId( 495 "Extensions.Messaging.GetPortIdSyncTime.NativeApp");
513 native_app_name, 496 render_frame->Send(new ExtensionHostMsg_OpenChannelToNativeApp(
514 base::Bind(&MessagingBindings::SetGlobalPortId, 497 render_frame->GetRoutingID(), native_app_name, port_id));
515 weak_ptr_factory_.GetWeakPtr(), local_id)); 498 }
516 args.GetReturnValue().Set(static_cast<int32_t>(local_id)); 499
500 args.GetReturnValue().Set(static_cast<int32_t>(js_id));
517 } 501 }
518 502
519 void MessagingBindings::OpenChannelToTab( 503 void MessagingBindings::OpenChannelToTab(
520 const v8::FunctionCallbackInfo<v8::Value>& args) { 504 const v8::FunctionCallbackInfo<v8::Value>& args) {
521 content::RenderFrame* render_frame = context()->GetRenderFrame(); 505 content::RenderFrame* render_frame = context()->GetRenderFrame();
522 if (!render_frame) 506 if (!render_frame)
523 return; 507 return;
524 508
525 // tabs_custom_bindings.js unwraps arguments to tabs.connect/sendMessage and 509 // tabs_custom_bindings.js unwraps arguments to tabs.connect/sendMessage and
526 // passes them to OpenChannelToTab, in the following order: 510 // passes them to OpenChannelToTab, in the following order:
527 // - |tab_id| - Positive number that specifies the destination of the channel. 511 // - |tab_id| - Positive number that specifies the destination of the channel.
528 // - |frame_id| - Target frame(s) in the tab where onConnect is dispatched: 512 // - |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. 513 // -1 for all frames, 0 for the main frame, >0 for a child frame.
530 // - |extension_id| - ID of the initiating extension. 514 // - |extension_id| - ID of the initiating extension.
531 // - |channel_name| - A user-defined channel name. 515 // - |channel_name| - A user-defined channel name.
532 CHECK(args.Length() == 4); 516 CHECK(args.Length() == 4);
533 CHECK(args[0]->IsInt32()); 517 CHECK(args[0]->IsInt32());
534 CHECK(args[1]->IsInt32()); 518 CHECK(args[1]->IsInt32());
535 CHECK(args[2]->IsString()); 519 CHECK(args[2]->IsString());
536 CHECK(args[3]->IsString()); 520 CHECK(args[3]->IsString());
537 521
538 int local_id = GetNextLocalId(); 522 int js_id = GetNextJsId();
539 ports_[local_id] = base::MakeUnique<ExtensionPort>(context(), local_id); 523 PortId port_id(context_id_, js_id, true);
524 ports_[js_id] = base::MakeUnique<ExtensionPort>(context(), port_id, js_id);
540 525
541 ExtensionMsg_TabTargetConnectionInfo info; 526 ExtensionMsg_TabTargetConnectionInfo info;
542 info.tab_id = args[0]->Int32Value(); 527 info.tab_id = args[0]->Int32Value();
543 info.frame_id = args[1]->Int32Value(); 528 info.frame_id = args[1]->Int32Value();
544 // TODO(devlin): Why is this not part of info? 529 // TODO(devlin): Why is this not part of info?
545 std::string extension_id = *v8::String::Utf8Value(args[2]); 530 std::string extension_id = *v8::String::Utf8Value(args[2]);
546 std::string channel_name = *v8::String::Utf8Value(args[3]); 531 std::string channel_name = *v8::String::Utf8Value(args[3]);
547 532
548 ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame); 533 ExtensionFrameHelper* frame_helper = ExtensionFrameHelper::Get(render_frame);
549 DCHECK(frame_helper); 534 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 535
555 args.GetReturnValue().Set(static_cast<int32_t>(local_id)); 536 {
537 SCOPED_UMA_HISTOGRAM_TIMER("Extensions.Messaging.GetPortIdSyncTime.Tab");
538 render_frame->Send(new ExtensionHostMsg_OpenChannelToTab(
539 render_frame->GetRoutingID(), info, extension_id, channel_name,
540 port_id));
541 }
542
543 args.GetReturnValue().Set(static_cast<int32_t>(js_id));
556 } 544 }
557 545
558 void MessagingBindings::ClosePort(int local_port_id, bool force_close) { 546 void MessagingBindings::ClosePort(int js_port_id, bool force_close) {
559 // TODO(robwu): Merge this logic with CloseChannel once the TODO in BindToGC 547 // TODO(robwu): Merge this logic with CloseChannel once the TODO in BindToGC
560 // has been addressed. 548 // has been addressed.
561 auto iter = ports_.find(local_port_id); 549 auto iter = ports_.find(js_port_id);
562 if (iter != ports_.end()) { 550 if (iter != ports_.end()) {
563 std::unique_ptr<ExtensionPort> port = std::move(iter->second); 551 std::unique_ptr<ExtensionPort> port = std::move(iter->second);
564 ports_.erase(iter); 552 ports_.erase(iter);
565 port->Close(force_close); 553 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 } 554 }
575 } 555 }
576 556
577 void MessagingBindings::SetGlobalPortId(int local_id, int global_id) { 557 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 558
594 } // namespace extensions 559 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698