Add ENABLE_MEDIA_ROUTER define to builds other than Android and iOS.
[chromium-blink-merge.git] / chrome / browser / extensions / api / messaging / message_service.cc
bloba300b98b8314b0e601c06ff6819af39cc46a1ad9
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/prefs/pref_service.h"
14 #include "base/stl_util.h"
15 #include "chrome/browser/chrome_notification_types.h"
16 #include "chrome/browser/extensions/api/messaging/extension_message_port.h"
17 #include "chrome/browser/extensions/api/messaging/incognito_connectability.h"
18 #include "chrome/browser/extensions/api/messaging/native_message_port.h"
19 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
20 #include "chrome/browser/extensions/extension_service.h"
21 #include "chrome/browser/extensions/extension_tab_util.h"
22 #include "chrome/browser/extensions/extension_util.h"
23 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/browser/tab_contents/tab_util.h"
25 #include "content/public/browser/notification_service.h"
26 #include "content/public/browser/render_frame_host.h"
27 #include "content/public/browser/render_process_host.h"
28 #include "content/public/browser/render_view_host.h"
29 #include "content/public/browser/render_widget_host.h"
30 #include "content/public/browser/render_widget_host_view.h"
31 #include "content/public/browser/site_instance.h"
32 #include "content/public/browser/web_contents.h"
33 #include "content/public/common/child_process_host.h"
34 #include "extensions/browser/event_router.h"
35 #include "extensions/browser/extension_host.h"
36 #include "extensions/browser/extension_registry.h"
37 #include "extensions/browser/extension_system.h"
38 #include "extensions/browser/extensions_browser_client.h"
39 #include "extensions/browser/guest_view/web_view/web_view_guest.h"
40 #include "extensions/browser/lazy_background_task_queue.h"
41 #include "extensions/browser/pref_names.h"
42 #include "extensions/browser/process_manager.h"
43 #include "extensions/common/extension.h"
44 #include "extensions/common/guest_view/guest_view_constants.h"
45 #include "extensions/common/manifest_constants.h"
46 #include "extensions/common/manifest_handlers/background_info.h"
47 #include "extensions/common/manifest_handlers/externally_connectable.h"
48 #include "extensions/common/manifest_handlers/incognito_info.h"
49 #include "extensions/common/permissions/permissions_data.h"
50 #include "net/base/completion_callback.h"
51 #include "url/gurl.h"
53 using content::BrowserContext;
54 using content::SiteInstance;
55 using content::WebContents;
57 // Since we have 2 ports for every channel, we just index channels by half the
58 // port ID.
59 #define GET_CHANNEL_ID(port_id) ((port_id) / 2)
60 #define GET_CHANNEL_OPENER_ID(channel_id) ((channel_id) * 2)
61 #define GET_CHANNEL_RECEIVERS_ID(channel_id) ((channel_id) * 2 + 1)
63 // Port1 is always even, port2 is always odd.
64 #define IS_OPENER_PORT_ID(port_id) (((port_id) & 1) == 0)
66 // Change even to odd and vice versa, to get the other side of a given channel.
67 #define GET_OPPOSITE_PORT_ID(source_port_id) ((source_port_id) ^ 1)
69 namespace extensions {
71 MessageService::PolicyPermission MessageService::IsNativeMessagingHostAllowed(
72 const PrefService* pref_service,
73 const std::string& native_host_name) {
74 PolicyPermission allow_result = ALLOW_ALL;
75 if (pref_service->IsManagedPreference(
76 pref_names::kNativeMessagingUserLevelHosts)) {
77 if (!pref_service->GetBoolean(pref_names::kNativeMessagingUserLevelHosts))
78 allow_result = ALLOW_SYSTEM_ONLY;
81 // All native messaging hosts are allowed if there is no blacklist.
82 if (!pref_service->IsManagedPreference(pref_names::kNativeMessagingBlacklist))
83 return allow_result;
84 const base::ListValue* blacklist =
85 pref_service->GetList(pref_names::kNativeMessagingBlacklist);
86 if (!blacklist)
87 return allow_result;
89 // Check if the name or the wildcard is in the blacklist.
90 base::StringValue name_value(native_host_name);
91 base::StringValue wildcard_value("*");
92 if (blacklist->Find(name_value) == blacklist->end() &&
93 blacklist->Find(wildcard_value) == blacklist->end()) {
94 return allow_result;
97 // The native messaging host is blacklisted. Check the whitelist.
98 if (pref_service->IsManagedPreference(
99 pref_names::kNativeMessagingWhitelist)) {
100 const base::ListValue* whitelist =
101 pref_service->GetList(pref_names::kNativeMessagingWhitelist);
102 if (whitelist && whitelist->Find(name_value) != whitelist->end())
103 return allow_result;
106 return DISALLOW;
109 const char kReceivingEndDoesntExistError[] =
110 "Could not establish connection. Receiving end does not exist.";
111 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
112 const char kMissingPermissionError[] =
113 "Access to native messaging requires nativeMessaging permission.";
114 const char kProhibitedByPoliciesError[] =
115 "Access to the native messaging host was disabled by the system "
116 "administrator.";
117 #endif
119 struct MessageService::MessageChannel {
120 scoped_ptr<MessagePort> opener;
121 scoped_ptr<MessagePort> receiver;
124 struct MessageService::OpenChannelParams {
125 int source_process_id;
126 scoped_ptr<base::DictionaryValue> source_tab;
127 int source_frame_id;
128 int target_frame_id;
129 scoped_ptr<MessagePort> receiver;
130 int receiver_port_id;
131 std::string source_extension_id;
132 std::string target_extension_id;
133 GURL source_url;
134 std::string channel_name;
135 bool include_tls_channel_id;
136 std::string tls_channel_id;
137 bool include_guest_process_id;
139 // Takes ownership of receiver.
140 OpenChannelParams(int source_process_id,
141 scoped_ptr<base::DictionaryValue> source_tab,
142 int source_frame_id,
143 int target_frame_id,
144 MessagePort* receiver,
145 int receiver_port_id,
146 const std::string& source_extension_id,
147 const std::string& target_extension_id,
148 const GURL& source_url,
149 const std::string& channel_name,
150 bool include_tls_channel_id,
151 bool include_guest_process_id)
152 : source_process_id(source_process_id),
153 source_frame_id(source_frame_id),
154 target_frame_id(target_frame_id),
155 receiver(receiver),
156 receiver_port_id(receiver_port_id),
157 source_extension_id(source_extension_id),
158 target_extension_id(target_extension_id),
159 source_url(source_url),
160 channel_name(channel_name),
161 include_tls_channel_id(include_tls_channel_id),
162 include_guest_process_id(include_guest_process_id) {
163 if (source_tab)
164 this->source_tab = source_tab.Pass();
167 private:
168 DISALLOW_COPY_AND_ASSIGN(OpenChannelParams);
171 namespace {
173 static base::StaticAtomicSequenceNumber g_next_channel_id;
174 static base::StaticAtomicSequenceNumber g_channel_id_overflow_count;
176 static content::RenderProcessHost* GetExtensionProcess(
177 BrowserContext* context,
178 const std::string& extension_id) {
179 scoped_refptr<SiteInstance> site_instance =
180 ProcessManager::Get(context)->GetSiteInstanceForURL(
181 Extension::GetBaseURLFromExtensionId(extension_id));
182 return site_instance->HasProcess() ? site_instance->GetProcess() : NULL;
185 } // namespace
187 content::RenderProcessHost*
188 MessageService::MessagePort::GetRenderProcessHost() {
189 return NULL;
192 // static
193 void MessageService::AllocatePortIdPair(int* port1, int* port2) {
194 unsigned channel_id =
195 static_cast<unsigned>(g_next_channel_id.GetNext()) % (kint32max/2);
197 if (channel_id == 0) {
198 int overflow_count = g_channel_id_overflow_count.GetNext();
199 if (overflow_count > 0)
200 UMA_HISTOGRAM_BOOLEAN("Extensions.AllocatePortIdPairOverflow", true);
203 unsigned port1_id = channel_id * 2;
204 unsigned port2_id = channel_id * 2 + 1;
206 // Sanity checks to make sure our channel<->port converters are correct.
207 DCHECK(IS_OPENER_PORT_ID(port1_id));
208 DCHECK_EQ(GET_OPPOSITE_PORT_ID(port1_id), port2_id);
209 DCHECK_EQ(GET_OPPOSITE_PORT_ID(port2_id), port1_id);
210 DCHECK_EQ(GET_CHANNEL_ID(port1_id), GET_CHANNEL_ID(port2_id));
211 DCHECK_EQ(GET_CHANNEL_ID(port1_id), channel_id);
212 DCHECK_EQ(GET_CHANNEL_OPENER_ID(channel_id), port1_id);
213 DCHECK_EQ(GET_CHANNEL_RECEIVERS_ID(channel_id), port2_id);
215 *port1 = port1_id;
216 *port2 = port2_id;
219 MessageService::MessageService(BrowserContext* context)
220 : lazy_background_task_queue_(
221 ExtensionSystem::Get(context)->lazy_background_task_queue()),
222 weak_factory_(this) {
223 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
224 content::NotificationService::AllBrowserContextsAndSources());
225 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
226 content::NotificationService::AllBrowserContextsAndSources());
229 MessageService::~MessageService() {
230 STLDeleteContainerPairSecondPointers(channels_.begin(), channels_.end());
231 channels_.clear();
234 static base::LazyInstance<BrowserContextKeyedAPIFactory<MessageService> >
235 g_factory = LAZY_INSTANCE_INITIALIZER;
237 // static
238 BrowserContextKeyedAPIFactory<MessageService>*
239 MessageService::GetFactoryInstance() {
240 return g_factory.Pointer();
243 // static
244 MessageService* MessageService::Get(BrowserContext* context) {
245 return BrowserContextKeyedAPIFactory<MessageService>::Get(context);
248 void MessageService::OpenChannelToExtension(
249 int source_process_id, int source_routing_id, int receiver_port_id,
250 const std::string& source_extension_id,
251 const std::string& target_extension_id,
252 const GURL& source_url,
253 const std::string& channel_name,
254 bool include_tls_channel_id) {
255 content::RenderProcessHost* source =
256 content::RenderProcessHost::FromID(source_process_id);
257 if (!source)
258 return;
259 BrowserContext* context = source->GetBrowserContext();
261 ExtensionRegistry* registry = ExtensionRegistry::Get(context);
262 const Extension* target_extension =
263 registry->enabled_extensions().GetByID(target_extension_id);
264 if (!target_extension) {
265 DispatchOnDisconnect(
266 source, receiver_port_id, kReceivingEndDoesntExistError);
267 return;
270 bool is_web_connection = false;
272 if (source_extension_id != target_extension_id) {
273 // It's an external connection. Check the externally_connectable manifest
274 // key if it's present. If it's not, we allow connection from any extension
275 // but not webpages.
276 ExternallyConnectableInfo* externally_connectable =
277 static_cast<ExternallyConnectableInfo*>(
278 target_extension->GetManifestData(
279 manifest_keys::kExternallyConnectable));
280 bool is_externally_connectable = false;
282 if (externally_connectable) {
283 if (source_extension_id.empty()) {
284 // No source extension ID so the source was a web page. Check that the
285 // URL matches.
286 is_web_connection = true;
287 is_externally_connectable =
288 externally_connectable->matches.MatchesURL(source_url);
289 // Only include the TLS channel ID for externally connected web pages.
290 include_tls_channel_id &=
291 is_externally_connectable &&
292 externally_connectable->accepts_tls_channel_id;
293 } else {
294 // Source extension ID so the source was an extension. Check that the
295 // extension matches.
296 is_externally_connectable =
297 externally_connectable->IdCanConnect(source_extension_id);
299 } else {
300 // Default behaviour. Any extension, no webpages.
301 is_externally_connectable = !source_extension_id.empty();
304 if (!is_externally_connectable) {
305 // Important: use kReceivingEndDoesntExistError here so that we don't
306 // leak information about this extension to callers. This way it's
307 // indistinguishable from the extension just not existing.
308 DispatchOnDisconnect(
309 source, receiver_port_id, kReceivingEndDoesntExistError);
310 return;
314 WebContents* source_contents = tab_util::GetWebContentsByFrameID(
315 source_process_id, source_routing_id);
317 bool include_guest_process_id = false;
319 // Include info about the opener's tab (if it was a tab).
320 scoped_ptr<base::DictionaryValue> source_tab;
321 int source_frame_id = -1;
322 if (source_contents && ExtensionTabUtil::GetTabId(source_contents) >= 0) {
323 // Only the tab id is useful to platform apps for internal use. The
324 // unnecessary bits will be stripped out in
325 // MessagingBindings::DispatchOnConnect().
326 source_tab.reset(ExtensionTabUtil::CreateTabValue(source_contents));
328 content::RenderFrameHost* rfh =
329 content::RenderFrameHost::FromID(source_process_id, source_routing_id);
330 // Main frame's frameId is 0.
331 if (rfh)
332 source_frame_id = !rfh->GetParent() ? 0 : source_routing_id;
333 } else {
334 // Check to see if it was a WebView making the request.
335 // Sending messages from WebViews to extensions breaks webview isolation,
336 // so only allow component extensions to receive messages from WebViews.
337 bool is_web_view = !!WebViewGuest::FromWebContents(source_contents);
338 if (is_web_view && extensions::Manifest::IsComponentLocation(
339 target_extension->location())) {
340 include_guest_process_id = true;
344 scoped_ptr<OpenChannelParams> params(new OpenChannelParams(
345 source_process_id, source_tab.Pass(), source_frame_id,
346 -1, // no target_frame_id for a channel to an extension/background page.
347 nullptr, receiver_port_id, source_extension_id, target_extension_id,
348 source_url, channel_name, include_tls_channel_id,
349 include_guest_process_id));
351 pending_incognito_channels_[GET_CHANNEL_ID(params->receiver_port_id)] =
352 PendingMessagesQueue();
353 if (context->IsOffTheRecord() &&
354 !util::IsIncognitoEnabled(target_extension_id, context)) {
355 // Give the user a chance to accept an incognito connection from the web if
356 // they haven't already, with the conditions:
357 // - Only for spanning-mode incognito. We don't want the complication of
358 // spinning up an additional process here which might need to do some
359 // setup that we're not expecting.
360 // - Only for extensions that can't normally be enabled in incognito, since
361 // that surface (e.g. chrome://extensions) should be the only one for
362 // enabling in incognito. In practice this means platform apps only.
363 if (!is_web_connection || IncognitoInfo::IsSplitMode(target_extension) ||
364 target_extension->can_be_incognito_enabled()) {
365 OnOpenChannelAllowed(params.Pass(), false);
366 return;
369 // If the target extension isn't even listening for connect/message events,
370 // there is no need to go any further and the connection should be
371 // rejected without showing a prompt. See http://crbug.com/442497
372 EventRouter* event_router = EventRouter::Get(context);
373 const char* const events[] = {"runtime.onConnectExternal",
374 "runtime.onMessageExternal",
375 "extension.onRequestExternal",
376 nullptr};
377 bool has_event_listener = false;
378 for (const char* const* event = events; *event; event++) {
379 has_event_listener |=
380 event_router->ExtensionHasEventListener(target_extension_id, *event);
382 if (!has_event_listener) {
383 OnOpenChannelAllowed(params.Pass(), false);
384 return;
387 // This check may show a dialog.
388 IncognitoConnectability::Get(context)
389 ->Query(target_extension, source_contents, source_url,
390 base::Bind(&MessageService::OnOpenChannelAllowed,
391 weak_factory_.GetWeakPtr(), base::Passed(&params)));
392 return;
395 OnOpenChannelAllowed(params.Pass(), true);
398 void MessageService::OpenChannelToNativeApp(
399 int source_process_id,
400 int source_routing_id,
401 int receiver_port_id,
402 const std::string& source_extension_id,
403 const std::string& native_app_name) {
404 content::RenderProcessHost* source =
405 content::RenderProcessHost::FromID(source_process_id);
406 if (!source)
407 return;
409 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
410 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
411 ExtensionService* extension_service =
412 ExtensionSystem::Get(profile)->extension_service();
413 bool has_permission = false;
414 if (extension_service) {
415 const Extension* extension =
416 extension_service->GetExtensionById(source_extension_id, false);
417 has_permission = extension &&
418 extension->permissions_data()->HasAPIPermission(
419 APIPermission::kNativeMessaging);
422 if (!has_permission) {
423 DispatchOnDisconnect(source, receiver_port_id, kMissingPermissionError);
424 return;
427 PrefService* pref_service = profile->GetPrefs();
429 // Verify that the host is not blocked by policies.
430 PolicyPermission policy_permission =
431 IsNativeMessagingHostAllowed(pref_service, native_app_name);
432 if (policy_permission == DISALLOW) {
433 DispatchOnDisconnect(source, receiver_port_id, kProhibitedByPoliciesError);
434 return;
437 scoped_ptr<MessageChannel> channel(new MessageChannel());
438 channel->opener.reset(new ExtensionMessagePort(source, MSG_ROUTING_CONTROL,
439 source_extension_id));
441 // Get handle of the native view and pass it to the native messaging host.
442 content::RenderWidgetHost* render_widget_host =
443 content::RenderWidgetHost::FromID(source_process_id, source_routing_id);
444 gfx::NativeView native_view =
445 (render_widget_host && render_widget_host->GetView())
446 ? render_widget_host->GetView()->GetNativeView()
447 : nullptr;
449 std::string error = kReceivingEndDoesntExistError;
450 scoped_ptr<NativeMessageHost> native_host = NativeMessageHost::Create(
451 native_view,
452 source_extension_id,
453 native_app_name,
454 policy_permission == ALLOW_ALL,
455 &error);
457 // Abandon the channel.
458 if (!native_host.get()) {
459 LOG(ERROR) << "Failed to create native process.";
460 DispatchOnDisconnect(source, receiver_port_id, error);
461 return;
463 channel->receiver.reset(new NativeMessagePort(
464 weak_factory_.GetWeakPtr(), receiver_port_id, native_host.Pass()));
466 // Keep the opener alive until the channel is closed.
467 channel->opener->IncrementLazyKeepaliveCount();
469 AddChannel(channel.release(), receiver_port_id);
470 #else // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
471 const char kNativeMessagingNotSupportedError[] =
472 "Native Messaging is not supported on this platform.";
473 DispatchOnDisconnect(
474 source, receiver_port_id, kNativeMessagingNotSupportedError);
475 #endif // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
478 void MessageService::OpenChannelToTab(
479 int source_process_id, int source_routing_id, int receiver_port_id,
480 int tab_id, int frame_id, const std::string& extension_id,
481 const std::string& channel_name) {
482 content::RenderProcessHost* source =
483 content::RenderProcessHost::FromID(source_process_id);
484 if (!source)
485 return;
486 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
488 WebContents* contents = NULL;
489 scoped_ptr<MessagePort> receiver;
490 if (!ExtensionTabUtil::GetTabById(tab_id, profile, true, NULL, NULL,
491 &contents, NULL) ||
492 contents->GetController().NeedsReload()) {
493 // The tab isn't loaded yet. Don't attempt to connect.
494 DispatchOnDisconnect(
495 source, receiver_port_id, kReceivingEndDoesntExistError);
496 return;
499 int receiver_routing_id;
500 if (frame_id > 0) {
501 // Positive frame ID is child frame.
502 int receiver_process_id = contents->GetRenderProcessHost()->GetID();
503 if (!content::RenderFrameHost::FromID(receiver_process_id, frame_id)) {
504 // Frame does not exist.
505 DispatchOnDisconnect(
506 source, receiver_port_id, kReceivingEndDoesntExistError);
507 return;
509 receiver_routing_id = frame_id;
510 } else if (frame_id == 0) {
511 // Frame ID 0 is main frame.
512 receiver_routing_id = contents->GetMainFrame()->GetRoutingID();
513 } else {
514 DCHECK_EQ(-1, frame_id);
515 // If the frame ID is not set (i.e. -1), then the channel has to be opened
516 // in every frame.
517 // TODO(robwu): Update logic so that frames that are not hosted in the main
518 // frame's process can also receive the port.
519 receiver_routing_id = contents->GetMainFrame()->GetRoutingID();
521 receiver.reset(new ExtensionMessagePort(
522 contents->GetRenderProcessHost(), receiver_routing_id, extension_id));
524 scoped_ptr<OpenChannelParams> params(new OpenChannelParams(
525 source_process_id,
526 scoped_ptr<base::DictionaryValue>(), // Source tab doesn't make sense
527 // for opening to tabs.
528 -1, // If there is no tab, then there is no frame either.
529 frame_id,
530 receiver.release(), receiver_port_id, extension_id, extension_id,
531 GURL(), // Source URL doesn't make sense for opening to tabs.
532 channel_name,
533 false, // Connections to tabs don't get TLS channel IDs.
534 false)); // Connections to tabs aren't webview guests.
535 OpenChannelImpl(params.Pass());
538 void MessageService::OpenChannelImpl(scoped_ptr<OpenChannelParams> params) {
539 content::RenderProcessHost* source =
540 content::RenderProcessHost::FromID(params->source_process_id);
541 if (!source)
542 return; // Closed while in flight.
544 if (!params->receiver || !params->receiver->GetRenderProcessHost()) {
545 DispatchOnDisconnect(source, params->receiver_port_id,
546 kReceivingEndDoesntExistError);
547 return;
550 // Add extra paranoid CHECKs, since we have crash reports of this being NULL.
551 // http://code.google.com/p/chromium/issues/detail?id=19067
552 CHECK(params->receiver->GetRenderProcessHost());
554 MessageChannel* channel(new MessageChannel);
555 channel->opener.reset(new ExtensionMessagePort(source, MSG_ROUTING_CONTROL,
556 params->source_extension_id));
557 channel->receiver.reset(params->receiver.release());
559 CHECK(channel->receiver->GetRenderProcessHost());
561 AddChannel(channel, params->receiver_port_id);
563 CHECK(channel->receiver->GetRenderProcessHost());
565 int guest_process_id = content::ChildProcessHost::kInvalidUniqueID;
566 if (params->include_guest_process_id)
567 guest_process_id = params->source_process_id;
569 // Send the connect event to the receiver. Give it the opener's port ID (the
570 // opener has the opposite port ID).
571 channel->receiver->DispatchOnConnect(params->receiver_port_id,
572 params->channel_name,
573 params->source_tab.Pass(),
574 params->source_frame_id,
575 params->target_frame_id,
576 guest_process_id,
577 params->source_extension_id,
578 params->target_extension_id,
579 params->source_url,
580 params->tls_channel_id);
582 // Keep both ends of the channel alive until the channel is closed.
583 channel->opener->IncrementLazyKeepaliveCount();
584 channel->receiver->IncrementLazyKeepaliveCount();
587 void MessageService::AddChannel(MessageChannel* channel, int receiver_port_id) {
588 int channel_id = GET_CHANNEL_ID(receiver_port_id);
589 CHECK(channels_.find(channel_id) == channels_.end());
590 channels_[channel_id] = channel;
591 pending_lazy_background_page_channels_.erase(channel_id);
594 void MessageService::CloseChannel(int port_id,
595 const std::string& error_message) {
596 // Note: The channel might be gone already, if the other side closed first.
597 int channel_id = GET_CHANNEL_ID(port_id);
598 MessageChannelMap::iterator it = channels_.find(channel_id);
599 if (it == channels_.end()) {
600 PendingLazyBackgroundPageChannelMap::iterator pending =
601 pending_lazy_background_page_channels_.find(channel_id);
602 if (pending != pending_lazy_background_page_channels_.end()) {
603 lazy_background_task_queue_->AddPendingTask(
604 pending->second.first, pending->second.second,
605 base::Bind(&MessageService::PendingLazyBackgroundPageCloseChannel,
606 weak_factory_.GetWeakPtr(), port_id, error_message));
608 return;
610 CloseChannelImpl(it, port_id, error_message, true);
613 void MessageService::CloseChannelImpl(
614 MessageChannelMap::iterator channel_iter,
615 int closing_port_id,
616 const std::string& error_message,
617 bool notify_other_port) {
618 MessageChannel* channel = channel_iter->second;
620 // Notify the other side.
621 if (notify_other_port) {
622 MessagePort* port = IS_OPENER_PORT_ID(closing_port_id) ?
623 channel->receiver.get() : channel->opener.get();
624 port->DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(closing_port_id),
625 error_message);
628 // Balance the IncrementLazyKeepaliveCount() in OpenChannelImpl.
629 channel->opener->DecrementLazyKeepaliveCount();
630 channel->receiver->DecrementLazyKeepaliveCount();
632 delete channel_iter->second;
633 channels_.erase(channel_iter);
636 void MessageService::PostMessage(int source_port_id, const Message& message) {
637 int channel_id = GET_CHANNEL_ID(source_port_id);
638 MessageChannelMap::iterator iter = channels_.find(channel_id);
639 if (iter == channels_.end()) {
640 // If this channel is pending, queue up the PostMessage to run once
641 // the channel opens.
642 EnqueuePendingMessage(source_port_id, channel_id, message);
643 return;
646 DispatchMessage(source_port_id, iter->second, message);
649 void MessageService::Observe(int type,
650 const content::NotificationSource& source,
651 const content::NotificationDetails& details) {
652 switch (type) {
653 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
654 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
655 content::RenderProcessHost* renderer =
656 content::Source<content::RenderProcessHost>(source).ptr();
657 OnProcessClosed(renderer);
658 break;
660 default:
661 NOTREACHED();
662 return;
666 void MessageService::OnProcessClosed(content::RenderProcessHost* process) {
667 // Close any channels that share this renderer. We notify the opposite
668 // port that his pair has closed.
669 for (MessageChannelMap::iterator it = channels_.begin();
670 it != channels_.end(); ) {
671 MessageChannelMap::iterator current = it++;
673 content::RenderProcessHost* opener_process =
674 current->second->opener->GetRenderProcessHost();
675 content::RenderProcessHost* receiver_process =
676 current->second->receiver->GetRenderProcessHost();
678 // Only notify the other side if it has a different porocess host.
679 bool notify_other_port = opener_process && receiver_process &&
680 opener_process != receiver_process;
682 if (opener_process == process) {
683 CloseChannelImpl(current, GET_CHANNEL_OPENER_ID(current->first),
684 std::string(), notify_other_port);
685 } else if (receiver_process == process) {
686 CloseChannelImpl(current, GET_CHANNEL_RECEIVERS_ID(current->first),
687 std::string(), notify_other_port);
692 void MessageService::EnqueuePendingMessage(int source_port_id,
693 int channel_id,
694 const Message& message) {
695 PendingChannelMap::iterator pending_for_incognito =
696 pending_incognito_channels_.find(channel_id);
697 if (pending_for_incognito != pending_incognito_channels_.end()) {
698 pending_for_incognito->second.push_back(
699 PendingMessage(source_port_id, message));
700 // A channel should only be holding pending messages because it is in one
701 // of these states.
702 DCHECK(!ContainsKey(pending_tls_channel_id_channels_, channel_id));
703 DCHECK(!ContainsKey(pending_lazy_background_page_channels_, channel_id));
704 return;
706 PendingChannelMap::iterator pending_for_tls_channel_id =
707 pending_tls_channel_id_channels_.find(channel_id);
708 if (pending_for_tls_channel_id != pending_tls_channel_id_channels_.end()) {
709 pending_for_tls_channel_id->second.push_back(
710 PendingMessage(source_port_id, message));
711 // A channel should only be holding pending messages because it is in one
712 // of these states.
713 DCHECK(!ContainsKey(pending_lazy_background_page_channels_, channel_id));
714 return;
716 EnqueuePendingMessageForLazyBackgroundLoad(source_port_id,
717 channel_id,
718 message);
721 void MessageService::EnqueuePendingMessageForLazyBackgroundLoad(
722 int source_port_id,
723 int channel_id,
724 const Message& message) {
725 PendingLazyBackgroundPageChannelMap::iterator pending =
726 pending_lazy_background_page_channels_.find(channel_id);
727 if (pending != pending_lazy_background_page_channels_.end()) {
728 lazy_background_task_queue_->AddPendingTask(
729 pending->second.first, pending->second.second,
730 base::Bind(&MessageService::PendingLazyBackgroundPagePostMessage,
731 weak_factory_.GetWeakPtr(), source_port_id, message));
735 void MessageService::DispatchMessage(int source_port_id,
736 MessageChannel* channel,
737 const Message& message) {
738 // Figure out which port the ID corresponds to.
739 int dest_port_id = GET_OPPOSITE_PORT_ID(source_port_id);
740 MessagePort* port = IS_OPENER_PORT_ID(dest_port_id) ?
741 channel->opener.get() : channel->receiver.get();
743 port->DispatchOnMessage(message, dest_port_id);
746 bool MessageService::MaybeAddPendingLazyBackgroundPageOpenChannelTask(
747 BrowserContext* context,
748 const Extension* extension,
749 scoped_ptr<OpenChannelParams>* params,
750 const PendingMessagesQueue& pending_messages) {
751 if (!BackgroundInfo::HasLazyBackgroundPage(extension))
752 return false;
754 // If the extension uses spanning incognito mode, make sure we're always
755 // using the original profile since that is what the extension process
756 // will use.
757 if (!IncognitoInfo::IsSplitMode(extension))
758 context = ExtensionsBrowserClient::Get()->GetOriginalContext(context);
760 if (!lazy_background_task_queue_->ShouldEnqueueTask(context, extension))
761 return false;
763 int channel_id = GET_CHANNEL_ID((*params)->receiver_port_id);
764 pending_lazy_background_page_channels_[channel_id] =
765 PendingLazyBackgroundPageChannel(context, extension->id());
766 int source_id = (*params)->source_process_id;
767 lazy_background_task_queue_->AddPendingTask(
768 context, extension->id(),
769 base::Bind(&MessageService::PendingLazyBackgroundPageOpenChannel,
770 weak_factory_.GetWeakPtr(), base::Passed(params), source_id));
772 for (const PendingMessage& message : pending_messages) {
773 EnqueuePendingMessageForLazyBackgroundLoad(message.first, channel_id,
774 message.second);
776 return true;
779 void MessageService::OnOpenChannelAllowed(scoped_ptr<OpenChannelParams> params,
780 bool allowed) {
781 int channel_id = GET_CHANNEL_ID(params->receiver_port_id);
783 PendingChannelMap::iterator pending_for_incognito =
784 pending_incognito_channels_.find(channel_id);
785 if (pending_for_incognito == pending_incognito_channels_.end()) {
786 NOTREACHED();
787 return;
789 PendingMessagesQueue pending_messages;
790 pending_messages.swap(pending_for_incognito->second);
791 pending_incognito_channels_.erase(pending_for_incognito);
793 // Re-lookup the source process since it may no longer be valid.
794 content::RenderProcessHost* source =
795 content::RenderProcessHost::FromID(params->source_process_id);
796 if (!source) {
797 return;
800 if (!allowed) {
801 DispatchOnDisconnect(source, params->receiver_port_id,
802 kReceivingEndDoesntExistError);
803 return;
806 BrowserContext* context = source->GetBrowserContext();
808 // Note: we use the source's profile here. If the source is an incognito
809 // process, we will use the incognito EPM to find the right extension process,
810 // which depends on whether the extension uses spanning or split mode.
811 params->receiver.reset(new ExtensionMessagePort(
812 GetExtensionProcess(context, params->target_extension_id),
813 MSG_ROUTING_CONTROL, params->target_extension_id));
815 // If the target requests the TLS channel id, begin the lookup for it.
816 // The target might also be a lazy background page, checked next, but the
817 // loading of lazy background pages continues asynchronously, so enqueue
818 // messages awaiting TLS channel ID first.
819 if (params->include_tls_channel_id) {
820 // Transfer pending messages to the next pending channel list.
821 pending_tls_channel_id_channels_[channel_id].swap(pending_messages);
822 // Capture this reference before params is invalidated by base::Passed().
823 const GURL& source_url = params->source_url;
824 property_provider_.GetChannelID(
825 Profile::FromBrowserContext(context), source_url,
826 base::Bind(&MessageService::GotChannelID, weak_factory_.GetWeakPtr(),
827 base::Passed(&params)));
828 return;
831 ExtensionRegistry* registry = ExtensionRegistry::Get(context);
832 const Extension* target_extension =
833 registry->enabled_extensions().GetByID(params->target_extension_id);
834 if (!target_extension) {
835 DispatchOnDisconnect(source, params->receiver_port_id,
836 kReceivingEndDoesntExistError);
837 return;
840 // The target might be a lazy background page. In that case, we have to check
841 // if it is loaded and ready, and if not, queue up the task and load the
842 // page.
843 if (!MaybeAddPendingLazyBackgroundPageOpenChannelTask(
844 context, target_extension, &params, pending_messages)) {
845 OpenChannelImpl(params.Pass());
846 DispatchPendingMessages(pending_messages, channel_id);
850 void MessageService::GotChannelID(scoped_ptr<OpenChannelParams> params,
851 const std::string& tls_channel_id) {
852 params->tls_channel_id.assign(tls_channel_id);
853 int channel_id = GET_CHANNEL_ID(params->receiver_port_id);
855 PendingChannelMap::iterator pending_for_tls_channel_id =
856 pending_tls_channel_id_channels_.find(channel_id);
857 if (pending_for_tls_channel_id == pending_tls_channel_id_channels_.end()) {
858 NOTREACHED();
859 return;
861 PendingMessagesQueue pending_messages;
862 pending_messages.swap(pending_for_tls_channel_id->second);
863 pending_tls_channel_id_channels_.erase(pending_for_tls_channel_id);
865 // Re-lookup the source process since it may no longer be valid.
866 content::RenderProcessHost* source =
867 content::RenderProcessHost::FromID(params->source_process_id);
868 if (!source) {
869 return;
872 BrowserContext* context = source->GetBrowserContext();
873 ExtensionRegistry* registry = ExtensionRegistry::Get(context);
874 const Extension* target_extension =
875 registry->enabled_extensions().GetByID(params->target_extension_id);
876 if (!target_extension) {
877 DispatchOnDisconnect(source, params->receiver_port_id,
878 kReceivingEndDoesntExistError);
879 return;
882 if (!MaybeAddPendingLazyBackgroundPageOpenChannelTask(
883 context, target_extension, &params, pending_messages)) {
884 OpenChannelImpl(params.Pass());
885 DispatchPendingMessages(pending_messages, channel_id);
889 void MessageService::PendingLazyBackgroundPageOpenChannel(
890 scoped_ptr<OpenChannelParams> params,
891 int source_process_id,
892 ExtensionHost* host) {
893 if (!host)
894 return; // TODO(mpcomplete): notify source of disconnect?
896 params->receiver.reset(new ExtensionMessagePort(host->render_process_host(),
897 MSG_ROUTING_CONTROL,
898 params->target_extension_id));
899 OpenChannelImpl(params.Pass());
902 void MessageService::DispatchOnDisconnect(content::RenderProcessHost* source,
903 int port_id,
904 const std::string& error_message) {
905 ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, "");
906 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(port_id), error_message);
909 void MessageService::DispatchPendingMessages(const PendingMessagesQueue& queue,
910 int channel_id) {
911 MessageChannelMap::iterator channel_iter = channels_.find(channel_id);
912 if (channel_iter != channels_.end()) {
913 for (const PendingMessage& message : queue) {
914 DispatchMessage(message.first, channel_iter->second, message.second);
919 } // namespace extensions