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