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 "content/public/browser/notification_service.h"
26 #include "content/public/browser/render_frame_host.h"
27 #include "content/public/browser/render_process_host.h"
28 #include "content/public/browser/render_view_host.h"
29 #include "content/public/browser/render_widget_host.h"
30 #include "content/public/browser/render_widget_host_view.h"
31 #include "content/public/browser/site_instance.h"
32 #include "content/public/browser/web_contents.h"
33 #include "content/public/common/child_process_host.h"
34 #include "extensions/browser/event_router.h"
35 #include "extensions/browser/extension_host.h"
36 #include "extensions/browser/extension_registry.h"
37 #include "extensions/browser/extension_system.h"
38 #include "extensions/browser/extensions_browser_client.h"
39 #include "extensions/browser/guest_view/web_view/web_view_guest.h"
40 #include "extensions/browser/lazy_background_task_queue.h"
41 #include "extensions/browser/pref_names.h"
42 #include "extensions/browser/process_manager.h"
43 #include "extensions/common/extension.h"
44 #include "extensions/common/guest_view/guest_view_constants.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_id
;
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_id
)
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_id(include_guest_process_id
) {
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 ExtensionSystem::Get(context
)->lazy_background_task_queue()),
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_id
= 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_id
= true;
344 scoped_ptr
<OpenChannelParams
> params(new OpenChannelParams(
345 source_process_id
, source_tab
.Pass(), source_frame_id
,
346 -1, // no target_frame_id for a channel to an extension/background page.
347 nullptr, receiver_port_id
, source_extension_id
, target_extension_id
,
348 source_url
, channel_name
, include_tls_channel_id
,
349 include_guest_process_id
));
351 pending_incognito_channels_
[GET_CHANNEL_ID(params
->receiver_port_id
)] =
352 PendingMessagesQueue();
353 if (context
->IsOffTheRecord() &&
354 !util::IsIncognitoEnabled(target_extension_id
, context
)) {
355 // Give the user a chance to accept an incognito connection from the web if
356 // they haven't already, with the conditions:
357 // - Only for spanning-mode incognito. We don't want the complication of
358 // spinning up an additional process here which might need to do some
359 // setup that we're not expecting.
360 // - Only for extensions that can't normally be enabled in incognito, since
361 // that surface (e.g. chrome://extensions) should be the only one for
362 // enabling in incognito. In practice this means platform apps only.
363 if (!is_web_connection
|| IncognitoInfo::IsSplitMode(target_extension
) ||
364 target_extension
->can_be_incognito_enabled()) {
365 OnOpenChannelAllowed(params
.Pass(), false);
369 // If the target extension isn't even listening for connect/message events,
370 // there is no need to go any further and the connection should be
371 // rejected without showing a prompt. See http://crbug.com/442497
372 EventRouter
* event_router
= EventRouter::Get(context
);
373 const char* const events
[] = {"runtime.onConnectExternal",
374 "runtime.onMessageExternal",
375 "extension.onRequestExternal",
377 bool has_event_listener
= false;
378 for (const char* const* event
= events
; *event
; event
++) {
379 has_event_listener
|=
380 event_router
->ExtensionHasEventListener(target_extension_id
, *event
);
382 if (!has_event_listener
) {
383 OnOpenChannelAllowed(params
.Pass(), false);
387 // This check may show a dialog.
388 IncognitoConnectability::Get(context
)
389 ->Query(target_extension
, source_contents
, source_url
,
390 base::Bind(&MessageService::OnOpenChannelAllowed
,
391 weak_factory_
.GetWeakPtr(), base::Passed(¶ms
)));
395 OnOpenChannelAllowed(params
.Pass(), true);
398 void MessageService::OpenChannelToNativeApp(
399 int source_process_id
,
400 int source_routing_id
,
401 int receiver_port_id
,
402 const std::string
& source_extension_id
,
403 const std::string
& native_app_name
) {
404 content::RenderProcessHost
* source
=
405 content::RenderProcessHost::FromID(source_process_id
);
409 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
410 Profile
* profile
= Profile::FromBrowserContext(source
->GetBrowserContext());
411 ExtensionService
* extension_service
=
412 ExtensionSystem::Get(profile
)->extension_service();
413 bool has_permission
= false;
414 if (extension_service
) {
415 const Extension
* extension
=
416 extension_service
->GetExtensionById(source_extension_id
, false);
417 has_permission
= extension
&&
418 extension
->permissions_data()->HasAPIPermission(
419 APIPermission::kNativeMessaging
);
422 if (!has_permission
) {
423 DispatchOnDisconnect(source
, receiver_port_id
, kMissingPermissionError
);
427 PrefService
* pref_service
= profile
->GetPrefs();
429 // Verify that the host is not blocked by policies.
430 PolicyPermission policy_permission
=
431 IsNativeMessagingHostAllowed(pref_service
, native_app_name
);
432 if (policy_permission
== DISALLOW
) {
433 DispatchOnDisconnect(source
, receiver_port_id
, kProhibitedByPoliciesError
);
437 scoped_ptr
<MessageChannel
> channel(new MessageChannel());
438 channel
->opener
.reset(new ExtensionMessagePort(source
, MSG_ROUTING_CONTROL
,
439 source_extension_id
));
441 // Get handle of the native view and pass it to the native messaging host.
442 content::RenderWidgetHost
* render_widget_host
=
443 content::RenderWidgetHost::FromID(source_process_id
, source_routing_id
);
444 gfx::NativeView native_view
=
445 (render_widget_host
&& render_widget_host
->GetView())
446 ? render_widget_host
->GetView()->GetNativeView()
449 std::string error
= kReceivingEndDoesntExistError
;
450 scoped_ptr
<NativeMessageHost
> native_host
= NativeMessageHost::Create(
454 policy_permission
== ALLOW_ALL
,
457 // Abandon the channel.
458 if (!native_host
.get()) {
459 LOG(ERROR
) << "Failed to create native process.";
460 DispatchOnDisconnect(source
, receiver_port_id
, error
);
463 channel
->receiver
.reset(new NativeMessagePort(
464 weak_factory_
.GetWeakPtr(), receiver_port_id
, native_host
.Pass()));
466 // Keep the opener alive until the channel is closed.
467 channel
->opener
->IncrementLazyKeepaliveCount();
469 AddChannel(channel
.release(), receiver_port_id
);
470 #else // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
471 const char kNativeMessagingNotSupportedError
[] =
472 "Native Messaging is not supported on this platform.";
473 DispatchOnDisconnect(
474 source
, receiver_port_id
, kNativeMessagingNotSupportedError
);
475 #endif // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
478 void MessageService::OpenChannelToTab(
479 int source_process_id
, int source_routing_id
, int receiver_port_id
,
480 int tab_id
, int frame_id
, const std::string
& extension_id
,
481 const std::string
& channel_name
) {
482 content::RenderProcessHost
* source
=
483 content::RenderProcessHost::FromID(source_process_id
);
486 Profile
* profile
= Profile::FromBrowserContext(source
->GetBrowserContext());
488 WebContents
* contents
= NULL
;
489 scoped_ptr
<MessagePort
> receiver
;
490 if (!ExtensionTabUtil::GetTabById(tab_id
, profile
, true, NULL
, NULL
,
492 contents
->GetController().NeedsReload()) {
493 // The tab isn't loaded yet. Don't attempt to connect.
494 DispatchOnDisconnect(
495 source
, receiver_port_id
, kReceivingEndDoesntExistError
);
499 int receiver_routing_id
;
501 // Positive frame ID is child frame.
502 int receiver_process_id
= contents
->GetRenderProcessHost()->GetID();
503 if (!content::RenderFrameHost::FromID(receiver_process_id
, frame_id
)) {
504 // Frame does not exist.
505 DispatchOnDisconnect(
506 source
, receiver_port_id
, kReceivingEndDoesntExistError
);
509 receiver_routing_id
= frame_id
;
510 } else if (frame_id
== 0) {
511 // Frame ID 0 is main frame.
512 receiver_routing_id
= contents
->GetMainFrame()->GetRoutingID();
514 DCHECK_EQ(-1, frame_id
);
515 // If the frame ID is not set (i.e. -1), then the channel has to be opened
517 // TODO(robwu): Update logic so that frames that are not hosted in the main
518 // frame's process can also receive the port.
519 receiver_routing_id
= contents
->GetMainFrame()->GetRoutingID();
521 receiver
.reset(new ExtensionMessagePort(
522 contents
->GetRenderProcessHost(), receiver_routing_id
, extension_id
));
524 scoped_ptr
<OpenChannelParams
> params(new OpenChannelParams(
526 scoped_ptr
<base::DictionaryValue
>(), // Source tab doesn't make sense
527 // for opening to tabs.
528 -1, // If there is no tab, then there is no frame either.
530 receiver
.release(), receiver_port_id
, extension_id
, extension_id
,
531 GURL(), // Source URL doesn't make sense for opening to tabs.
533 false, // Connections to tabs don't get TLS channel IDs.
534 false)); // Connections to tabs aren't webview guests.
535 OpenChannelImpl(params
.Pass());
538 void MessageService::OpenChannelImpl(scoped_ptr
<OpenChannelParams
> params
) {
539 content::RenderProcessHost
* source
=
540 content::RenderProcessHost::FromID(params
->source_process_id
);
542 return; // Closed while in flight.
544 if (!params
->receiver
|| !params
->receiver
->GetRenderProcessHost()) {
545 DispatchOnDisconnect(source
, params
->receiver_port_id
,
546 kReceivingEndDoesntExistError
);
550 // Add extra paranoid CHECKs, since we have crash reports of this being NULL.
551 // http://code.google.com/p/chromium/issues/detail?id=19067
552 CHECK(params
->receiver
->GetRenderProcessHost());
554 MessageChannel
* channel(new MessageChannel
);
555 channel
->opener
.reset(new ExtensionMessagePort(source
, MSG_ROUTING_CONTROL
,
556 params
->source_extension_id
));
557 channel
->receiver
.reset(params
->receiver
.release());
559 CHECK(channel
->receiver
->GetRenderProcessHost());
561 AddChannel(channel
, params
->receiver_port_id
);
563 CHECK(channel
->receiver
->GetRenderProcessHost());
565 int guest_process_id
= content::ChildProcessHost::kInvalidUniqueID
;
566 if (params
->include_guest_process_id
)
567 guest_process_id
= params
->source_process_id
;
569 // Send the connect event to the receiver. Give it the opener's port ID (the
570 // opener has the opposite port ID).
571 channel
->receiver
->DispatchOnConnect(params
->receiver_port_id
,
572 params
->channel_name
,
573 params
->source_tab
.Pass(),
574 params
->source_frame_id
,
575 params
->target_frame_id
,
577 params
->source_extension_id
,
578 params
->target_extension_id
,
580 params
->tls_channel_id
);
582 // Keep both ends of the channel alive until the channel is closed.
583 channel
->opener
->IncrementLazyKeepaliveCount();
584 channel
->receiver
->IncrementLazyKeepaliveCount();
587 void MessageService::AddChannel(MessageChannel
* channel
, int receiver_port_id
) {
588 int channel_id
= GET_CHANNEL_ID(receiver_port_id
);
589 CHECK(channels_
.find(channel_id
) == channels_
.end());
590 channels_
[channel_id
] = channel
;
591 pending_lazy_background_page_channels_
.erase(channel_id
);
594 void MessageService::CloseChannel(int port_id
,
595 const std::string
& error_message
) {
596 // Note: The channel might be gone already, if the other side closed first.
597 int channel_id
= GET_CHANNEL_ID(port_id
);
598 MessageChannelMap::iterator it
= channels_
.find(channel_id
);
599 if (it
== channels_
.end()) {
600 PendingLazyBackgroundPageChannelMap::iterator pending
=
601 pending_lazy_background_page_channels_
.find(channel_id
);
602 if (pending
!= pending_lazy_background_page_channels_
.end()) {
603 lazy_background_task_queue_
->AddPendingTask(
604 pending
->second
.first
, pending
->second
.second
,
605 base::Bind(&MessageService::PendingLazyBackgroundPageCloseChannel
,
606 weak_factory_
.GetWeakPtr(), port_id
, error_message
));
610 CloseChannelImpl(it
, port_id
, error_message
, true);
613 void MessageService::CloseChannelImpl(
614 MessageChannelMap::iterator channel_iter
,
616 const std::string
& error_message
,
617 bool notify_other_port
) {
618 MessageChannel
* channel
= channel_iter
->second
;
620 // Notify the other side.
621 if (notify_other_port
) {
622 MessagePort
* port
= IS_OPENER_PORT_ID(closing_port_id
) ?
623 channel
->receiver
.get() : channel
->opener
.get();
624 port
->DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(closing_port_id
),
628 // Balance the IncrementLazyKeepaliveCount() in OpenChannelImpl.
629 channel
->opener
->DecrementLazyKeepaliveCount();
630 channel
->receiver
->DecrementLazyKeepaliveCount();
632 delete channel_iter
->second
;
633 channels_
.erase(channel_iter
);
636 void MessageService::PostMessage(int source_port_id
, const Message
& message
) {
637 int channel_id
= GET_CHANNEL_ID(source_port_id
);
638 MessageChannelMap::iterator iter
= channels_
.find(channel_id
);
639 if (iter
== channels_
.end()) {
640 // If this channel is pending, queue up the PostMessage to run once
641 // the channel opens.
642 EnqueuePendingMessage(source_port_id
, channel_id
, message
);
646 DispatchMessage(source_port_id
, iter
->second
, message
);
649 void MessageService::Observe(int type
,
650 const content::NotificationSource
& source
,
651 const content::NotificationDetails
& details
) {
653 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED
:
654 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED
: {
655 content::RenderProcessHost
* renderer
=
656 content::Source
<content::RenderProcessHost
>(source
).ptr();
657 OnProcessClosed(renderer
);
666 void MessageService::OnProcessClosed(content::RenderProcessHost
* process
) {
667 // Close any channels that share this renderer. We notify the opposite
668 // port that his pair has closed.
669 for (MessageChannelMap::iterator it
= channels_
.begin();
670 it
!= channels_
.end(); ) {
671 MessageChannelMap::iterator current
= it
++;
673 content::RenderProcessHost
* opener_process
=
674 current
->second
->opener
->GetRenderProcessHost();
675 content::RenderProcessHost
* receiver_process
=
676 current
->second
->receiver
->GetRenderProcessHost();
678 // Only notify the other side if it has a different porocess host.
679 bool notify_other_port
= opener_process
&& receiver_process
&&
680 opener_process
!= receiver_process
;
682 if (opener_process
== process
) {
683 CloseChannelImpl(current
, GET_CHANNEL_OPENER_ID(current
->first
),
684 std::string(), notify_other_port
);
685 } else if (receiver_process
== process
) {
686 CloseChannelImpl(current
, GET_CHANNEL_RECEIVERS_ID(current
->first
),
687 std::string(), notify_other_port
);
692 void MessageService::EnqueuePendingMessage(int source_port_id
,
694 const Message
& message
) {
695 PendingChannelMap::iterator pending_for_incognito
=
696 pending_incognito_channels_
.find(channel_id
);
697 if (pending_for_incognito
!= pending_incognito_channels_
.end()) {
698 pending_for_incognito
->second
.push_back(
699 PendingMessage(source_port_id
, message
));
700 // A channel should only be holding pending messages because it is in one
702 DCHECK(!ContainsKey(pending_tls_channel_id_channels_
, channel_id
));
703 DCHECK(!ContainsKey(pending_lazy_background_page_channels_
, channel_id
));
706 PendingChannelMap::iterator pending_for_tls_channel_id
=
707 pending_tls_channel_id_channels_
.find(channel_id
);
708 if (pending_for_tls_channel_id
!= pending_tls_channel_id_channels_
.end()) {
709 pending_for_tls_channel_id
->second
.push_back(
710 PendingMessage(source_port_id
, message
));
711 // A channel should only be holding pending messages because it is in one
713 DCHECK(!ContainsKey(pending_lazy_background_page_channels_
, channel_id
));
716 EnqueuePendingMessageForLazyBackgroundLoad(source_port_id
,
721 void MessageService::EnqueuePendingMessageForLazyBackgroundLoad(
724 const Message
& message
) {
725 PendingLazyBackgroundPageChannelMap::iterator pending
=
726 pending_lazy_background_page_channels_
.find(channel_id
);
727 if (pending
!= pending_lazy_background_page_channels_
.end()) {
728 lazy_background_task_queue_
->AddPendingTask(
729 pending
->second
.first
, pending
->second
.second
,
730 base::Bind(&MessageService::PendingLazyBackgroundPagePostMessage
,
731 weak_factory_
.GetWeakPtr(), source_port_id
, message
));
735 void MessageService::DispatchMessage(int source_port_id
,
736 MessageChannel
* channel
,
737 const Message
& message
) {
738 // Figure out which port the ID corresponds to.
739 int dest_port_id
= GET_OPPOSITE_PORT_ID(source_port_id
);
740 MessagePort
* port
= IS_OPENER_PORT_ID(dest_port_id
) ?
741 channel
->opener
.get() : channel
->receiver
.get();
743 port
->DispatchOnMessage(message
, dest_port_id
);
746 bool MessageService::MaybeAddPendingLazyBackgroundPageOpenChannelTask(
747 BrowserContext
* context
,
748 const Extension
* extension
,
749 scoped_ptr
<OpenChannelParams
>* params
,
750 const PendingMessagesQueue
& pending_messages
) {
751 if (!BackgroundInfo::HasLazyBackgroundPage(extension
))
754 // If the extension uses spanning incognito mode, make sure we're always
755 // using the original profile since that is what the extension process
757 if (!IncognitoInfo::IsSplitMode(extension
))
758 context
= ExtensionsBrowserClient::Get()->GetOriginalContext(context
);
760 if (!lazy_background_task_queue_
->ShouldEnqueueTask(context
, extension
))
763 int channel_id
= GET_CHANNEL_ID((*params
)->receiver_port_id
);
764 pending_lazy_background_page_channels_
[channel_id
] =
765 PendingLazyBackgroundPageChannel(context
, extension
->id());
766 int source_id
= (*params
)->source_process_id
;
767 lazy_background_task_queue_
->AddPendingTask(
768 context
, extension
->id(),
769 base::Bind(&MessageService::PendingLazyBackgroundPageOpenChannel
,
770 weak_factory_
.GetWeakPtr(), base::Passed(params
), source_id
));
772 for (const PendingMessage
& message
: pending_messages
) {
773 EnqueuePendingMessageForLazyBackgroundLoad(message
.first
, channel_id
,
779 void MessageService::OnOpenChannelAllowed(scoped_ptr
<OpenChannelParams
> params
,
781 int channel_id
= GET_CHANNEL_ID(params
->receiver_port_id
);
783 PendingChannelMap::iterator pending_for_incognito
=
784 pending_incognito_channels_
.find(channel_id
);
785 if (pending_for_incognito
== pending_incognito_channels_
.end()) {
789 PendingMessagesQueue pending_messages
;
790 pending_messages
.swap(pending_for_incognito
->second
);
791 pending_incognito_channels_
.erase(pending_for_incognito
);
793 // Re-lookup the source process since it may no longer be valid.
794 content::RenderProcessHost
* source
=
795 content::RenderProcessHost::FromID(params
->source_process_id
);
801 DispatchOnDisconnect(source
, params
->receiver_port_id
,
802 kReceivingEndDoesntExistError
);
806 BrowserContext
* context
= source
->GetBrowserContext();
808 // Note: we use the source's profile here. If the source is an incognito
809 // process, we will use the incognito EPM to find the right extension process,
810 // which depends on whether the extension uses spanning or split mode.
811 params
->receiver
.reset(new ExtensionMessagePort(
812 GetExtensionProcess(context
, params
->target_extension_id
),
813 MSG_ROUTING_CONTROL
, params
->target_extension_id
));
815 // If the target requests the TLS channel id, begin the lookup for it.
816 // The target might also be a lazy background page, checked next, but the
817 // loading of lazy background pages continues asynchronously, so enqueue
818 // messages awaiting TLS channel ID first.
819 if (params
->include_tls_channel_id
) {
820 // Transfer pending messages to the next pending channel list.
821 pending_tls_channel_id_channels_
[channel_id
].swap(pending_messages
);
822 // Capture this reference before params is invalidated by base::Passed().
823 const GURL
& source_url
= params
->source_url
;
824 property_provider_
.GetChannelID(
825 Profile::FromBrowserContext(context
), source_url
,
826 base::Bind(&MessageService::GotChannelID
, weak_factory_
.GetWeakPtr(),
827 base::Passed(¶ms
)));
831 ExtensionRegistry
* registry
= ExtensionRegistry::Get(context
);
832 const Extension
* target_extension
=
833 registry
->enabled_extensions().GetByID(params
->target_extension_id
);
834 if (!target_extension
) {
835 DispatchOnDisconnect(source
, params
->receiver_port_id
,
836 kReceivingEndDoesntExistError
);
840 // The target might be a lazy background page. In that case, we have to check
841 // if it is loaded and ready, and if not, queue up the task and load the
843 if (!MaybeAddPendingLazyBackgroundPageOpenChannelTask(
844 context
, target_extension
, ¶ms
, pending_messages
)) {
845 OpenChannelImpl(params
.Pass());
846 DispatchPendingMessages(pending_messages
, channel_id
);
850 void MessageService::GotChannelID(scoped_ptr
<OpenChannelParams
> params
,
851 const std::string
& tls_channel_id
) {
852 params
->tls_channel_id
.assign(tls_channel_id
);
853 int channel_id
= GET_CHANNEL_ID(params
->receiver_port_id
);
855 PendingChannelMap::iterator pending_for_tls_channel_id
=
856 pending_tls_channel_id_channels_
.find(channel_id
);
857 if (pending_for_tls_channel_id
== pending_tls_channel_id_channels_
.end()) {
861 PendingMessagesQueue pending_messages
;
862 pending_messages
.swap(pending_for_tls_channel_id
->second
);
863 pending_tls_channel_id_channels_
.erase(pending_for_tls_channel_id
);
865 // Re-lookup the source process since it may no longer be valid.
866 content::RenderProcessHost
* source
=
867 content::RenderProcessHost::FromID(params
->source_process_id
);
872 BrowserContext
* context
= source
->GetBrowserContext();
873 ExtensionRegistry
* registry
= ExtensionRegistry::Get(context
);
874 const Extension
* target_extension
=
875 registry
->enabled_extensions().GetByID(params
->target_extension_id
);
876 if (!target_extension
) {
877 DispatchOnDisconnect(source
, params
->receiver_port_id
,
878 kReceivingEndDoesntExistError
);
882 if (!MaybeAddPendingLazyBackgroundPageOpenChannelTask(
883 context
, target_extension
, ¶ms
, pending_messages
)) {
884 OpenChannelImpl(params
.Pass());
885 DispatchPendingMessages(pending_messages
, channel_id
);
889 void MessageService::PendingLazyBackgroundPageOpenChannel(
890 scoped_ptr
<OpenChannelParams
> params
,
891 int source_process_id
,
892 ExtensionHost
* host
) {
894 return; // TODO(mpcomplete): notify source of disconnect?
896 params
->receiver
.reset(new ExtensionMessagePort(host
->render_process_host(),
898 params
->target_extension_id
));
899 OpenChannelImpl(params
.Pass());
902 void MessageService::DispatchOnDisconnect(content::RenderProcessHost
* source
,
904 const std::string
& error_message
) {
905 ExtensionMessagePort
port(source
, MSG_ROUTING_CONTROL
, "");
906 port
.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(port_id
), error_message
);
909 void MessageService::DispatchPendingMessages(const PendingMessagesQueue
& queue
,
911 MessageChannelMap::iterator channel_iter
= channels_
.find(channel_id
);
912 if (channel_iter
!= channels_
.end()) {
913 for (const PendingMessage
& message
: queue
) {
914 DispatchMessage(message
.first
, channel_iter
->second
, message
.second
);
919 } // namespace extensions