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"
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/notification_service.h"
27 #include "content/public/browser/render_frame_host.h"
28 #include "content/public/browser/render_process_host.h"
29 #include "content/public/browser/render_view_host.h"
30 #include "content/public/browser/render_widget_host.h"
31 #include "content/public/browser/render_widget_host_view.h"
32 #include "content/public/browser/site_instance.h"
33 #include "content/public/browser/web_contents.h"
34 #include "content/public/common/child_process_host.h"
35 #include "extensions/browser/event_router.h"
36 #include "extensions/browser/extension_host.h"
37 #include "extensions/browser/extension_registry.h"
38 #include "extensions/browser/extension_system.h"
39 #include "extensions/browser/extensions_browser_client.h"
40 #include "extensions/browser/guest_view/web_view/web_view_guest.h"
41 #include "extensions/browser/lazy_background_task_queue.h"
42 #include "extensions/browser/pref_names.h"
43 #include "extensions/browser/process_manager.h"
44 #include "extensions/common/extension.h"
45 #include "extensions/common/manifest_constants.h"
46 #include "extensions/common/manifest_handlers/background_info.h"
47 #include "extensions/common/manifest_handlers/externally_connectable.h"
48 #include "extensions/common/manifest_handlers/incognito_info.h"
49 #include "extensions/common/permissions/permissions_data.h"
50 #include "net/base/completion_callback.h"
53 using content::BrowserContext
;
54 using content::SiteInstance
;
55 using content::WebContents
;
57 // Since we have 2 ports for every channel, we just index channels by half the
59 #define GET_CHANNEL_ID(port_id) ((port_id) / 2)
60 #define GET_CHANNEL_OPENER_ID(channel_id) ((channel_id) * 2)
61 #define GET_CHANNEL_RECEIVERS_ID(channel_id) ((channel_id) * 2 + 1)
63 // Port1 is always even, port2 is always odd.
64 #define IS_OPENER_PORT_ID(port_id) (((port_id) & 1) == 0)
66 // Change even to odd and vice versa, to get the other side of a given channel.
67 #define GET_OPPOSITE_PORT_ID(source_port_id) ((source_port_id) ^ 1)
69 namespace extensions
{
71 MessageService::PolicyPermission
MessageService::IsNativeMessagingHostAllowed(
72 const PrefService
* pref_service
,
73 const std::string
& native_host_name
) {
74 PolicyPermission allow_result
= ALLOW_ALL
;
75 if (pref_service
->IsManagedPreference(
76 pref_names::kNativeMessagingUserLevelHosts
)) {
77 if (!pref_service
->GetBoolean(pref_names::kNativeMessagingUserLevelHosts
))
78 allow_result
= ALLOW_SYSTEM_ONLY
;
81 // All native messaging hosts are allowed if there is no blacklist.
82 if (!pref_service
->IsManagedPreference(pref_names::kNativeMessagingBlacklist
))
84 const base::ListValue
* blacklist
=
85 pref_service
->GetList(pref_names::kNativeMessagingBlacklist
);
89 // Check if the name or the wildcard is in the blacklist.
90 base::StringValue
name_value(native_host_name
);
91 base::StringValue
wildcard_value("*");
92 if (blacklist
->Find(name_value
) == blacklist
->end() &&
93 blacklist
->Find(wildcard_value
) == blacklist
->end()) {
97 // The native messaging host is blacklisted. Check the whitelist.
98 if (pref_service
->IsManagedPreference(
99 pref_names::kNativeMessagingWhitelist
)) {
100 const base::ListValue
* whitelist
=
101 pref_service
->GetList(pref_names::kNativeMessagingWhitelist
);
102 if (whitelist
&& whitelist
->Find(name_value
) != whitelist
->end())
109 const char kReceivingEndDoesntExistError
[] =
110 "Could not establish connection. Receiving end does not exist.";
111 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
112 const char kMissingPermissionError
[] =
113 "Access to native messaging requires nativeMessaging permission.";
114 const char kProhibitedByPoliciesError
[] =
115 "Access to the native messaging host was disabled by the system "
119 struct MessageService::MessageChannel
{
120 scoped_ptr
<MessagePort
> opener
;
121 scoped_ptr
<MessagePort
> receiver
;
124 struct MessageService::OpenChannelParams
{
125 int source_process_id
;
126 scoped_ptr
<base::DictionaryValue
> source_tab
;
129 scoped_ptr
<MessagePort
> receiver
;
130 int receiver_port_id
;
131 std::string source_extension_id
;
132 std::string target_extension_id
;
134 std::string channel_name
;
135 bool include_tls_channel_id
;
136 std::string tls_channel_id
;
137 bool include_guest_process_info
;
139 // Takes ownership of receiver.
140 OpenChannelParams(int source_process_id
,
141 scoped_ptr
<base::DictionaryValue
> source_tab
,
144 MessagePort
* receiver
,
145 int receiver_port_id
,
146 const std::string
& source_extension_id
,
147 const std::string
& target_extension_id
,
148 const GURL
& source_url
,
149 const std::string
& channel_name
,
150 bool include_tls_channel_id
,
151 bool include_guest_process_info
)
152 : source_process_id(source_process_id
),
153 source_frame_id(source_frame_id
),
154 target_frame_id(target_frame_id
),
156 receiver_port_id(receiver_port_id
),
157 source_extension_id(source_extension_id
),
158 target_extension_id(target_extension_id
),
159 source_url(source_url
),
160 channel_name(channel_name
),
161 include_tls_channel_id(include_tls_channel_id
),
162 include_guest_process_info(include_guest_process_info
) {
164 this->source_tab
= source_tab
.Pass();
168 DISALLOW_COPY_AND_ASSIGN(OpenChannelParams
);
173 static base::StaticAtomicSequenceNumber g_next_channel_id
;
174 static base::StaticAtomicSequenceNumber g_channel_id_overflow_count
;
176 static content::RenderProcessHost
* GetExtensionProcess(
177 BrowserContext
* context
,
178 const std::string
& extension_id
) {
179 scoped_refptr
<SiteInstance
> site_instance
=
180 ProcessManager::Get(context
)->GetSiteInstanceForURL(
181 Extension::GetBaseURLFromExtensionId(extension_id
));
182 return site_instance
->HasProcess() ? site_instance
->GetProcess() : NULL
;
187 content::RenderProcessHost
*
188 MessageService::MessagePort::GetRenderProcessHost() {
193 void MessageService::AllocatePortIdPair(int* port1
, int* port2
) {
194 unsigned channel_id
=
195 static_cast<unsigned>(g_next_channel_id
.GetNext()) % (kint32max
/2);
197 if (channel_id
== 0) {
198 int overflow_count
= g_channel_id_overflow_count
.GetNext();
199 if (overflow_count
> 0)
200 UMA_HISTOGRAM_BOOLEAN("Extensions.AllocatePortIdPairOverflow", true);
203 unsigned port1_id
= channel_id
* 2;
204 unsigned port2_id
= channel_id
* 2 + 1;
206 // Sanity checks to make sure our channel<->port converters are correct.
207 DCHECK(IS_OPENER_PORT_ID(port1_id
));
208 DCHECK_EQ(GET_OPPOSITE_PORT_ID(port1_id
), port2_id
);
209 DCHECK_EQ(GET_OPPOSITE_PORT_ID(port2_id
), port1_id
);
210 DCHECK_EQ(GET_CHANNEL_ID(port1_id
), GET_CHANNEL_ID(port2_id
));
211 DCHECK_EQ(GET_CHANNEL_ID(port1_id
), channel_id
);
212 DCHECK_EQ(GET_CHANNEL_OPENER_ID(channel_id
), port1_id
);
213 DCHECK_EQ(GET_CHANNEL_RECEIVERS_ID(channel_id
), port2_id
);
219 MessageService::MessageService(BrowserContext
* context
)
220 : lazy_background_task_queue_(
221 LazyBackgroundTaskQueue::Get(context
)),
222 weak_factory_(this) {
223 registrar_
.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED
,
224 content::NotificationService::AllBrowserContextsAndSources());
225 registrar_
.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED
,
226 content::NotificationService::AllBrowserContextsAndSources());
229 MessageService::~MessageService() {
230 STLDeleteContainerPairSecondPointers(channels_
.begin(), channels_
.end());
234 static base::LazyInstance
<BrowserContextKeyedAPIFactory
<MessageService
> >
235 g_factory
= LAZY_INSTANCE_INITIALIZER
;
238 BrowserContextKeyedAPIFactory
<MessageService
>*
239 MessageService::GetFactoryInstance() {
240 return g_factory
.Pointer();
244 MessageService
* MessageService::Get(BrowserContext
* context
) {
245 return BrowserContextKeyedAPIFactory
<MessageService
>::Get(context
);
248 void MessageService::OpenChannelToExtension(
249 int source_process_id
, int source_routing_id
, int receiver_port_id
,
250 const std::string
& source_extension_id
,
251 const std::string
& target_extension_id
,
252 const GURL
& source_url
,
253 const std::string
& channel_name
,
254 bool include_tls_channel_id
) {
255 content::RenderProcessHost
* source
=
256 content::RenderProcessHost::FromID(source_process_id
);
259 BrowserContext
* context
= source
->GetBrowserContext();
261 ExtensionRegistry
* registry
= ExtensionRegistry::Get(context
);
262 const Extension
* target_extension
=
263 registry
->enabled_extensions().GetByID(target_extension_id
);
264 if (!target_extension
) {
265 DispatchOnDisconnect(
266 source
, receiver_port_id
, kReceivingEndDoesntExistError
);
270 bool is_web_connection
= false;
272 if (source_extension_id
!= target_extension_id
) {
273 // It's an external connection. Check the externally_connectable manifest
274 // key if it's present. If it's not, we allow connection from any extension
276 ExternallyConnectableInfo
* externally_connectable
=
277 static_cast<ExternallyConnectableInfo
*>(
278 target_extension
->GetManifestData(
279 manifest_keys::kExternallyConnectable
));
280 bool is_externally_connectable
= false;
282 if (externally_connectable
) {
283 if (source_extension_id
.empty()) {
284 // No source extension ID so the source was a web page. Check that the
286 is_web_connection
= true;
287 is_externally_connectable
=
288 externally_connectable
->matches
.MatchesURL(source_url
);
289 // Only include the TLS channel ID for externally connected web pages.
290 include_tls_channel_id
&=
291 is_externally_connectable
&&
292 externally_connectable
->accepts_tls_channel_id
;
294 // Source extension ID so the source was an extension. Check that the
295 // extension matches.
296 is_externally_connectable
=
297 externally_connectable
->IdCanConnect(source_extension_id
);
300 // Default behaviour. Any extension, no webpages.
301 is_externally_connectable
= !source_extension_id
.empty();
304 if (!is_externally_connectable
) {
305 // Important: use kReceivingEndDoesntExistError here so that we don't
306 // leak information about this extension to callers. This way it's
307 // indistinguishable from the extension just not existing.
308 DispatchOnDisconnect(
309 source
, receiver_port_id
, kReceivingEndDoesntExistError
);
314 WebContents
* source_contents
= tab_util::GetWebContentsByFrameID(
315 source_process_id
, source_routing_id
);
317 bool include_guest_process_info
= false;
319 // Include info about the opener's tab (if it was a tab).
320 scoped_ptr
<base::DictionaryValue
> source_tab
;
321 int source_frame_id
= -1;
322 if (source_contents
&& ExtensionTabUtil::GetTabId(source_contents
) >= 0) {
323 // Only the tab id is useful to platform apps for internal use. The
324 // unnecessary bits will be stripped out in
325 // MessagingBindings::DispatchOnConnect().
326 source_tab
.reset(ExtensionTabUtil::CreateTabValue(source_contents
));
328 content::RenderFrameHost
* rfh
=
329 content::RenderFrameHost::FromID(source_process_id
, source_routing_id
);
330 // Main frame's frameId is 0.
332 source_frame_id
= !rfh
->GetParent() ? 0 : source_routing_id
;
334 // Check to see if it was a WebView making the request.
335 // Sending messages from WebViews to extensions breaks webview isolation,
336 // so only allow component extensions to receive messages from WebViews.
337 bool is_web_view
= !!WebViewGuest::FromWebContents(source_contents
);
338 if (is_web_view
&& extensions::Manifest::IsComponentLocation(
339 target_extension
->location())) {
340 include_guest_process_info
= true;
341 auto* rfh
= content::RenderFrameHost::FromID(source_process_id
,
343 // Include |source_frame_id| so that we can retrieve the guest's frame
344 // routing id in OpenChannelImpl.
346 source_frame_id
= source_routing_id
;
350 scoped_ptr
<OpenChannelParams
> params(new OpenChannelParams(
351 source_process_id
, source_tab
.Pass(), source_frame_id
,
352 -1, // no target_frame_id for a channel to an extension/background page.
353 nullptr, receiver_port_id
, source_extension_id
, target_extension_id
,
354 source_url
, channel_name
, include_tls_channel_id
,
355 include_guest_process_info
));
357 pending_incognito_channels_
[GET_CHANNEL_ID(params
->receiver_port_id
)] =
358 PendingMessagesQueue();
359 if (context
->IsOffTheRecord() &&
360 !util::IsIncognitoEnabled(target_extension_id
, context
)) {
361 // Give the user a chance to accept an incognito connection from the web if
362 // they haven't already, with the conditions:
363 // - Only for spanning-mode incognito. We don't want the complication of
364 // spinning up an additional process here which might need to do some
365 // setup that we're not expecting.
366 // - Only for extensions that can't normally be enabled in incognito, since
367 // that surface (e.g. chrome://extensions) should be the only one for
368 // enabling in incognito. In practice this means platform apps only.
369 if (!is_web_connection
|| IncognitoInfo::IsSplitMode(target_extension
) ||
370 target_extension
->can_be_incognito_enabled()) {
371 OnOpenChannelAllowed(params
.Pass(), false);
375 // If the target extension isn't even listening for connect/message events,
376 // there is no need to go any further and the connection should be
377 // rejected without showing a prompt. See http://crbug.com/442497
378 EventRouter
* event_router
= EventRouter::Get(context
);
379 const char* const events
[] = {"runtime.onConnectExternal",
380 "runtime.onMessageExternal",
381 "extension.onRequestExternal",
383 bool has_event_listener
= false;
384 for (const char* const* event
= events
; *event
; event
++) {
385 has_event_listener
|=
386 event_router
->ExtensionHasEventListener(target_extension_id
, *event
);
388 if (!has_event_listener
) {
389 OnOpenChannelAllowed(params
.Pass(), false);
393 // This check may show a dialog.
394 IncognitoConnectability::Get(context
)
395 ->Query(target_extension
, source_contents
, source_url
,
396 base::Bind(&MessageService::OnOpenChannelAllowed
,
397 weak_factory_
.GetWeakPtr(), base::Passed(¶ms
)));
401 OnOpenChannelAllowed(params
.Pass(), true);
404 void MessageService::OpenChannelToNativeApp(
405 int source_process_id
,
406 int source_routing_id
,
407 int receiver_port_id
,
408 const std::string
& source_extension_id
,
409 const std::string
& native_app_name
) {
410 content::RenderProcessHost
* source
=
411 content::RenderProcessHost::FromID(source_process_id
);
415 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
416 Profile
* profile
= Profile::FromBrowserContext(source
->GetBrowserContext());
417 ExtensionService
* extension_service
=
418 ExtensionSystem::Get(profile
)->extension_service();
419 bool has_permission
= false;
420 if (extension_service
) {
421 const Extension
* extension
=
422 extension_service
->GetExtensionById(source_extension_id
, false);
423 has_permission
= extension
&&
424 extension
->permissions_data()->HasAPIPermission(
425 APIPermission::kNativeMessaging
);
428 if (!has_permission
) {
429 DispatchOnDisconnect(source
, receiver_port_id
, kMissingPermissionError
);
433 PrefService
* pref_service
= profile
->GetPrefs();
435 // Verify that the host is not blocked by policies.
436 PolicyPermission policy_permission
=
437 IsNativeMessagingHostAllowed(pref_service
, native_app_name
);
438 if (policy_permission
== DISALLOW
) {
439 DispatchOnDisconnect(source
, receiver_port_id
, kProhibitedByPoliciesError
);
443 scoped_ptr
<MessageChannel
> channel(new MessageChannel());
444 channel
->opener
.reset(new ExtensionMessagePort(source
, MSG_ROUTING_CONTROL
,
445 source_extension_id
));
447 // Get handle of the native view and pass it to the native messaging host.
448 content::RenderFrameHost
* render_frame_host
=
449 content::RenderFrameHost::FromID(source_process_id
, source_routing_id
);
450 gfx::NativeView native_view
=
451 render_frame_host
? render_frame_host
->GetNativeView() : nullptr;
453 std::string error
= kReceivingEndDoesntExistError
;
454 scoped_ptr
<NativeMessageHost
> native_host
= NativeMessageHost::Create(
458 policy_permission
== ALLOW_ALL
,
461 // Abandon the channel.
462 if (!native_host
.get()) {
463 LOG(ERROR
) << "Failed to create native process.";
464 DispatchOnDisconnect(source
, receiver_port_id
, error
);
467 channel
->receiver
.reset(new NativeMessagePort(
468 weak_factory_
.GetWeakPtr(), receiver_port_id
, native_host
.Pass()));
470 // Keep the opener alive until the channel is closed.
471 channel
->opener
->IncrementLazyKeepaliveCount();
473 AddChannel(channel
.release(), receiver_port_id
);
474 #else // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
475 const char kNativeMessagingNotSupportedError
[] =
476 "Native Messaging is not supported on this platform.";
477 DispatchOnDisconnect(
478 source
, receiver_port_id
, kNativeMessagingNotSupportedError
);
479 #endif // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
482 void MessageService::OpenChannelToTab(int source_process_id
,
483 int receiver_port_id
,
486 const std::string
& extension_id
,
487 const std::string
& channel_name
) {
488 content::RenderProcessHost
* source
=
489 content::RenderProcessHost::FromID(source_process_id
);
492 Profile
* profile
= Profile::FromBrowserContext(source
->GetBrowserContext());
494 WebContents
* contents
= NULL
;
495 scoped_ptr
<MessagePort
> receiver
;
496 if (!ExtensionTabUtil::GetTabById(tab_id
, profile
, true, NULL
, NULL
,
498 contents
->GetController().NeedsReload()) {
499 // The tab isn't loaded yet. Don't attempt to connect.
500 DispatchOnDisconnect(
501 source
, receiver_port_id
, kReceivingEndDoesntExistError
);
505 int receiver_routing_id
;
507 // Positive frame ID is child frame.
508 int receiver_process_id
= contents
->GetRenderProcessHost()->GetID();
509 if (!content::RenderFrameHost::FromID(receiver_process_id
, frame_id
)) {
510 // Frame does not exist.
511 DispatchOnDisconnect(
512 source
, receiver_port_id
, kReceivingEndDoesntExistError
);
515 receiver_routing_id
= frame_id
;
516 } else if (frame_id
== 0) {
517 // Frame ID 0 is main frame.
518 receiver_routing_id
= contents
->GetMainFrame()->GetRoutingID();
520 DCHECK_EQ(-1, frame_id
);
521 // If the frame ID is not set (i.e. -1), then the channel has to be opened
523 // TODO(robwu): Update logic so that frames that are not hosted in the main
524 // frame's process can also receive the port.
525 receiver_routing_id
= MSG_ROUTING_CONTROL
;
527 receiver
.reset(new ExtensionMessagePort(
528 contents
->GetRenderProcessHost(), receiver_routing_id
, extension_id
));
530 scoped_ptr
<OpenChannelParams
> params(new OpenChannelParams(
532 scoped_ptr
<base::DictionaryValue
>(), // Source tab doesn't make sense
533 // for opening to tabs.
534 -1, // If there is no tab, then there is no frame either.
536 receiver
.release(), receiver_port_id
, extension_id
, extension_id
,
537 GURL(), // Source URL doesn't make sense for opening to tabs.
539 false, // Connections to tabs don't get TLS channel IDs.
540 false)); // Connections to tabs aren't webview guests.
541 OpenChannelImpl(params
.Pass());
544 void MessageService::OpenChannelImpl(scoped_ptr
<OpenChannelParams
> params
) {
545 content::RenderProcessHost
* source
=
546 content::RenderProcessHost::FromID(params
->source_process_id
);
548 return; // Closed while in flight.
550 if (!params
->receiver
|| !params
->receiver
->GetRenderProcessHost()) {
551 DispatchOnDisconnect(source
, params
->receiver_port_id
,
552 kReceivingEndDoesntExistError
);
556 // Add extra paranoid CHECKs, since we have crash reports of this being NULL.
557 // http://code.google.com/p/chromium/issues/detail?id=19067
558 CHECK(params
->receiver
->GetRenderProcessHost());
560 MessageChannel
* channel(new MessageChannel
);
561 channel
->opener
.reset(new ExtensionMessagePort(source
, MSG_ROUTING_CONTROL
,
562 params
->source_extension_id
));
563 channel
->receiver
.reset(params
->receiver
.release());
565 CHECK(channel
->receiver
->GetRenderProcessHost());
567 AddChannel(channel
, params
->receiver_port_id
);
569 CHECK(channel
->receiver
->GetRenderProcessHost());
571 int guest_process_id
= content::ChildProcessHost::kInvalidUniqueID
;
572 int guest_render_frame_routing_id
= MSG_ROUTING_NONE
;
573 if (params
->include_guest_process_info
) {
574 guest_process_id
= params
->source_process_id
;
575 guest_render_frame_routing_id
= params
->source_frame_id
;
576 auto* guest_rfh
= content::RenderFrameHost::FromID(
577 guest_process_id
, guest_render_frame_routing_id
);
578 // Reset the |source_frame_id| parameter.
579 params
->source_frame_id
= -1;
581 DCHECK(guest_rfh
== nullptr ||
582 WebViewGuest::FromWebContents(
583 WebContents::FromRenderFrameHost(guest_rfh
)) != nullptr);
586 // Send the connect event to the receiver. Give it the opener's port ID (the
587 // opener has the opposite port ID).
588 channel
->receiver
->DispatchOnConnect(params
->receiver_port_id
,
589 params
->channel_name
,
590 params
->source_tab
.Pass(),
591 params
->source_frame_id
,
592 params
->target_frame_id
,
594 guest_render_frame_routing_id
,
595 params
->source_extension_id
,
596 params
->target_extension_id
,
598 params
->tls_channel_id
);
600 // Keep both ends of the channel alive until the channel is closed.
601 channel
->opener
->IncrementLazyKeepaliveCount();
602 channel
->receiver
->IncrementLazyKeepaliveCount();
605 void MessageService::AddChannel(MessageChannel
* channel
, int receiver_port_id
) {
606 int channel_id
= GET_CHANNEL_ID(receiver_port_id
);
607 CHECK(channels_
.find(channel_id
) == channels_
.end());
608 channels_
[channel_id
] = channel
;
609 pending_lazy_background_page_channels_
.erase(channel_id
);
612 void MessageService::CloseChannel(int port_id
,
613 const std::string
& error_message
) {
614 // Note: The channel might be gone already, if the other side closed first.
615 int channel_id
= GET_CHANNEL_ID(port_id
);
616 MessageChannelMap::iterator it
= channels_
.find(channel_id
);
617 if (it
== channels_
.end()) {
618 PendingLazyBackgroundPageChannelMap::iterator pending
=
619 pending_lazy_background_page_channels_
.find(channel_id
);
620 if (pending
!= pending_lazy_background_page_channels_
.end()) {
621 lazy_background_task_queue_
->AddPendingTask(
622 pending
->second
.first
, pending
->second
.second
,
623 base::Bind(&MessageService::PendingLazyBackgroundPageCloseChannel
,
624 weak_factory_
.GetWeakPtr(), port_id
, error_message
));
628 CloseChannelImpl(it
, port_id
, error_message
, true);
631 void MessageService::CloseChannelImpl(
632 MessageChannelMap::iterator channel_iter
,
634 const std::string
& error_message
,
635 bool notify_other_port
) {
636 MessageChannel
* channel
= channel_iter
->second
;
638 // Notify the other side.
639 if (notify_other_port
) {
640 MessagePort
* port
= IS_OPENER_PORT_ID(closing_port_id
) ?
641 channel
->receiver
.get() : channel
->opener
.get();
642 port
->DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(closing_port_id
),
646 // Balance the IncrementLazyKeepaliveCount() in OpenChannelImpl.
647 channel
->opener
->DecrementLazyKeepaliveCount();
648 channel
->receiver
->DecrementLazyKeepaliveCount();
650 delete channel_iter
->second
;
651 channels_
.erase(channel_iter
);
654 void MessageService::PostMessage(int source_port_id
, const Message
& message
) {
655 int channel_id
= GET_CHANNEL_ID(source_port_id
);
656 MessageChannelMap::iterator iter
= channels_
.find(channel_id
);
657 if (iter
== channels_
.end()) {
658 // If this channel is pending, queue up the PostMessage to run once
659 // the channel opens.
660 EnqueuePendingMessage(source_port_id
, channel_id
, message
);
664 DispatchMessage(source_port_id
, iter
->second
, message
);
667 void MessageService::Observe(int type
,
668 const content::NotificationSource
& source
,
669 const content::NotificationDetails
& details
) {
671 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED
:
672 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED
: {
673 content::RenderProcessHost
* renderer
=
674 content::Source
<content::RenderProcessHost
>(source
).ptr();
675 OnProcessClosed(renderer
);
684 void MessageService::OnProcessClosed(content::RenderProcessHost
* process
) {
685 // Close any channels that share this renderer. We notify the opposite
686 // port that his pair has closed.
687 for (MessageChannelMap::iterator it
= channels_
.begin();
688 it
!= channels_
.end(); ) {
689 MessageChannelMap::iterator current
= it
++;
691 content::RenderProcessHost
* opener_process
=
692 current
->second
->opener
->GetRenderProcessHost();
693 content::RenderProcessHost
* receiver_process
=
694 current
->second
->receiver
->GetRenderProcessHost();
696 // Only notify the other side if it has a different porocess host.
697 bool notify_other_port
= opener_process
&& receiver_process
&&
698 opener_process
!= receiver_process
;
700 if (opener_process
== process
) {
701 CloseChannelImpl(current
, GET_CHANNEL_OPENER_ID(current
->first
),
702 std::string(), notify_other_port
);
703 } else if (receiver_process
== process
) {
704 CloseChannelImpl(current
, GET_CHANNEL_RECEIVERS_ID(current
->first
),
705 std::string(), notify_other_port
);
710 void MessageService::EnqueuePendingMessage(int source_port_id
,
712 const Message
& message
) {
713 PendingChannelMap::iterator pending_for_incognito
=
714 pending_incognito_channels_
.find(channel_id
);
715 if (pending_for_incognito
!= pending_incognito_channels_
.end()) {
716 pending_for_incognito
->second
.push_back(
717 PendingMessage(source_port_id
, message
));
718 // A channel should only be holding pending messages because it is in one
720 DCHECK(!ContainsKey(pending_tls_channel_id_channels_
, channel_id
));
721 DCHECK(!ContainsKey(pending_lazy_background_page_channels_
, channel_id
));
724 PendingChannelMap::iterator pending_for_tls_channel_id
=
725 pending_tls_channel_id_channels_
.find(channel_id
);
726 if (pending_for_tls_channel_id
!= pending_tls_channel_id_channels_
.end()) {
727 pending_for_tls_channel_id
->second
.push_back(
728 PendingMessage(source_port_id
, message
));
729 // A channel should only be holding pending messages because it is in one
731 DCHECK(!ContainsKey(pending_lazy_background_page_channels_
, channel_id
));
734 EnqueuePendingMessageForLazyBackgroundLoad(source_port_id
,
739 void MessageService::EnqueuePendingMessageForLazyBackgroundLoad(
742 const Message
& message
) {
743 PendingLazyBackgroundPageChannelMap::iterator pending
=
744 pending_lazy_background_page_channels_
.find(channel_id
);
745 if (pending
!= pending_lazy_background_page_channels_
.end()) {
746 lazy_background_task_queue_
->AddPendingTask(
747 pending
->second
.first
, pending
->second
.second
,
748 base::Bind(&MessageService::PendingLazyBackgroundPagePostMessage
,
749 weak_factory_
.GetWeakPtr(), source_port_id
, message
));
753 void MessageService::DispatchMessage(int source_port_id
,
754 MessageChannel
* channel
,
755 const Message
& message
) {
756 // Figure out which port the ID corresponds to.
757 int dest_port_id
= GET_OPPOSITE_PORT_ID(source_port_id
);
758 MessagePort
* port
= IS_OPENER_PORT_ID(dest_port_id
) ?
759 channel
->opener
.get() : channel
->receiver
.get();
761 port
->DispatchOnMessage(message
, dest_port_id
);
764 bool MessageService::MaybeAddPendingLazyBackgroundPageOpenChannelTask(
765 BrowserContext
* context
,
766 const Extension
* extension
,
767 scoped_ptr
<OpenChannelParams
>* params
,
768 const PendingMessagesQueue
& pending_messages
) {
769 if (!BackgroundInfo::HasLazyBackgroundPage(extension
))
772 // If the extension uses spanning incognito mode, make sure we're always
773 // using the original profile since that is what the extension process
775 if (!IncognitoInfo::IsSplitMode(extension
))
776 context
= ExtensionsBrowserClient::Get()->GetOriginalContext(context
);
778 if (!lazy_background_task_queue_
->ShouldEnqueueTask(context
, extension
))
781 int channel_id
= GET_CHANNEL_ID((*params
)->receiver_port_id
);
782 pending_lazy_background_page_channels_
[channel_id
] =
783 PendingLazyBackgroundPageChannel(context
, extension
->id());
784 int source_id
= (*params
)->source_process_id
;
785 lazy_background_task_queue_
->AddPendingTask(
786 context
, extension
->id(),
787 base::Bind(&MessageService::PendingLazyBackgroundPageOpenChannel
,
788 weak_factory_
.GetWeakPtr(), base::Passed(params
), source_id
));
790 for (const PendingMessage
& message
: pending_messages
) {
791 EnqueuePendingMessageForLazyBackgroundLoad(message
.first
, channel_id
,
797 void MessageService::OnOpenChannelAllowed(scoped_ptr
<OpenChannelParams
> params
,
799 int channel_id
= GET_CHANNEL_ID(params
->receiver_port_id
);
801 PendingChannelMap::iterator pending_for_incognito
=
802 pending_incognito_channels_
.find(channel_id
);
803 if (pending_for_incognito
== pending_incognito_channels_
.end()) {
807 PendingMessagesQueue pending_messages
;
808 pending_messages
.swap(pending_for_incognito
->second
);
809 pending_incognito_channels_
.erase(pending_for_incognito
);
811 // Re-lookup the source process since it may no longer be valid.
812 content::RenderProcessHost
* source
=
813 content::RenderProcessHost::FromID(params
->source_process_id
);
819 DispatchOnDisconnect(source
, params
->receiver_port_id
,
820 kReceivingEndDoesntExistError
);
824 BrowserContext
* context
= source
->GetBrowserContext();
826 // Note: we use the source's profile here. If the source is an incognito
827 // process, we will use the incognito EPM to find the right extension process,
828 // which depends on whether the extension uses spanning or split mode.
829 params
->receiver
.reset(new ExtensionMessagePort(
830 GetExtensionProcess(context
, params
->target_extension_id
),
831 MSG_ROUTING_CONTROL
, params
->target_extension_id
));
833 // If the target requests the TLS channel id, begin the lookup for it.
834 // The target might also be a lazy background page, checked next, but the
835 // loading of lazy background pages continues asynchronously, so enqueue
836 // messages awaiting TLS channel ID first.
837 if (params
->include_tls_channel_id
) {
838 // Transfer pending messages to the next pending channel list.
839 pending_tls_channel_id_channels_
[channel_id
].swap(pending_messages
);
840 // Capture this reference before params is invalidated by base::Passed().
841 const GURL
& source_url
= params
->source_url
;
842 property_provider_
.GetChannelID(
843 Profile::FromBrowserContext(context
), source_url
,
844 base::Bind(&MessageService::GotChannelID
, weak_factory_
.GetWeakPtr(),
845 base::Passed(¶ms
)));
849 ExtensionRegistry
* registry
= ExtensionRegistry::Get(context
);
850 const Extension
* target_extension
=
851 registry
->enabled_extensions().GetByID(params
->target_extension_id
);
852 if (!target_extension
) {
853 DispatchOnDisconnect(source
, params
->receiver_port_id
,
854 kReceivingEndDoesntExistError
);
858 // The target might be a lazy background page. In that case, we have to check
859 // if it is loaded and ready, and if not, queue up the task and load the
861 if (!MaybeAddPendingLazyBackgroundPageOpenChannelTask(
862 context
, target_extension
, ¶ms
, pending_messages
)) {
863 OpenChannelImpl(params
.Pass());
864 DispatchPendingMessages(pending_messages
, channel_id
);
868 void MessageService::GotChannelID(scoped_ptr
<OpenChannelParams
> params
,
869 const std::string
& tls_channel_id
) {
870 params
->tls_channel_id
.assign(tls_channel_id
);
871 int channel_id
= GET_CHANNEL_ID(params
->receiver_port_id
);
873 PendingChannelMap::iterator pending_for_tls_channel_id
=
874 pending_tls_channel_id_channels_
.find(channel_id
);
875 if (pending_for_tls_channel_id
== pending_tls_channel_id_channels_
.end()) {
879 PendingMessagesQueue pending_messages
;
880 pending_messages
.swap(pending_for_tls_channel_id
->second
);
881 pending_tls_channel_id_channels_
.erase(pending_for_tls_channel_id
);
883 // Re-lookup the source process since it may no longer be valid.
884 content::RenderProcessHost
* source
=
885 content::RenderProcessHost::FromID(params
->source_process_id
);
890 BrowserContext
* context
= source
->GetBrowserContext();
891 ExtensionRegistry
* registry
= ExtensionRegistry::Get(context
);
892 const Extension
* target_extension
=
893 registry
->enabled_extensions().GetByID(params
->target_extension_id
);
894 if (!target_extension
) {
895 DispatchOnDisconnect(source
, params
->receiver_port_id
,
896 kReceivingEndDoesntExistError
);
900 if (!MaybeAddPendingLazyBackgroundPageOpenChannelTask(
901 context
, target_extension
, ¶ms
, pending_messages
)) {
902 OpenChannelImpl(params
.Pass());
903 DispatchPendingMessages(pending_messages
, channel_id
);
907 void MessageService::PendingLazyBackgroundPageOpenChannel(
908 scoped_ptr
<OpenChannelParams
> params
,
909 int source_process_id
,
910 ExtensionHost
* host
) {
912 return; // TODO(mpcomplete): notify source of disconnect?
914 params
->receiver
.reset(new ExtensionMessagePort(host
->render_process_host(),
916 params
->target_extension_id
));
917 OpenChannelImpl(params
.Pass());
920 void MessageService::DispatchOnDisconnect(content::RenderProcessHost
* source
,
922 const std::string
& error_message
) {
923 ExtensionMessagePort
port(source
, MSG_ROUTING_CONTROL
, "");
924 port
.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(port_id
), error_message
);
927 void MessageService::DispatchPendingMessages(const PendingMessagesQueue
& queue
,
929 MessageChannelMap::iterator channel_iter
= channels_
.find(channel_id
);
930 if (channel_iter
!= channels_
.end()) {
931 for (const PendingMessage
& message
: queue
) {
932 DispatchMessage(message
.first
, channel_iter
->second
, message
.second
);
937 } // namespace extensions