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