Revert 285173 "Removed InProcessBrowserTest::CleanUpOnMainThread()"
[chromium-blink-merge.git] / chrome / browser / extensions / api / messaging / message_service.cc
blob8f336f2f46cc0177ec0a8600d0d6077322e642f8
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/stl_util.h"
14 #include "base/values.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_process_host.h"
27 #include "content/public/browser/render_view_host.h"
28 #include "content/public/browser/render_widget_host.h"
29 #include "content/public/browser/render_widget_host_view.h"
30 #include "content/public/browser/site_instance.h"
31 #include "content/public/browser/web_contents.h"
32 #include "extensions/browser/extension_host.h"
33 #include "extensions/browser/extension_system.h"
34 #include "extensions/browser/extension_util.h"
35 #include "extensions/browser/extensions_browser_client.h"
36 #include "extensions/browser/lazy_background_task_queue.h"
37 #include "extensions/browser/process_manager.h"
38 #include "extensions/common/extension.h"
39 #include "extensions/common/extension_messages.h"
40 #include "extensions/common/manifest_constants.h"
41 #include "extensions/common/manifest_handlers/background_info.h"
42 #include "extensions/common/manifest_handlers/externally_connectable.h"
43 #include "extensions/common/manifest_handlers/incognito_info.h"
44 #include "extensions/common/permissions/permissions_data.h"
45 #include "net/base/completion_callback.h"
46 #include "url/gurl.h"
48 using content::BrowserContext;
49 using content::SiteInstance;
50 using content::WebContents;
52 // Since we have 2 ports for every channel, we just index channels by half the
53 // port ID.
54 #define GET_CHANNEL_ID(port_id) ((port_id) / 2)
55 #define GET_CHANNEL_OPENER_ID(channel_id) ((channel_id) * 2)
56 #define GET_CHANNEL_RECEIVERS_ID(channel_id) ((channel_id) * 2 + 1)
58 // Port1 is always even, port2 is always odd.
59 #define IS_OPENER_PORT_ID(port_id) (((port_id) & 1) == 0)
61 // Change even to odd and vice versa, to get the other side of a given channel.
62 #define GET_OPPOSITE_PORT_ID(source_port_id) ((source_port_id) ^ 1)
64 namespace extensions {
66 const char kReceivingEndDoesntExistError[] =
67 "Could not establish connection. Receiving end does not exist.";
68 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
69 const char kMissingPermissionError[] =
70 "Access to native messaging requires nativeMessaging permission.";
71 const char kProhibitedByPoliciesError[] =
72 "Access to the native messaging host was disabled by the system "
73 "administrator.";
74 #endif
76 struct MessageService::MessageChannel {
77 scoped_ptr<MessagePort> opener;
78 scoped_ptr<MessagePort> receiver;
81 struct MessageService::OpenChannelParams {
82 content::RenderProcessHost* source;
83 base::DictionaryValue source_tab;
84 scoped_ptr<MessagePort> receiver;
85 int receiver_port_id;
86 std::string source_extension_id;
87 std::string target_extension_id;
88 GURL source_url;
89 std::string channel_name;
90 bool include_tls_channel_id;
91 std::string tls_channel_id;
93 // Takes ownership of receiver.
94 OpenChannelParams(content::RenderProcessHost* source,
95 scoped_ptr<base::DictionaryValue> source_tab,
96 MessagePort* receiver,
97 int receiver_port_id,
98 const std::string& source_extension_id,
99 const std::string& target_extension_id,
100 const GURL& source_url,
101 const std::string& channel_name,
102 bool include_tls_channel_id)
103 : source(source),
104 receiver(receiver),
105 receiver_port_id(receiver_port_id),
106 source_extension_id(source_extension_id),
107 target_extension_id(target_extension_id),
108 source_url(source_url),
109 channel_name(channel_name),
110 include_tls_channel_id(include_tls_channel_id) {
111 if (source_tab)
112 this->source_tab.Swap(source_tab.get());
115 private:
116 DISALLOW_COPY_AND_ASSIGN(OpenChannelParams);
119 namespace {
121 static base::StaticAtomicSequenceNumber g_next_channel_id;
122 static base::StaticAtomicSequenceNumber g_channel_id_overflow_count;
124 static content::RenderProcessHost* GetExtensionProcess(
125 BrowserContext* context,
126 const std::string& extension_id) {
127 SiteInstance* site_instance =
128 ExtensionSystem::Get(context)->process_manager()->GetSiteInstanceForURL(
129 Extension::GetBaseURLFromExtensionId(extension_id));
130 return site_instance->HasProcess() ? site_instance->GetProcess() : NULL;
133 } // namespace
135 content::RenderProcessHost*
136 MessageService::MessagePort::GetRenderProcessHost() {
137 return NULL;
140 // static
141 void MessageService::AllocatePortIdPair(int* port1, int* port2) {
142 unsigned channel_id =
143 static_cast<unsigned>(g_next_channel_id.GetNext()) % (kint32max/2);
145 if (channel_id == 0) {
146 int overflow_count = g_channel_id_overflow_count.GetNext();
147 if (overflow_count > 0)
148 UMA_HISTOGRAM_BOOLEAN("Extensions.AllocatePortIdPairOverflow", true);
151 unsigned port1_id = channel_id * 2;
152 unsigned port2_id = channel_id * 2 + 1;
154 // Sanity checks to make sure our channel<->port converters are correct.
155 DCHECK(IS_OPENER_PORT_ID(port1_id));
156 DCHECK_EQ(GET_OPPOSITE_PORT_ID(port1_id), port2_id);
157 DCHECK_EQ(GET_OPPOSITE_PORT_ID(port2_id), port1_id);
158 DCHECK_EQ(GET_CHANNEL_ID(port1_id), GET_CHANNEL_ID(port2_id));
159 DCHECK_EQ(GET_CHANNEL_ID(port1_id), channel_id);
160 DCHECK_EQ(GET_CHANNEL_OPENER_ID(channel_id), port1_id);
161 DCHECK_EQ(GET_CHANNEL_RECEIVERS_ID(channel_id), port2_id);
163 *port1 = port1_id;
164 *port2 = port2_id;
167 MessageService::MessageService(BrowserContext* context)
168 : lazy_background_task_queue_(
169 ExtensionSystem::Get(context)->lazy_background_task_queue()),
170 weak_factory_(this) {
171 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
172 content::NotificationService::AllBrowserContextsAndSources());
173 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
174 content::NotificationService::AllBrowserContextsAndSources());
177 MessageService::~MessageService() {
178 STLDeleteContainerPairSecondPointers(channels_.begin(), channels_.end());
179 channels_.clear();
182 static base::LazyInstance<BrowserContextKeyedAPIFactory<MessageService> >
183 g_factory = LAZY_INSTANCE_INITIALIZER;
185 // static
186 BrowserContextKeyedAPIFactory<MessageService>*
187 MessageService::GetFactoryInstance() {
188 return g_factory.Pointer();
191 // static
192 MessageService* MessageService::Get(BrowserContext* context) {
193 return BrowserContextKeyedAPIFactory<MessageService>::Get(context);
196 void MessageService::OpenChannelToExtension(
197 int source_process_id, int source_routing_id, int receiver_port_id,
198 const std::string& source_extension_id,
199 const std::string& target_extension_id,
200 const GURL& source_url,
201 const std::string& channel_name,
202 bool include_tls_channel_id) {
203 content::RenderProcessHost* source =
204 content::RenderProcessHost::FromID(source_process_id);
205 if (!source)
206 return;
207 BrowserContext* context = source->GetBrowserContext();
209 ExtensionSystem* extension_system = ExtensionSystem::Get(context);
210 DCHECK(extension_system);
211 const Extension* target_extension = extension_system->extension_service()->
212 extensions()->GetByID(target_extension_id);
213 if (!target_extension) {
214 DispatchOnDisconnect(
215 source, receiver_port_id, kReceivingEndDoesntExistError);
216 return;
219 // Only running ephemeral apps can receive messages. Idle cached ephemeral
220 // apps are invisible and should not be connectable.
221 if (util::IsEphemeralApp(target_extension_id, context) &&
222 util::IsExtensionIdle(target_extension_id, context)) {
223 DispatchOnDisconnect(
224 source, receiver_port_id, kReceivingEndDoesntExistError);
225 return;
228 bool is_web_connection = false;
230 if (source_extension_id != target_extension_id) {
231 // It's an external connection. Check the externally_connectable manifest
232 // key if it's present. If it's not, we allow connection from any extension
233 // but not webpages.
234 ExternallyConnectableInfo* externally_connectable =
235 static_cast<ExternallyConnectableInfo*>(
236 target_extension->GetManifestData(
237 manifest_keys::kExternallyConnectable));
238 bool is_externally_connectable = false;
240 if (externally_connectable) {
241 if (source_extension_id.empty()) {
242 // No source extension ID so the source was a web page. Check that the
243 // URL matches.
244 is_web_connection = true;
245 is_externally_connectable =
246 externally_connectable->matches.MatchesURL(source_url);
247 // Only include the TLS channel ID for externally connected web pages.
248 include_tls_channel_id &=
249 is_externally_connectable &&
250 externally_connectable->accepts_tls_channel_id;
251 } else {
252 // Source extension ID so the source was an extension. Check that the
253 // extension matches.
254 is_externally_connectable =
255 externally_connectable->IdCanConnect(source_extension_id);
257 } else {
258 // Default behaviour. Any extension, no webpages.
259 is_externally_connectable = !source_extension_id.empty();
262 if (!is_externally_connectable) {
263 // Important: use kReceivingEndDoesntExistError here so that we don't
264 // leak information about this extension to callers. This way it's
265 // indistinguishable from the extension just not existing.
266 DispatchOnDisconnect(
267 source, receiver_port_id, kReceivingEndDoesntExistError);
268 return;
272 WebContents* source_contents = tab_util::GetWebContentsByID(
273 source_process_id, source_routing_id);
275 if (context->IsOffTheRecord() &&
276 !util::IsIncognitoEnabled(target_extension_id, context)) {
277 // Give the user a chance to accept an incognito connection from the web if
278 // they haven't already, with the conditions:
279 // - Only for spanning-mode incognito. We don't want the complication of
280 // spinning up an additional process here which might need to do some
281 // setup that we're not expecting.
282 // - Only for extensions that can't normally be enabled in incognito, since
283 // that surface (e.g. chrome://extensions) should be the only one for
284 // enabling in incognito. In practice this means platform apps only.
285 if (!is_web_connection || IncognitoInfo::IsSplitMode(target_extension) ||
286 target_extension->can_be_incognito_enabled() ||
287 // This check may show a dialog.
288 !IncognitoConnectability::Get(context)
289 ->Query(target_extension, source_contents, source_url)) {
290 DispatchOnDisconnect(
291 source, receiver_port_id, kReceivingEndDoesntExistError);
292 return;
296 // Note: we use the source's profile here. If the source is an incognito
297 // process, we will use the incognito EPM to find the right extension process,
298 // which depends on whether the extension uses spanning or split mode.
299 MessagePort* receiver = new ExtensionMessagePort(
300 GetExtensionProcess(context, target_extension_id),
301 MSG_ROUTING_CONTROL,
302 target_extension_id);
304 // Include info about the opener's tab (if it was a tab).
305 scoped_ptr<base::DictionaryValue> source_tab;
306 GURL source_url_for_tab;
308 if (source_contents && ExtensionTabUtil::GetTabId(source_contents) >= 0) {
309 // Only the tab id is useful to platform apps for internal use. The
310 // unnecessary bits will be stripped out in
311 // MessagingBindings::DispatchOnConnect().
312 source_tab.reset(ExtensionTabUtil::CreateTabValue(source_contents));
313 source_url_for_tab = source_url;
316 OpenChannelParams* params = new OpenChannelParams(source,
317 source_tab.Pass(),
318 receiver,
319 receiver_port_id,
320 source_extension_id,
321 target_extension_id,
322 source_url_for_tab,
323 channel_name,
324 include_tls_channel_id);
326 // If the target requests the TLS channel id, begin the lookup for it.
327 // The target might also be a lazy background page, checked next, but the
328 // loading of lazy background pages continues asynchronously, so enqueue
329 // messages awaiting TLS channel ID first.
330 if (include_tls_channel_id) {
331 pending_tls_channel_id_channels_[GET_CHANNEL_ID(params->receiver_port_id)]
332 = PendingMessagesQueue();
333 property_provider_.GetDomainBoundCert(
334 Profile::FromBrowserContext(context),
335 source_url,
336 base::Bind(&MessageService::GotDomainBoundCert,
337 weak_factory_.GetWeakPtr(),
338 base::Passed(make_scoped_ptr(params))));
339 return;
342 // The target might be a lazy background page. In that case, we have to check
343 // if it is loaded and ready, and if not, queue up the task and load the
344 // page.
345 if (MaybeAddPendingLazyBackgroundPageOpenChannelTask(
346 context, target_extension, params)) {
347 return;
350 OpenChannelImpl(make_scoped_ptr(params));
353 void MessageService::OpenChannelToNativeApp(
354 int source_process_id,
355 int source_routing_id,
356 int receiver_port_id,
357 const std::string& source_extension_id,
358 const std::string& native_app_name) {
359 content::RenderProcessHost* source =
360 content::RenderProcessHost::FromID(source_process_id);
361 if (!source)
362 return;
364 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
365 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
366 ExtensionService* extension_service =
367 ExtensionSystem::Get(profile)->extension_service();
368 bool has_permission = false;
369 if (extension_service) {
370 const Extension* extension =
371 extension_service->GetExtensionById(source_extension_id, false);
372 has_permission = extension &&
373 extension->permissions_data()->HasAPIPermission(
374 APIPermission::kNativeMessaging);
377 if (!has_permission) {
378 DispatchOnDisconnect(source, receiver_port_id, kMissingPermissionError);
379 return;
382 PrefService* pref_service = profile->GetPrefs();
384 // Verify that the host is not blocked by policies.
385 NativeMessageProcessHost::PolicyPermission policy_permission =
386 NativeMessageProcessHost::IsHostAllowed(pref_service, native_app_name);
387 if (policy_permission == NativeMessageProcessHost::DISALLOW) {
388 DispatchOnDisconnect(source, receiver_port_id, kProhibitedByPoliciesError);
389 return;
392 scoped_ptr<MessageChannel> channel(new MessageChannel());
393 channel->opener.reset(new ExtensionMessagePort(source, MSG_ROUTING_CONTROL,
394 source_extension_id));
396 // Get handle of the native view and pass it to the native messaging host.
397 gfx::NativeView native_view =
398 content::RenderWidgetHost::FromID(source_process_id, source_routing_id)->
399 GetView()->GetNativeView();
401 scoped_ptr<NativeMessageProcessHost> native_process =
402 NativeMessageProcessHost::Create(
403 native_view,
404 base::WeakPtr<NativeMessageProcessHost::Client>(
405 weak_factory_.GetWeakPtr()),
406 source_extension_id, native_app_name, receiver_port_id,
407 policy_permission == NativeMessageProcessHost::ALLOW_ALL);
409 // Abandon the channel.
410 if (!native_process.get()) {
411 LOG(ERROR) << "Failed to create native process.";
412 DispatchOnDisconnect(
413 source, receiver_port_id, kReceivingEndDoesntExistError);
414 return;
416 channel->receiver.reset(new NativeMessagePort(native_process.release()));
418 // Keep the opener alive until the channel is closed.
419 channel->opener->IncrementLazyKeepaliveCount();
421 AddChannel(channel.release(), receiver_port_id);
422 #else // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
423 const char kNativeMessagingNotSupportedError[] =
424 "Native Messaging is not supported on this platform.";
425 DispatchOnDisconnect(
426 source, receiver_port_id, kNativeMessagingNotSupportedError);
427 #endif // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
430 void MessageService::OpenChannelToTab(
431 int source_process_id, int source_routing_id, int receiver_port_id,
432 int tab_id, const std::string& extension_id,
433 const std::string& channel_name) {
434 content::RenderProcessHost* source =
435 content::RenderProcessHost::FromID(source_process_id);
436 if (!source)
437 return;
438 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
440 WebContents* contents = NULL;
441 scoped_ptr<MessagePort> receiver;
442 if (ExtensionTabUtil::GetTabById(tab_id, profile, true,
443 NULL, NULL, &contents, NULL)) {
444 receiver.reset(new ExtensionMessagePort(
445 contents->GetRenderProcessHost(),
446 contents->GetRenderViewHost()->GetRoutingID(),
447 extension_id));
450 if (contents && contents->GetController().NeedsReload()) {
451 // The tab isn't loaded yet. Don't attempt to connect.
452 DispatchOnDisconnect(
453 source, receiver_port_id, kReceivingEndDoesntExistError);
454 return;
457 scoped_ptr<OpenChannelParams> params(new OpenChannelParams(
458 source,
459 scoped_ptr<base::DictionaryValue>(), // Source tab doesn't make sense
460 // for opening to tabs.
461 receiver.release(),
462 receiver_port_id,
463 extension_id,
464 extension_id,
465 GURL(), // Source URL doesn't make sense for opening to tabs.
466 channel_name,
467 false)); // Connections to tabs don't get TLS channel IDs.
468 OpenChannelImpl(params.Pass());
471 bool MessageService::OpenChannelImpl(scoped_ptr<OpenChannelParams> params) {
472 if (!params->source)
473 return false; // Closed while in flight.
475 if (!params->receiver || !params->receiver->GetRenderProcessHost()) {
476 DispatchOnDisconnect(params->source,
477 params->receiver_port_id,
478 kReceivingEndDoesntExistError);
479 return false;
482 // Add extra paranoid CHECKs, since we have crash reports of this being NULL.
483 // http://code.google.com/p/chromium/issues/detail?id=19067
484 CHECK(params->receiver->GetRenderProcessHost());
486 MessageChannel* channel(new MessageChannel);
487 channel->opener.reset(new ExtensionMessagePort(params->source,
488 MSG_ROUTING_CONTROL,
489 params->source_extension_id));
490 channel->receiver.reset(params->receiver.release());
492 CHECK(channel->receiver->GetRenderProcessHost());
494 AddChannel(channel, params->receiver_port_id);
496 CHECK(channel->receiver->GetRenderProcessHost());
498 // Send the connect event to the receiver. Give it the opener's port ID (the
499 // opener has the opposite port ID).
500 channel->receiver->DispatchOnConnect(params->receiver_port_id,
501 params->channel_name,
502 params->source_tab,
503 params->source_extension_id,
504 params->target_extension_id,
505 params->source_url,
506 params->tls_channel_id);
508 // Keep both ends of the channel alive until the channel is closed.
509 channel->opener->IncrementLazyKeepaliveCount();
510 channel->receiver->IncrementLazyKeepaliveCount();
511 return true;
514 void MessageService::AddChannel(MessageChannel* channel, int receiver_port_id) {
515 int channel_id = GET_CHANNEL_ID(receiver_port_id);
516 CHECK(channels_.find(channel_id) == channels_.end());
517 channels_[channel_id] = channel;
518 pending_lazy_background_page_channels_.erase(channel_id);
521 void MessageService::CloseChannel(int port_id,
522 const std::string& error_message) {
523 // Note: The channel might be gone already, if the other side closed first.
524 int channel_id = GET_CHANNEL_ID(port_id);
525 MessageChannelMap::iterator it = channels_.find(channel_id);
526 if (it == channels_.end()) {
527 PendingLazyBackgroundPageChannelMap::iterator pending =
528 pending_lazy_background_page_channels_.find(channel_id);
529 if (pending != pending_lazy_background_page_channels_.end()) {
530 lazy_background_task_queue_->AddPendingTask(
531 pending->second.first, pending->second.second,
532 base::Bind(&MessageService::PendingLazyBackgroundPageCloseChannel,
533 weak_factory_.GetWeakPtr(), port_id, error_message));
535 return;
537 CloseChannelImpl(it, port_id, error_message, true);
540 void MessageService::CloseChannelImpl(
541 MessageChannelMap::iterator channel_iter,
542 int closing_port_id,
543 const std::string& error_message,
544 bool notify_other_port) {
545 MessageChannel* channel = channel_iter->second;
547 // Notify the other side.
548 if (notify_other_port) {
549 MessagePort* port = IS_OPENER_PORT_ID(closing_port_id) ?
550 channel->receiver.get() : channel->opener.get();
551 port->DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(closing_port_id),
552 error_message);
555 // Balance the IncrementLazyKeepaliveCount() in OpenChannelImpl.
556 channel->opener->DecrementLazyKeepaliveCount();
557 channel->receiver->DecrementLazyKeepaliveCount();
559 delete channel_iter->second;
560 channels_.erase(channel_iter);
563 void MessageService::PostMessage(int source_port_id, const Message& message) {
564 int channel_id = GET_CHANNEL_ID(source_port_id);
565 MessageChannelMap::iterator iter = channels_.find(channel_id);
566 if (iter == channels_.end()) {
567 // If this channel is pending, queue up the PostMessage to run once
568 // the channel opens.
569 EnqueuePendingMessage(source_port_id, channel_id, message);
570 return;
573 DispatchMessage(source_port_id, iter->second, message);
576 void MessageService::PostMessageFromNativeProcess(int port_id,
577 const std::string& message) {
578 PostMessage(port_id, Message(message, false /* user_gesture */));
581 void MessageService::Observe(int type,
582 const content::NotificationSource& source,
583 const content::NotificationDetails& details) {
584 switch (type) {
585 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
586 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
587 content::RenderProcessHost* renderer =
588 content::Source<content::RenderProcessHost>(source).ptr();
589 OnProcessClosed(renderer);
590 break;
592 default:
593 NOTREACHED();
594 return;
598 void MessageService::OnProcessClosed(content::RenderProcessHost* process) {
599 // Close any channels that share this renderer. We notify the opposite
600 // port that his pair has closed.
601 for (MessageChannelMap::iterator it = channels_.begin();
602 it != channels_.end(); ) {
603 MessageChannelMap::iterator current = it++;
605 content::RenderProcessHost* opener_process =
606 current->second->opener->GetRenderProcessHost();
607 content::RenderProcessHost* receiver_process =
608 current->second->receiver->GetRenderProcessHost();
610 // Only notify the other side if it has a different porocess host.
611 bool notify_other_port = opener_process && receiver_process &&
612 opener_process != receiver_process;
614 if (opener_process == process) {
615 CloseChannelImpl(current, GET_CHANNEL_OPENER_ID(current->first),
616 std::string(), notify_other_port);
617 } else if (receiver_process == process) {
618 CloseChannelImpl(current, GET_CHANNEL_RECEIVERS_ID(current->first),
619 std::string(), notify_other_port);
624 void MessageService::EnqueuePendingMessage(int source_port_id,
625 int channel_id,
626 const Message& message) {
627 PendingTlsChannelIdMap::iterator pending_for_tls_channel_id =
628 pending_tls_channel_id_channels_.find(channel_id);
629 if (pending_for_tls_channel_id != pending_tls_channel_id_channels_.end()) {
630 pending_for_tls_channel_id->second.push_back(
631 PendingMessage(source_port_id, message));
632 // Pending messages must only be pending the TLS channel ID or lazy
633 // background page loading, never both.
634 return;
636 EnqueuePendingMessageForLazyBackgroundLoad(source_port_id,
637 channel_id,
638 message);
641 void MessageService::EnqueuePendingMessageForLazyBackgroundLoad(
642 int source_port_id,
643 int channel_id,
644 const Message& message) {
645 PendingLazyBackgroundPageChannelMap::iterator pending =
646 pending_lazy_background_page_channels_.find(channel_id);
647 if (pending != pending_lazy_background_page_channels_.end()) {
648 lazy_background_task_queue_->AddPendingTask(
649 pending->second.first, pending->second.second,
650 base::Bind(&MessageService::PendingLazyBackgroundPagePostMessage,
651 weak_factory_.GetWeakPtr(), source_port_id, message));
655 void MessageService::DispatchMessage(int source_port_id,
656 MessageChannel* channel,
657 const Message& message) {
658 // Figure out which port the ID corresponds to.
659 int dest_port_id = GET_OPPOSITE_PORT_ID(source_port_id);
660 MessagePort* port = IS_OPENER_PORT_ID(dest_port_id) ?
661 channel->opener.get() : channel->receiver.get();
663 port->DispatchOnMessage(message, dest_port_id);
666 bool MessageService::MaybeAddPendingLazyBackgroundPageOpenChannelTask(
667 BrowserContext* context,
668 const Extension* extension,
669 OpenChannelParams* params) {
670 if (!BackgroundInfo::HasLazyBackgroundPage(extension))
671 return false;
673 // If the extension uses spanning incognito mode, make sure we're always
674 // using the original profile since that is what the extension process
675 // will use.
676 if (!IncognitoInfo::IsSplitMode(extension))
677 context = ExtensionsBrowserClient::Get()->GetOriginalContext(context);
679 if (!lazy_background_task_queue_->ShouldEnqueueTask(context, extension))
680 return false;
682 pending_lazy_background_page_channels_
683 [GET_CHANNEL_ID(params->receiver_port_id)] =
684 PendingLazyBackgroundPageChannel(context, extension->id());
685 scoped_ptr<OpenChannelParams> scoped_params(params);
686 lazy_background_task_queue_->AddPendingTask(
687 context,
688 extension->id(),
689 base::Bind(&MessageService::PendingLazyBackgroundPageOpenChannel,
690 weak_factory_.GetWeakPtr(),
691 base::Passed(&scoped_params),
692 params->source->GetID()));
693 return true;
696 void MessageService::GotDomainBoundCert(scoped_ptr<OpenChannelParams> params,
697 const std::string& tls_channel_id) {
698 params->tls_channel_id.assign(tls_channel_id);
699 int channel_id = GET_CHANNEL_ID(params->receiver_port_id);
701 PendingTlsChannelIdMap::iterator pending_for_tls_channel_id =
702 pending_tls_channel_id_channels_.find(channel_id);
703 if (pending_for_tls_channel_id == pending_tls_channel_id_channels_.end()) {
704 NOTREACHED();
705 return;
708 BrowserContext* context = params->source->GetBrowserContext();
710 const Extension* target_extension =
711 ExtensionSystem::Get(context)->extension_service()->extensions()->GetByID(
712 params->target_extension_id);
713 if (!target_extension) {
714 pending_tls_channel_id_channels_.erase(channel_id);
715 DispatchOnDisconnect(
716 params->source, params->receiver_port_id,
717 kReceivingEndDoesntExistError);
718 return;
720 PendingMessagesQueue& pending_messages = pending_for_tls_channel_id->second;
721 if (MaybeAddPendingLazyBackgroundPageOpenChannelTask(
722 context, target_extension, params.get())) {
723 // Lazy background queue took ownership. Release ours.
724 ignore_result(params.release());
725 // Messages queued up waiting for the TLS channel ID now need to be queued
726 // up for the lazy background page to load.
727 for (PendingMessagesQueue::iterator it = pending_messages.begin();
728 it != pending_messages.end();
729 it++) {
730 EnqueuePendingMessageForLazyBackgroundLoad(it->first, channel_id,
731 it->second);
733 } else {
734 OpenChannelImpl(params.Pass());
735 // Messages queued up waiting for the TLS channel ID can be posted now.
736 MessageChannelMap::iterator channel_iter = channels_.find(channel_id);
737 if (channel_iter != channels_.end()) {
738 for (PendingMessagesQueue::iterator it = pending_messages.begin();
739 it != pending_messages.end();
740 it++) {
741 DispatchMessage(it->first, channel_iter->second, it->second);
745 pending_tls_channel_id_channels_.erase(channel_id);
748 void MessageService::PendingLazyBackgroundPageOpenChannel(
749 scoped_ptr<OpenChannelParams> params,
750 int source_process_id,
751 ExtensionHost* host) {
752 if (!host)
753 return; // TODO(mpcomplete): notify source of disconnect?
755 // Re-lookup the source process since it may no longer be valid.
756 content::RenderProcessHost* source =
757 content::RenderProcessHost::FromID(source_process_id);
758 if (!source)
759 return;
761 params->source = source;
762 params->receiver.reset(new ExtensionMessagePort(host->render_process_host(),
763 MSG_ROUTING_CONTROL,
764 params->target_extension_id));
765 OpenChannelImpl(params.Pass());
768 void MessageService::DispatchOnDisconnect(content::RenderProcessHost* source,
769 int port_id,
770 const std::string& error_message) {
771 ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, "");
772 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(port_id), error_message);
775 } // namespace extensions