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

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

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

Powered by Google App Engine
This is Rietveld 408576698