Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / extensions / api / messaging / message_service.cc
blob5c1a219e7613f18f482fc6106e72ed725d4f2cd0
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/api/messaging/message_service.h"
7 #include "base/atomic_sequence_num.h"
8 #include "base/bind.h"
9 #include "base/callback.h"
10 #include "base/json/json_writer.h"
11 #include "base/lazy_instance.h"
12 #include "base/metrics/histogram.h"
13 #include "base/prefs/pref_service.h"
14 #include "base/stl_util.h"
15 #include "chrome/browser/chrome_notification_types.h"
16 #include "chrome/browser/extensions/api/messaging/extension_message_port.h"
17 #include "chrome/browser/extensions/api/messaging/incognito_connectability.h"
18 #include "chrome/browser/extensions/api/messaging/native_message_port.h"
19 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
20 #include "chrome/browser/extensions/extension_service.h"
21 #include "chrome/browser/extensions/extension_tab_util.h"
22 #include "chrome/browser/extensions/extension_util.h"
23 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/browser/tab_contents/tab_util.h"
25 #include "components/guest_view/common/guest_view_constants.h"
26 #include "content/public/browser/browser_thread.h"
27 #include "content/public/browser/notification_service.h"
28 #include "content/public/browser/render_frame_host.h"
29 #include "content/public/browser/render_process_host.h"
30 #include "content/public/browser/render_view_host.h"
31 #include "content/public/browser/render_widget_host.h"
32 #include "content/public/browser/render_widget_host_view.h"
33 #include "content/public/browser/site_instance.h"
34 #include "content/public/browser/web_contents.h"
35 #include "content/public/common/child_process_host.h"
36 #include "extensions/browser/event_router.h"
37 #include "extensions/browser/extension_host.h"
38 #include "extensions/browser/extension_registry.h"
39 #include "extensions/browser/extension_system.h"
40 #include "extensions/browser/extension_util.h"
41 #include "extensions/browser/extensions_browser_client.h"
42 #include "extensions/browser/guest_view/web_view/web_view_guest.h"
43 #include "extensions/browser/lazy_background_task_queue.h"
44 #include "extensions/browser/pref_names.h"
45 #include "extensions/browser/process_manager.h"
46 #include "extensions/common/extension.h"
47 #include "extensions/common/manifest_constants.h"
48 #include "extensions/common/manifest_handlers/background_info.h"
49 #include "extensions/common/manifest_handlers/externally_connectable.h"
50 #include "extensions/common/manifest_handlers/incognito_info.h"
51 #include "extensions/common/permissions/permissions_data.h"
52 #include "net/base/completion_callback.h"
53 #include "url/gurl.h"
55 using content::BrowserContext;
56 using content::BrowserThread;
57 using content::SiteInstance;
58 using content::WebContents;
60 // Since we have 2 ports for every channel, we just index channels by half the
61 // port ID.
62 #define GET_CHANNEL_ID(port_id) ((port_id) / 2)
63 #define GET_CHANNEL_OPENER_ID(channel_id) ((channel_id) * 2)
64 #define GET_CHANNEL_RECEIVERS_ID(channel_id) ((channel_id) * 2 + 1)
66 // Port1 is always even, port2 is always odd.
67 #define IS_OPENER_PORT_ID(port_id) (((port_id) & 1) == 0)
69 // Change even to odd and vice versa, to get the other side of a given channel.
70 #define GET_OPPOSITE_PORT_ID(source_port_id) ((source_port_id) ^ 1)
72 namespace extensions {
74 MessageService::PolicyPermission MessageService::IsNativeMessagingHostAllowed(
75 const PrefService* pref_service,
76 const std::string& native_host_name) {
77 DCHECK_CURRENTLY_ON(BrowserThread::UI);
79 PolicyPermission allow_result = ALLOW_ALL;
80 if (pref_service->IsManagedPreference(
81 pref_names::kNativeMessagingUserLevelHosts)) {
82 if (!pref_service->GetBoolean(pref_names::kNativeMessagingUserLevelHosts))
83 allow_result = ALLOW_SYSTEM_ONLY;
86 // All native messaging hosts are allowed if there is no blacklist.
87 if (!pref_service->IsManagedPreference(pref_names::kNativeMessagingBlacklist))
88 return allow_result;
89 const base::ListValue* blacklist =
90 pref_service->GetList(pref_names::kNativeMessagingBlacklist);
91 if (!blacklist)
92 return allow_result;
94 // Check if the name or the wildcard is in the blacklist.
95 base::StringValue name_value(native_host_name);
96 base::StringValue wildcard_value("*");
97 if (blacklist->Find(name_value) == blacklist->end() &&
98 blacklist->Find(wildcard_value) == blacklist->end()) {
99 return allow_result;
102 // The native messaging host is blacklisted. Check the whitelist.
103 if (pref_service->IsManagedPreference(
104 pref_names::kNativeMessagingWhitelist)) {
105 const base::ListValue* whitelist =
106 pref_service->GetList(pref_names::kNativeMessagingWhitelist);
107 if (whitelist && whitelist->Find(name_value) != whitelist->end())
108 return allow_result;
111 return DISALLOW;
114 const char kReceivingEndDoesntExistError[] =
115 "Could not establish connection. Receiving end does not exist.";
116 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
117 const char kMissingPermissionError[] =
118 "Access to native messaging requires nativeMessaging permission.";
119 const char kProhibitedByPoliciesError[] =
120 "Access to the native messaging host was disabled by the system "
121 "administrator.";
122 #endif
124 struct MessageService::MessageChannel {
125 scoped_ptr<MessagePort> opener;
126 scoped_ptr<MessagePort> receiver;
129 struct MessageService::OpenChannelParams {
130 int source_process_id;
131 scoped_ptr<base::DictionaryValue> source_tab;
132 int source_frame_id;
133 int target_frame_id;
134 scoped_ptr<MessagePort> receiver;
135 int receiver_port_id;
136 std::string source_extension_id;
137 std::string target_extension_id;
138 GURL source_url;
139 std::string channel_name;
140 bool include_tls_channel_id;
141 std::string tls_channel_id;
142 bool include_guest_process_info;
144 // Takes ownership of receiver.
145 OpenChannelParams(int source_process_id,
146 scoped_ptr<base::DictionaryValue> source_tab,
147 int source_frame_id,
148 int target_frame_id,
149 MessagePort* receiver,
150 int receiver_port_id,
151 const std::string& source_extension_id,
152 const std::string& target_extension_id,
153 const GURL& source_url,
154 const std::string& channel_name,
155 bool include_tls_channel_id,
156 bool include_guest_process_info)
157 : source_process_id(source_process_id),
158 source_frame_id(source_frame_id),
159 target_frame_id(target_frame_id),
160 receiver(receiver),
161 receiver_port_id(receiver_port_id),
162 source_extension_id(source_extension_id),
163 target_extension_id(target_extension_id),
164 source_url(source_url),
165 channel_name(channel_name),
166 include_tls_channel_id(include_tls_channel_id),
167 include_guest_process_info(include_guest_process_info) {
168 if (source_tab)
169 this->source_tab = source_tab.Pass();
172 private:
173 DISALLOW_COPY_AND_ASSIGN(OpenChannelParams);
176 namespace {
178 static base::StaticAtomicSequenceNumber g_next_channel_id;
180 static content::RenderProcessHost* GetExtensionProcess(
181 BrowserContext* context,
182 const std::string& extension_id) {
183 scoped_refptr<SiteInstance> site_instance =
184 ProcessManager::Get(context)->GetSiteInstanceForURL(
185 Extension::GetBaseURLFromExtensionId(extension_id));
186 return site_instance->HasProcess() ? site_instance->GetProcess() : NULL;
189 } // namespace
191 content::RenderProcessHost*
192 MessageService::MessagePort::GetRenderProcessHost() {
193 return NULL;
196 // static
197 void MessageService::AllocatePortIdPair(int* port1, int* port2) {
198 DCHECK_CURRENTLY_ON(BrowserThread::IO);
200 unsigned channel_id =
201 static_cast<unsigned>(g_next_channel_id.GetNext()) % (kint32max/2);
202 unsigned port1_id = channel_id * 2;
203 unsigned port2_id = channel_id * 2 + 1;
205 // Sanity checks to make sure our channel<->port converters are correct.
206 DCHECK(IS_OPENER_PORT_ID(port1_id));
207 DCHECK_EQ(GET_OPPOSITE_PORT_ID(port1_id), port2_id);
208 DCHECK_EQ(GET_OPPOSITE_PORT_ID(port2_id), port1_id);
209 DCHECK_EQ(GET_CHANNEL_ID(port1_id), GET_CHANNEL_ID(port2_id));
210 DCHECK_EQ(GET_CHANNEL_ID(port1_id), channel_id);
211 DCHECK_EQ(GET_CHANNEL_OPENER_ID(channel_id), port1_id);
212 DCHECK_EQ(GET_CHANNEL_RECEIVERS_ID(channel_id), port2_id);
214 *port1 = port1_id;
215 *port2 = port2_id;
218 MessageService::MessageService(BrowserContext* context)
219 : lazy_background_task_queue_(
220 LazyBackgroundTaskQueue::Get(context)),
221 weak_factory_(this) {
222 DCHECK_CURRENTLY_ON(BrowserThread::UI);
224 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
225 content::NotificationService::AllBrowserContextsAndSources());
226 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
227 content::NotificationService::AllBrowserContextsAndSources());
230 MessageService::~MessageService() {
231 DCHECK_CURRENTLY_ON(BrowserThread::UI);
233 STLDeleteContainerPairSecondPointers(channels_.begin(), channels_.end());
234 channels_.clear();
237 static base::LazyInstance<BrowserContextKeyedAPIFactory<MessageService> >
238 g_factory = LAZY_INSTANCE_INITIALIZER;
240 // static
241 BrowserContextKeyedAPIFactory<MessageService>*
242 MessageService::GetFactoryInstance() {
243 return g_factory.Pointer();
246 // static
247 MessageService* MessageService::Get(BrowserContext* context) {
248 return BrowserContextKeyedAPIFactory<MessageService>::Get(context);
251 void MessageService::OpenChannelToExtension(
252 int source_process_id, int source_routing_id, int receiver_port_id,
253 const std::string& source_extension_id,
254 const std::string& target_extension_id,
255 const GURL& source_url,
256 const std::string& channel_name,
257 bool include_tls_channel_id) {
258 DCHECK_CURRENTLY_ON(BrowserThread::UI);
260 content::RenderProcessHost* source =
261 content::RenderProcessHost::FromID(source_process_id);
262 if (!source)
263 return;
264 BrowserContext* context = source->GetBrowserContext();
266 ExtensionRegistry* registry = ExtensionRegistry::Get(context);
267 const Extension* target_extension =
268 registry->enabled_extensions().GetByID(target_extension_id);
269 if (!target_extension) {
270 DispatchOnDisconnect(
271 source, receiver_port_id, kReceivingEndDoesntExistError);
272 return;
275 bool is_web_connection = false;
277 if (source_extension_id != target_extension_id) {
278 // It's an external connection. Check the externally_connectable manifest
279 // key if it's present. If it's not, we allow connection from any extension
280 // but not webpages.
281 ExternallyConnectableInfo* externally_connectable =
282 static_cast<ExternallyConnectableInfo*>(
283 target_extension->GetManifestData(
284 manifest_keys::kExternallyConnectable));
285 bool is_externally_connectable = false;
287 if (externally_connectable) {
288 if (source_extension_id.empty()) {
289 // No source extension ID so the source was a web page. Check that the
290 // URL matches.
291 is_web_connection = true;
292 is_externally_connectable =
293 externally_connectable->matches.MatchesURL(source_url);
294 // Only include the TLS channel ID for externally connected web pages.
295 include_tls_channel_id &=
296 is_externally_connectable &&
297 externally_connectable->accepts_tls_channel_id;
298 } else {
299 // Source extension ID so the source was an extension. Check that the
300 // extension matches.
301 is_externally_connectable =
302 externally_connectable->IdCanConnect(source_extension_id);
304 } else {
305 // Default behaviour. Any extension, no webpages.
306 is_externally_connectable = !source_extension_id.empty();
309 if (!is_externally_connectable) {
310 // Important: use kReceivingEndDoesntExistError here so that we don't
311 // leak information about this extension to callers. This way it's
312 // indistinguishable from the extension just not existing.
313 DispatchOnDisconnect(
314 source, receiver_port_id, kReceivingEndDoesntExistError);
315 return;
319 WebContents* source_contents = tab_util::GetWebContentsByFrameID(
320 source_process_id, source_routing_id);
322 bool include_guest_process_info = false;
324 // Include info about the opener's tab (if it was a tab).
325 scoped_ptr<base::DictionaryValue> source_tab;
326 int source_frame_id = -1;
327 if (source_contents && ExtensionTabUtil::GetTabId(source_contents) >= 0) {
328 // Only the tab id is useful to platform apps for internal use. The
329 // unnecessary bits will be stripped out in
330 // MessagingBindings::DispatchOnConnect().
331 source_tab.reset(ExtensionTabUtil::CreateTabValue(source_contents));
333 content::RenderFrameHost* rfh =
334 content::RenderFrameHost::FromID(source_process_id, source_routing_id);
335 // Main frame's frameId is 0.
336 if (rfh)
337 source_frame_id = !rfh->GetParent() ? 0 : source_routing_id;
338 } else {
339 // Check to see if it was a WebView making the request.
340 // Sending messages from WebViews to extensions breaks webview isolation,
341 // so only allow component extensions to receive messages from WebViews.
342 bool is_web_view = !!WebViewGuest::FromWebContents(source_contents);
343 if (is_web_view && extensions::Manifest::IsComponentLocation(
344 target_extension->location())) {
345 include_guest_process_info = true;
346 auto* rfh = content::RenderFrameHost::FromID(source_process_id,
347 source_routing_id);
348 // Include |source_frame_id| so that we can retrieve the guest's frame
349 // routing id in OpenChannelImpl.
350 if (rfh)
351 source_frame_id = source_routing_id;
355 scoped_ptr<OpenChannelParams> params(new OpenChannelParams(
356 source_process_id, source_tab.Pass(), source_frame_id,
357 -1, // no target_frame_id for a channel to an extension/background page.
358 nullptr, receiver_port_id, source_extension_id, target_extension_id,
359 source_url, channel_name, include_tls_channel_id,
360 include_guest_process_info));
362 pending_incognito_channels_[GET_CHANNEL_ID(params->receiver_port_id)] =
363 PendingMessagesQueue();
364 if (context->IsOffTheRecord() &&
365 !util::IsIncognitoEnabled(target_extension_id, context)) {
366 // Give the user a chance to accept an incognito connection from the web if
367 // they haven't already, with the conditions:
368 // - Only for spanning-mode incognito. We don't want the complication of
369 // spinning up an additional process here which might need to do some
370 // setup that we're not expecting.
371 // - Only for extensions that can't normally be enabled in incognito, since
372 // that surface (e.g. chrome://extensions) should be the only one for
373 // enabling in incognito. In practice this means platform apps only.
374 if (!is_web_connection || IncognitoInfo::IsSplitMode(target_extension) ||
375 util::CanBeIncognitoEnabled(target_extension)) {
376 OnOpenChannelAllowed(params.Pass(), false);
377 return;
380 // If the target extension isn't even listening for connect/message events,
381 // there is no need to go any further and the connection should be
382 // rejected without showing a prompt. See http://crbug.com/442497
383 EventRouter* event_router = EventRouter::Get(context);
384 const char* const events[] = {"runtime.onConnectExternal",
385 "runtime.onMessageExternal",
386 "extension.onRequestExternal",
387 nullptr};
388 bool has_event_listener = false;
389 for (const char* const* event = events; *event; event++) {
390 has_event_listener |=
391 event_router->ExtensionHasEventListener(target_extension_id, *event);
393 if (!has_event_listener) {
394 OnOpenChannelAllowed(params.Pass(), false);
395 return;
398 // This check may show a dialog.
399 IncognitoConnectability::Get(context)
400 ->Query(target_extension, source_contents, source_url,
401 base::Bind(&MessageService::OnOpenChannelAllowed,
402 weak_factory_.GetWeakPtr(), base::Passed(&params)));
403 return;
406 OnOpenChannelAllowed(params.Pass(), true);
409 void MessageService::OpenChannelToNativeApp(
410 int source_process_id,
411 int source_routing_id,
412 int receiver_port_id,
413 const std::string& source_extension_id,
414 const std::string& native_app_name) {
415 DCHECK_CURRENTLY_ON(BrowserThread::UI);
417 content::RenderProcessHost* source =
418 content::RenderProcessHost::FromID(source_process_id);
419 if (!source)
420 return;
422 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
423 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
424 ExtensionService* extension_service =
425 ExtensionSystem::Get(profile)->extension_service();
426 bool has_permission = false;
427 if (extension_service) {
428 const Extension* extension =
429 extension_service->GetExtensionById(source_extension_id, false);
430 has_permission = extension &&
431 extension->permissions_data()->HasAPIPermission(
432 APIPermission::kNativeMessaging);
435 if (!has_permission) {
436 DispatchOnDisconnect(source, receiver_port_id, kMissingPermissionError);
437 return;
440 PrefService* pref_service = profile->GetPrefs();
442 // Verify that the host is not blocked by policies.
443 PolicyPermission policy_permission =
444 IsNativeMessagingHostAllowed(pref_service, native_app_name);
445 if (policy_permission == DISALLOW) {
446 DispatchOnDisconnect(source, receiver_port_id, kProhibitedByPoliciesError);
447 return;
450 scoped_ptr<MessageChannel> channel(new MessageChannel());
451 channel->opener.reset(new ExtensionMessagePort(source, MSG_ROUTING_CONTROL,
452 source_extension_id));
454 // Get handle of the native view and pass it to the native messaging host.
455 content::RenderFrameHost* render_frame_host =
456 content::RenderFrameHost::FromID(source_process_id, source_routing_id);
457 gfx::NativeView native_view =
458 render_frame_host ? render_frame_host->GetNativeView() : nullptr;
460 std::string error = kReceivingEndDoesntExistError;
461 scoped_ptr<NativeMessageHost> native_host = NativeMessageHost::Create(
462 native_view,
463 source_extension_id,
464 native_app_name,
465 policy_permission == ALLOW_ALL,
466 &error);
468 // Abandon the channel.
469 if (!native_host.get()) {
470 LOG(ERROR) << "Failed to create native process.";
471 DispatchOnDisconnect(source, receiver_port_id, error);
472 return;
474 channel->receiver.reset(new NativeMessagePort(
475 weak_factory_.GetWeakPtr(), receiver_port_id, native_host.Pass()));
477 // Keep the opener alive until the channel is closed.
478 channel->opener->IncrementLazyKeepaliveCount();
480 AddChannel(channel.release(), receiver_port_id);
481 #else // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
482 const char kNativeMessagingNotSupportedError[] =
483 "Native Messaging is not supported on this platform.";
484 DispatchOnDisconnect(
485 source, receiver_port_id, kNativeMessagingNotSupportedError);
486 #endif // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
489 void MessageService::OpenChannelToTab(int source_process_id,
490 int receiver_port_id,
491 int tab_id,
492 int frame_id,
493 const std::string& extension_id,
494 const std::string& channel_name) {
495 DCHECK_CURRENTLY_ON(BrowserThread::UI);
497 content::RenderProcessHost* source =
498 content::RenderProcessHost::FromID(source_process_id);
499 if (!source)
500 return;
501 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
503 WebContents* contents = NULL;
504 scoped_ptr<MessagePort> receiver;
505 if (!ExtensionTabUtil::GetTabById(tab_id, profile, true, NULL, NULL,
506 &contents, NULL) ||
507 contents->GetController().NeedsReload()) {
508 // The tab isn't loaded yet. Don't attempt to connect.
509 DispatchOnDisconnect(
510 source, receiver_port_id, kReceivingEndDoesntExistError);
511 return;
514 int receiver_routing_id;
515 if (frame_id > 0) {
516 // Positive frame ID is child frame.
517 int receiver_process_id = contents->GetRenderProcessHost()->GetID();
518 if (!content::RenderFrameHost::FromID(receiver_process_id, frame_id)) {
519 // Frame does not exist.
520 DispatchOnDisconnect(
521 source, receiver_port_id, kReceivingEndDoesntExistError);
522 return;
524 receiver_routing_id = frame_id;
525 } else if (frame_id == 0) {
526 // Frame ID 0 is main frame.
527 receiver_routing_id = contents->GetMainFrame()->GetRoutingID();
528 } else {
529 DCHECK_EQ(-1, frame_id);
530 // If the frame ID is not set (i.e. -1), then the channel has to be opened
531 // in every frame.
532 // TODO(robwu): Update logic so that frames that are not hosted in the main
533 // frame's process can also receive the port.
534 receiver_routing_id = MSG_ROUTING_CONTROL;
536 receiver.reset(new ExtensionMessagePort(contents->GetRenderProcessHost(),
537 receiver_routing_id, extension_id));
539 const Extension* extension = nullptr;
540 if (!extension_id.empty()) {
541 // Source extension == target extension so the extension must exist, or
542 // where did the IPC come from?
543 extension = ExtensionRegistry::Get(profile)->enabled_extensions().GetByID(
544 extension_id);
545 DCHECK(extension);
548 scoped_ptr<OpenChannelParams> params(new OpenChannelParams(
549 source_process_id,
550 scoped_ptr<base::DictionaryValue>(), // Source tab doesn't make sense
551 // for opening to tabs.
552 -1, // If there is no tab, then there is no frame either.
553 frame_id,
554 receiver.release(), receiver_port_id, extension_id, extension_id,
555 GURL(), // Source URL doesn't make sense for opening to tabs.
556 channel_name,
557 false, // Connections to tabs don't get TLS channel IDs.
558 false)); // Connections to tabs aren't webview guests.
559 OpenChannelImpl(contents->GetBrowserContext(), params.Pass(), extension,
560 false /* did_enqueue */);
563 void MessageService::OpenChannelImpl(BrowserContext* browser_context,
564 scoped_ptr<OpenChannelParams> params,
565 const Extension* target_extension,
566 bool did_enqueue) {
567 DCHECK_CURRENTLY_ON(BrowserThread::UI);
568 DCHECK_EQ(target_extension != nullptr, !params->target_extension_id.empty());
570 content::RenderProcessHost* source =
571 content::RenderProcessHost::FromID(params->source_process_id);
572 if (!source)
573 return; // Closed while in flight.
575 if (!params->receiver || !params->receiver->GetRenderProcessHost()) {
576 DispatchOnDisconnect(source, params->receiver_port_id,
577 kReceivingEndDoesntExistError);
578 return;
581 MessageChannel* channel(new MessageChannel);
582 channel->opener.reset(new ExtensionMessagePort(source, MSG_ROUTING_CONTROL,
583 params->source_extension_id));
584 channel->receiver.reset(params->receiver.release());
585 AddChannel(channel, params->receiver_port_id);
587 int guest_process_id = content::ChildProcessHost::kInvalidUniqueID;
588 int guest_render_frame_routing_id = MSG_ROUTING_NONE;
589 if (params->include_guest_process_info) {
590 guest_process_id = params->source_process_id;
591 guest_render_frame_routing_id = params->source_frame_id;
592 auto* guest_rfh = content::RenderFrameHost::FromID(
593 guest_process_id, guest_render_frame_routing_id);
594 // Reset the |source_frame_id| parameter.
595 params->source_frame_id = -1;
597 DCHECK(guest_rfh == nullptr ||
598 WebViewGuest::FromWebContents(
599 WebContents::FromRenderFrameHost(guest_rfh)) != nullptr);
602 // Send the connect event to the receiver. Give it the opener's port ID (the
603 // opener has the opposite port ID).
604 channel->receiver->DispatchOnConnect(
605 params->receiver_port_id, params->channel_name, params->source_tab.Pass(),
606 params->source_frame_id, params->target_frame_id, guest_process_id,
607 guest_render_frame_routing_id, params->source_extension_id,
608 params->target_extension_id, params->source_url, params->tls_channel_id);
610 // Report the event to the event router, if the target is an extension.
612 // First, determine what event this will be (runtime.onConnect vs
613 // runtime.onMessage etc), and what the event target is (view vs background
614 // page etc).
616 // Yes - even though this is opening a channel, they may actually be
617 // runtime.onRequest/onMessage events because those single-use events are
618 // built using the connect framework (see messaging.js).
620 // Likewise, if you're wondering about native messaging events, these are
621 // only initiated *by* the extension, so aren't really events, just the
622 // endpoint of a communication channel.
623 if (target_extension) {
624 events::HistogramValue histogram_value = events::UNKNOWN;
625 bool is_external =
626 params->source_extension_id != params->target_extension_id;
627 if (params->channel_name == "chrome.runtime.onRequest") {
628 histogram_value = is_external ? events::RUNTIME_ON_REQUEST_EXTERNAL
629 : events::RUNTIME_ON_REQUEST;
630 } else if (params->channel_name == "chrome.runtime.onMessage") {
631 histogram_value = is_external ? events::RUNTIME_ON_MESSAGE_EXTERNAL
632 : events::RUNTIME_ON_MESSAGE;
633 } else {
634 histogram_value = is_external ? events::RUNTIME_ON_CONNECT_EXTERNAL
635 : events::RUNTIME_ON_CONNECT;
637 EventRouter::Get(browser_context)
638 ->ReportEvent(histogram_value, target_extension, did_enqueue);
641 // Keep both ends of the channel alive until the channel is closed.
642 channel->opener->IncrementLazyKeepaliveCount();
643 channel->receiver->IncrementLazyKeepaliveCount();
646 void MessageService::AddChannel(MessageChannel* channel, int receiver_port_id) {
647 DCHECK_CURRENTLY_ON(BrowserThread::UI);
649 int channel_id = GET_CHANNEL_ID(receiver_port_id);
650 CHECK(channels_.find(channel_id) == channels_.end());
651 channels_[channel_id] = channel;
652 pending_lazy_background_page_channels_.erase(channel_id);
655 void MessageService::CloseChannel(int port_id,
656 const std::string& error_message) {
657 DCHECK_CURRENTLY_ON(BrowserThread::UI);
659 // Note: The channel might be gone already, if the other side closed first.
660 int channel_id = GET_CHANNEL_ID(port_id);
661 MessageChannelMap::iterator it = channels_.find(channel_id);
662 if (it == channels_.end()) {
663 PendingLazyBackgroundPageChannelMap::iterator pending =
664 pending_lazy_background_page_channels_.find(channel_id);
665 if (pending != pending_lazy_background_page_channels_.end()) {
666 lazy_background_task_queue_->AddPendingTask(
667 pending->second.first, pending->second.second,
668 base::Bind(&MessageService::PendingLazyBackgroundPageCloseChannel,
669 weak_factory_.GetWeakPtr(), port_id, error_message));
671 return;
673 CloseChannelImpl(it, port_id, error_message, true);
676 void MessageService::CloseChannelImpl(
677 MessageChannelMap::iterator channel_iter,
678 int closing_port_id,
679 const std::string& error_message,
680 bool notify_other_port) {
681 DCHECK_CURRENTLY_ON(BrowserThread::UI);
683 MessageChannel* channel = channel_iter->second;
685 // Notify the other side.
686 if (notify_other_port) {
687 MessagePort* port = IS_OPENER_PORT_ID(closing_port_id) ?
688 channel->receiver.get() : channel->opener.get();
689 port->DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(closing_port_id),
690 error_message);
693 // Balance the IncrementLazyKeepaliveCount() in OpenChannelImpl.
694 channel->opener->DecrementLazyKeepaliveCount();
695 channel->receiver->DecrementLazyKeepaliveCount();
697 delete channel_iter->second;
698 channels_.erase(channel_iter);
701 void MessageService::PostMessage(int source_port_id, const Message& message) {
702 DCHECK_CURRENTLY_ON(BrowserThread::UI);
704 int channel_id = GET_CHANNEL_ID(source_port_id);
705 MessageChannelMap::iterator iter = channels_.find(channel_id);
706 if (iter == channels_.end()) {
707 // If this channel is pending, queue up the PostMessage to run once
708 // the channel opens.
709 EnqueuePendingMessage(source_port_id, channel_id, message);
710 return;
713 DispatchMessage(source_port_id, iter->second, message);
716 void MessageService::Observe(int type,
717 const content::NotificationSource& source,
718 const content::NotificationDetails& details) {
719 DCHECK_CURRENTLY_ON(BrowserThread::UI);
721 switch (type) {
722 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
723 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
724 content::RenderProcessHost* renderer =
725 content::Source<content::RenderProcessHost>(source).ptr();
726 OnProcessClosed(renderer);
727 break;
729 default:
730 NOTREACHED();
731 return;
735 void MessageService::OnProcessClosed(content::RenderProcessHost* process) {
736 DCHECK_CURRENTLY_ON(BrowserThread::UI);
738 // Close any channels that share this renderer. We notify the opposite
739 // port that its pair has closed.
740 for (MessageChannelMap::iterator it = channels_.begin();
741 it != channels_.end(); ) {
742 MessageChannelMap::iterator current = it++;
744 content::RenderProcessHost* opener_process =
745 current->second->opener->GetRenderProcessHost();
746 content::RenderProcessHost* receiver_process =
747 current->second->receiver->GetRenderProcessHost();
749 // Only notify the other side if it has a different porocess host.
750 bool notify_other_port = opener_process && receiver_process &&
751 opener_process != receiver_process;
753 if (opener_process == process) {
754 CloseChannelImpl(current, GET_CHANNEL_OPENER_ID(current->first),
755 std::string(), notify_other_port);
756 } else if (receiver_process == process) {
757 CloseChannelImpl(current, GET_CHANNEL_RECEIVERS_ID(current->first),
758 std::string(), notify_other_port);
763 void MessageService::EnqueuePendingMessage(int source_port_id,
764 int channel_id,
765 const Message& message) {
766 DCHECK_CURRENTLY_ON(BrowserThread::UI);
768 PendingChannelMap::iterator pending_for_incognito =
769 pending_incognito_channels_.find(channel_id);
770 if (pending_for_incognito != pending_incognito_channels_.end()) {
771 pending_for_incognito->second.push_back(
772 PendingMessage(source_port_id, message));
773 // A channel should only be holding pending messages because it is in one
774 // of these states.
775 DCHECK(!ContainsKey(pending_tls_channel_id_channels_, channel_id));
776 DCHECK(!ContainsKey(pending_lazy_background_page_channels_, channel_id));
777 return;
779 PendingChannelMap::iterator pending_for_tls_channel_id =
780 pending_tls_channel_id_channels_.find(channel_id);
781 if (pending_for_tls_channel_id != pending_tls_channel_id_channels_.end()) {
782 pending_for_tls_channel_id->second.push_back(
783 PendingMessage(source_port_id, message));
784 // A channel should only be holding pending messages because it is in one
785 // of these states.
786 DCHECK(!ContainsKey(pending_lazy_background_page_channels_, channel_id));
787 return;
789 EnqueuePendingMessageForLazyBackgroundLoad(source_port_id,
790 channel_id,
791 message);
794 void MessageService::EnqueuePendingMessageForLazyBackgroundLoad(
795 int source_port_id,
796 int channel_id,
797 const Message& message) {
798 DCHECK_CURRENTLY_ON(BrowserThread::UI);
800 PendingLazyBackgroundPageChannelMap::iterator pending =
801 pending_lazy_background_page_channels_.find(channel_id);
802 if (pending != pending_lazy_background_page_channels_.end()) {
803 lazy_background_task_queue_->AddPendingTask(
804 pending->second.first, pending->second.second,
805 base::Bind(&MessageService::PendingLazyBackgroundPagePostMessage,
806 weak_factory_.GetWeakPtr(), source_port_id, message));
810 void MessageService::DispatchMessage(int source_port_id,
811 MessageChannel* channel,
812 const Message& message) {
813 DCHECK_CURRENTLY_ON(BrowserThread::UI);
815 // Figure out which port the ID corresponds to.
816 int dest_port_id = GET_OPPOSITE_PORT_ID(source_port_id);
817 MessagePort* port = IS_OPENER_PORT_ID(dest_port_id) ?
818 channel->opener.get() : channel->receiver.get();
820 port->DispatchOnMessage(message, dest_port_id);
823 bool MessageService::MaybeAddPendingLazyBackgroundPageOpenChannelTask(
824 BrowserContext* context,
825 const Extension* extension,
826 scoped_ptr<OpenChannelParams>* params,
827 const PendingMessagesQueue& pending_messages) {
828 DCHECK_CURRENTLY_ON(BrowserThread::UI);
830 if (!BackgroundInfo::HasLazyBackgroundPage(extension))
831 return false;
833 // If the extension uses spanning incognito mode, make sure we're always
834 // using the original profile since that is what the extension process
835 // will use.
836 if (!IncognitoInfo::IsSplitMode(extension))
837 context = ExtensionsBrowserClient::Get()->GetOriginalContext(context);
839 if (!lazy_background_task_queue_->ShouldEnqueueTask(context, extension))
840 return false;
842 int channel_id = GET_CHANNEL_ID((*params)->receiver_port_id);
843 pending_lazy_background_page_channels_[channel_id] =
844 PendingLazyBackgroundPageChannel(context, extension->id());
845 int source_id = (*params)->source_process_id;
846 lazy_background_task_queue_->AddPendingTask(
847 context, extension->id(),
848 base::Bind(&MessageService::PendingLazyBackgroundPageOpenChannel,
849 weak_factory_.GetWeakPtr(), base::Passed(params), source_id));
851 for (const PendingMessage& message : pending_messages) {
852 EnqueuePendingMessageForLazyBackgroundLoad(message.first, channel_id,
853 message.second);
855 return true;
858 void MessageService::OnOpenChannelAllowed(scoped_ptr<OpenChannelParams> params,
859 bool allowed) {
860 DCHECK_CURRENTLY_ON(BrowserThread::UI);
862 int channel_id = GET_CHANNEL_ID(params->receiver_port_id);
864 PendingChannelMap::iterator pending_for_incognito =
865 pending_incognito_channels_.find(channel_id);
866 if (pending_for_incognito == pending_incognito_channels_.end()) {
867 NOTREACHED();
868 return;
870 PendingMessagesQueue pending_messages;
871 pending_messages.swap(pending_for_incognito->second);
872 pending_incognito_channels_.erase(pending_for_incognito);
874 // Re-lookup the source process since it may no longer be valid.
875 content::RenderProcessHost* source =
876 content::RenderProcessHost::FromID(params->source_process_id);
877 if (!source) {
878 return;
881 if (!allowed) {
882 DispatchOnDisconnect(source, params->receiver_port_id,
883 kReceivingEndDoesntExistError);
884 return;
887 BrowserContext* context = source->GetBrowserContext();
889 // Note: we use the source's profile here. If the source is an incognito
890 // process, we will use the incognito EPM to find the right extension process,
891 // which depends on whether the extension uses spanning or split mode.
892 params->receiver.reset(new ExtensionMessagePort(
893 GetExtensionProcess(context, params->target_extension_id),
894 MSG_ROUTING_CONTROL, params->target_extension_id));
896 // If the target requests the TLS channel id, begin the lookup for it.
897 // The target might also be a lazy background page, checked next, but the
898 // loading of lazy background pages continues asynchronously, so enqueue
899 // messages awaiting TLS channel ID first.
900 if (params->include_tls_channel_id) {
901 // Transfer pending messages to the next pending channel list.
902 pending_tls_channel_id_channels_[channel_id].swap(pending_messages);
903 // Capture this reference before params is invalidated by base::Passed().
904 const GURL& source_url = params->source_url;
905 property_provider_.GetChannelID(
906 Profile::FromBrowserContext(context), source_url,
907 base::Bind(&MessageService::GotChannelID, weak_factory_.GetWeakPtr(),
908 base::Passed(&params)));
909 return;
912 ExtensionRegistry* registry = ExtensionRegistry::Get(context);
913 const Extension* target_extension =
914 registry->enabled_extensions().GetByID(params->target_extension_id);
915 if (!target_extension) {
916 DispatchOnDisconnect(source, params->receiver_port_id,
917 kReceivingEndDoesntExistError);
918 return;
921 // The target might be a lazy background page. In that case, we have to check
922 // if it is loaded and ready, and if not, queue up the task and load the
923 // page.
924 if (!MaybeAddPendingLazyBackgroundPageOpenChannelTask(
925 context, target_extension, &params, pending_messages)) {
926 OpenChannelImpl(context, params.Pass(), target_extension,
927 false /* did_enqueue */);
928 DispatchPendingMessages(pending_messages, channel_id);
932 void MessageService::GotChannelID(scoped_ptr<OpenChannelParams> params,
933 const std::string& tls_channel_id) {
934 DCHECK_CURRENTLY_ON(BrowserThread::UI);
936 params->tls_channel_id.assign(tls_channel_id);
937 int channel_id = GET_CHANNEL_ID(params->receiver_port_id);
939 PendingChannelMap::iterator pending_for_tls_channel_id =
940 pending_tls_channel_id_channels_.find(channel_id);
941 if (pending_for_tls_channel_id == pending_tls_channel_id_channels_.end()) {
942 NOTREACHED();
943 return;
945 PendingMessagesQueue pending_messages;
946 pending_messages.swap(pending_for_tls_channel_id->second);
947 pending_tls_channel_id_channels_.erase(pending_for_tls_channel_id);
949 // Re-lookup the source process since it may no longer be valid.
950 content::RenderProcessHost* source =
951 content::RenderProcessHost::FromID(params->source_process_id);
952 if (!source) {
953 return;
956 BrowserContext* context = source->GetBrowserContext();
957 ExtensionRegistry* registry = ExtensionRegistry::Get(context);
958 const Extension* target_extension =
959 registry->enabled_extensions().GetByID(params->target_extension_id);
960 if (!target_extension) {
961 DispatchOnDisconnect(source, params->receiver_port_id,
962 kReceivingEndDoesntExistError);
963 return;
966 if (!MaybeAddPendingLazyBackgroundPageOpenChannelTask(
967 context, target_extension, &params, pending_messages)) {
968 OpenChannelImpl(context, params.Pass(), target_extension,
969 false /* did_enqueue */);
970 DispatchPendingMessages(pending_messages, channel_id);
974 void MessageService::PendingLazyBackgroundPageOpenChannel(
975 scoped_ptr<OpenChannelParams> params,
976 int source_process_id,
977 ExtensionHost* host) {
978 DCHECK_CURRENTLY_ON(BrowserThread::UI);
980 if (!host)
981 return; // TODO(mpcomplete): notify source of disconnect?
983 params->receiver.reset(new ExtensionMessagePort(host->render_process_host(),
984 MSG_ROUTING_CONTROL,
985 params->target_extension_id));
986 OpenChannelImpl(host->browser_context(), params.Pass(), host->extension(),
987 true /* did_enqueue */);
990 void MessageService::DispatchOnDisconnect(content::RenderProcessHost* source,
991 int port_id,
992 const std::string& error_message) {
993 DCHECK_CURRENTLY_ON(BrowserThread::UI);
995 ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, "");
996 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(port_id), error_message);
999 void MessageService::DispatchPendingMessages(const PendingMessagesQueue& queue,
1000 int channel_id) {
1001 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1003 MessageChannelMap::iterator channel_iter = channels_.find(channel_id);
1004 if (channel_iter != channels_.end()) {
1005 for (const PendingMessage& message : queue) {
1006 DispatchMessage(message.first, channel_iter->second, message.second);
1011 } // namespace extensions