Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / extensions / api / messaging / message_service.cc
blobacef124640b14bb21d20a0176fe64b0a830a837c
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 "components/guest_view/common/guest_view_constants.h"
26 #include "content/public/browser/notification_service.h"
27 #include "content/public/browser/render_frame_host.h"
28 #include "content/public/browser/render_process_host.h"
29 #include "content/public/browser/render_view_host.h"
30 #include "content/public/browser/render_widget_host.h"
31 #include "content/public/browser/render_widget_host_view.h"
32 #include "content/public/browser/site_instance.h"
33 #include "content/public/browser/web_contents.h"
34 #include "content/public/common/child_process_host.h"
35 #include "extensions/browser/event_router.h"
36 #include "extensions/browser/extension_host.h"
37 #include "extensions/browser/extension_registry.h"
38 #include "extensions/browser/extension_system.h"
39 #include "extensions/browser/extensions_browser_client.h"
40 #include "extensions/browser/guest_view/web_view/web_view_guest.h"
41 #include "extensions/browser/lazy_background_task_queue.h"
42 #include "extensions/browser/pref_names.h"
43 #include "extensions/browser/process_manager.h"
44 #include "extensions/common/extension.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_info;
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_info)
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_info(include_guest_process_info) {
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 LazyBackgroundTaskQueue::Get(context)),
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_info = 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_info = true;
341 auto* rfh = content::RenderFrameHost::FromID(source_process_id,
342 source_routing_id);
343 // Include |source_frame_id| so that we can retrieve the guest's frame
344 // routing id in OpenChannelImpl.
345 if (rfh)
346 source_frame_id = source_routing_id;
350 scoped_ptr<OpenChannelParams> params(new OpenChannelParams(
351 source_process_id, source_tab.Pass(), source_frame_id,
352 -1, // no target_frame_id for a channel to an extension/background page.
353 nullptr, receiver_port_id, source_extension_id, target_extension_id,
354 source_url, channel_name, include_tls_channel_id,
355 include_guest_process_info));
357 pending_incognito_channels_[GET_CHANNEL_ID(params->receiver_port_id)] =
358 PendingMessagesQueue();
359 if (context->IsOffTheRecord() &&
360 !util::IsIncognitoEnabled(target_extension_id, context)) {
361 // Give the user a chance to accept an incognito connection from the web if
362 // they haven't already, with the conditions:
363 // - Only for spanning-mode incognito. We don't want the complication of
364 // spinning up an additional process here which might need to do some
365 // setup that we're not expecting.
366 // - Only for extensions that can't normally be enabled in incognito, since
367 // that surface (e.g. chrome://extensions) should be the only one for
368 // enabling in incognito. In practice this means platform apps only.
369 if (!is_web_connection || IncognitoInfo::IsSplitMode(target_extension) ||
370 target_extension->can_be_incognito_enabled()) {
371 OnOpenChannelAllowed(params.Pass(), false);
372 return;
375 // If the target extension isn't even listening for connect/message events,
376 // there is no need to go any further and the connection should be
377 // rejected without showing a prompt. See http://crbug.com/442497
378 EventRouter* event_router = EventRouter::Get(context);
379 const char* const events[] = {"runtime.onConnectExternal",
380 "runtime.onMessageExternal",
381 "extension.onRequestExternal",
382 nullptr};
383 bool has_event_listener = false;
384 for (const char* const* event = events; *event; event++) {
385 has_event_listener |=
386 event_router->ExtensionHasEventListener(target_extension_id, *event);
388 if (!has_event_listener) {
389 OnOpenChannelAllowed(params.Pass(), false);
390 return;
393 // This check may show a dialog.
394 IncognitoConnectability::Get(context)
395 ->Query(target_extension, source_contents, source_url,
396 base::Bind(&MessageService::OnOpenChannelAllowed,
397 weak_factory_.GetWeakPtr(), base::Passed(&params)));
398 return;
401 OnOpenChannelAllowed(params.Pass(), true);
404 void MessageService::OpenChannelToNativeApp(
405 int source_process_id,
406 int source_routing_id,
407 int receiver_port_id,
408 const std::string& source_extension_id,
409 const std::string& native_app_name) {
410 content::RenderProcessHost* source =
411 content::RenderProcessHost::FromID(source_process_id);
412 if (!source)
413 return;
415 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
416 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
417 ExtensionService* extension_service =
418 ExtensionSystem::Get(profile)->extension_service();
419 bool has_permission = false;
420 if (extension_service) {
421 const Extension* extension =
422 extension_service->GetExtensionById(source_extension_id, false);
423 has_permission = extension &&
424 extension->permissions_data()->HasAPIPermission(
425 APIPermission::kNativeMessaging);
428 if (!has_permission) {
429 DispatchOnDisconnect(source, receiver_port_id, kMissingPermissionError);
430 return;
433 PrefService* pref_service = profile->GetPrefs();
435 // Verify that the host is not blocked by policies.
436 PolicyPermission policy_permission =
437 IsNativeMessagingHostAllowed(pref_service, native_app_name);
438 if (policy_permission == DISALLOW) {
439 DispatchOnDisconnect(source, receiver_port_id, kProhibitedByPoliciesError);
440 return;
443 scoped_ptr<MessageChannel> channel(new MessageChannel());
444 channel->opener.reset(new ExtensionMessagePort(source, MSG_ROUTING_CONTROL,
445 source_extension_id));
447 // Get handle of the native view and pass it to the native messaging host.
448 content::RenderFrameHost* render_frame_host =
449 content::RenderFrameHost::FromID(source_process_id, source_routing_id);
450 gfx::NativeView native_view =
451 render_frame_host ? render_frame_host->GetNativeView() : nullptr;
453 std::string error = kReceivingEndDoesntExistError;
454 scoped_ptr<NativeMessageHost> native_host = NativeMessageHost::Create(
455 native_view,
456 source_extension_id,
457 native_app_name,
458 policy_permission == ALLOW_ALL,
459 &error);
461 // Abandon the channel.
462 if (!native_host.get()) {
463 LOG(ERROR) << "Failed to create native process.";
464 DispatchOnDisconnect(source, receiver_port_id, error);
465 return;
467 channel->receiver.reset(new NativeMessagePort(
468 weak_factory_.GetWeakPtr(), receiver_port_id, native_host.Pass()));
470 // Keep the opener alive until the channel is closed.
471 channel->opener->IncrementLazyKeepaliveCount();
473 AddChannel(channel.release(), receiver_port_id);
474 #else // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
475 const char kNativeMessagingNotSupportedError[] =
476 "Native Messaging is not supported on this platform.";
477 DispatchOnDisconnect(
478 source, receiver_port_id, kNativeMessagingNotSupportedError);
479 #endif // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
482 void MessageService::OpenChannelToTab(int source_process_id,
483 int receiver_port_id,
484 int tab_id,
485 int frame_id,
486 const std::string& extension_id,
487 const std::string& channel_name) {
488 content::RenderProcessHost* source =
489 content::RenderProcessHost::FromID(source_process_id);
490 if (!source)
491 return;
492 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
494 WebContents* contents = NULL;
495 scoped_ptr<MessagePort> receiver;
496 if (!ExtensionTabUtil::GetTabById(tab_id, profile, true, NULL, NULL,
497 &contents, NULL) ||
498 contents->GetController().NeedsReload()) {
499 // The tab isn't loaded yet. Don't attempt to connect.
500 DispatchOnDisconnect(
501 source, receiver_port_id, kReceivingEndDoesntExistError);
502 return;
505 int receiver_routing_id;
506 if (frame_id > 0) {
507 // Positive frame ID is child frame.
508 int receiver_process_id = contents->GetRenderProcessHost()->GetID();
509 if (!content::RenderFrameHost::FromID(receiver_process_id, frame_id)) {
510 // Frame does not exist.
511 DispatchOnDisconnect(
512 source, receiver_port_id, kReceivingEndDoesntExistError);
513 return;
515 receiver_routing_id = frame_id;
516 } else if (frame_id == 0) {
517 // Frame ID 0 is main frame.
518 receiver_routing_id = contents->GetMainFrame()->GetRoutingID();
519 } else {
520 DCHECK_EQ(-1, frame_id);
521 // If the frame ID is not set (i.e. -1), then the channel has to be opened
522 // in every frame.
523 // TODO(robwu): Update logic so that frames that are not hosted in the main
524 // frame's process can also receive the port.
525 receiver_routing_id = MSG_ROUTING_CONTROL;
527 receiver.reset(new ExtensionMessagePort(
528 contents->GetRenderProcessHost(), receiver_routing_id, extension_id));
530 scoped_ptr<OpenChannelParams> params(new OpenChannelParams(
531 source_process_id,
532 scoped_ptr<base::DictionaryValue>(), // Source tab doesn't make sense
533 // for opening to tabs.
534 -1, // If there is no tab, then there is no frame either.
535 frame_id,
536 receiver.release(), receiver_port_id, extension_id, extension_id,
537 GURL(), // Source URL doesn't make sense for opening to tabs.
538 channel_name,
539 false, // Connections to tabs don't get TLS channel IDs.
540 false)); // Connections to tabs aren't webview guests.
541 OpenChannelImpl(params.Pass());
544 void MessageService::OpenChannelImpl(scoped_ptr<OpenChannelParams> params) {
545 content::RenderProcessHost* source =
546 content::RenderProcessHost::FromID(params->source_process_id);
547 if (!source)
548 return; // Closed while in flight.
550 if (!params->receiver || !params->receiver->GetRenderProcessHost()) {
551 DispatchOnDisconnect(source, params->receiver_port_id,
552 kReceivingEndDoesntExistError);
553 return;
556 // Add extra paranoid CHECKs, since we have crash reports of this being NULL.
557 // http://code.google.com/p/chromium/issues/detail?id=19067
558 CHECK(params->receiver->GetRenderProcessHost());
560 MessageChannel* channel(new MessageChannel);
561 channel->opener.reset(new ExtensionMessagePort(source, MSG_ROUTING_CONTROL,
562 params->source_extension_id));
563 channel->receiver.reset(params->receiver.release());
565 CHECK(channel->receiver->GetRenderProcessHost());
567 AddChannel(channel, params->receiver_port_id);
569 CHECK(channel->receiver->GetRenderProcessHost());
571 int guest_process_id = content::ChildProcessHost::kInvalidUniqueID;
572 int guest_render_frame_routing_id = MSG_ROUTING_NONE;
573 if (params->include_guest_process_info) {
574 guest_process_id = params->source_process_id;
575 guest_render_frame_routing_id = params->source_frame_id;
576 auto* guest_rfh = content::RenderFrameHost::FromID(
577 guest_process_id, guest_render_frame_routing_id);
578 // Reset the |source_frame_id| parameter.
579 params->source_frame_id = -1;
581 DCHECK(guest_rfh == nullptr ||
582 WebViewGuest::FromWebContents(
583 WebContents::FromRenderFrameHost(guest_rfh)) != nullptr);
586 // Send the connect event to the receiver. Give it the opener's port ID (the
587 // opener has the opposite port ID).
588 channel->receiver->DispatchOnConnect(params->receiver_port_id,
589 params->channel_name,
590 params->source_tab.Pass(),
591 params->source_frame_id,
592 params->target_frame_id,
593 guest_process_id,
594 guest_render_frame_routing_id,
595 params->source_extension_id,
596 params->target_extension_id,
597 params->source_url,
598 params->tls_channel_id);
600 // Keep both ends of the channel alive until the channel is closed.
601 channel->opener->IncrementLazyKeepaliveCount();
602 channel->receiver->IncrementLazyKeepaliveCount();
605 void MessageService::AddChannel(MessageChannel* channel, int receiver_port_id) {
606 int channel_id = GET_CHANNEL_ID(receiver_port_id);
607 CHECK(channels_.find(channel_id) == channels_.end());
608 channels_[channel_id] = channel;
609 pending_lazy_background_page_channels_.erase(channel_id);
612 void MessageService::CloseChannel(int port_id,
613 const std::string& error_message) {
614 // Note: The channel might be gone already, if the other side closed first.
615 int channel_id = GET_CHANNEL_ID(port_id);
616 MessageChannelMap::iterator it = channels_.find(channel_id);
617 if (it == channels_.end()) {
618 PendingLazyBackgroundPageChannelMap::iterator pending =
619 pending_lazy_background_page_channels_.find(channel_id);
620 if (pending != pending_lazy_background_page_channels_.end()) {
621 lazy_background_task_queue_->AddPendingTask(
622 pending->second.first, pending->second.second,
623 base::Bind(&MessageService::PendingLazyBackgroundPageCloseChannel,
624 weak_factory_.GetWeakPtr(), port_id, error_message));
626 return;
628 CloseChannelImpl(it, port_id, error_message, true);
631 void MessageService::CloseChannelImpl(
632 MessageChannelMap::iterator channel_iter,
633 int closing_port_id,
634 const std::string& error_message,
635 bool notify_other_port) {
636 MessageChannel* channel = channel_iter->second;
638 // Notify the other side.
639 if (notify_other_port) {
640 MessagePort* port = IS_OPENER_PORT_ID(closing_port_id) ?
641 channel->receiver.get() : channel->opener.get();
642 port->DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(closing_port_id),
643 error_message);
646 // Balance the IncrementLazyKeepaliveCount() in OpenChannelImpl.
647 channel->opener->DecrementLazyKeepaliveCount();
648 channel->receiver->DecrementLazyKeepaliveCount();
650 delete channel_iter->second;
651 channels_.erase(channel_iter);
654 void MessageService::PostMessage(int source_port_id, const Message& message) {
655 int channel_id = GET_CHANNEL_ID(source_port_id);
656 MessageChannelMap::iterator iter = channels_.find(channel_id);
657 if (iter == channels_.end()) {
658 // If this channel is pending, queue up the PostMessage to run once
659 // the channel opens.
660 EnqueuePendingMessage(source_port_id, channel_id, message);
661 return;
664 DispatchMessage(source_port_id, iter->second, message);
667 void MessageService::Observe(int type,
668 const content::NotificationSource& source,
669 const content::NotificationDetails& details) {
670 switch (type) {
671 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
672 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
673 content::RenderProcessHost* renderer =
674 content::Source<content::RenderProcessHost>(source).ptr();
675 OnProcessClosed(renderer);
676 break;
678 default:
679 NOTREACHED();
680 return;
684 void MessageService::OnProcessClosed(content::RenderProcessHost* process) {
685 // Close any channels that share this renderer. We notify the opposite
686 // port that his pair has closed.
687 for (MessageChannelMap::iterator it = channels_.begin();
688 it != channels_.end(); ) {
689 MessageChannelMap::iterator current = it++;
691 content::RenderProcessHost* opener_process =
692 current->second->opener->GetRenderProcessHost();
693 content::RenderProcessHost* receiver_process =
694 current->second->receiver->GetRenderProcessHost();
696 // Only notify the other side if it has a different porocess host.
697 bool notify_other_port = opener_process && receiver_process &&
698 opener_process != receiver_process;
700 if (opener_process == process) {
701 CloseChannelImpl(current, GET_CHANNEL_OPENER_ID(current->first),
702 std::string(), notify_other_port);
703 } else if (receiver_process == process) {
704 CloseChannelImpl(current, GET_CHANNEL_RECEIVERS_ID(current->first),
705 std::string(), notify_other_port);
710 void MessageService::EnqueuePendingMessage(int source_port_id,
711 int channel_id,
712 const Message& message) {
713 PendingChannelMap::iterator pending_for_incognito =
714 pending_incognito_channels_.find(channel_id);
715 if (pending_for_incognito != pending_incognito_channels_.end()) {
716 pending_for_incognito->second.push_back(
717 PendingMessage(source_port_id, message));
718 // A channel should only be holding pending messages because it is in one
719 // of these states.
720 DCHECK(!ContainsKey(pending_tls_channel_id_channels_, channel_id));
721 DCHECK(!ContainsKey(pending_lazy_background_page_channels_, channel_id));
722 return;
724 PendingChannelMap::iterator pending_for_tls_channel_id =
725 pending_tls_channel_id_channels_.find(channel_id);
726 if (pending_for_tls_channel_id != pending_tls_channel_id_channels_.end()) {
727 pending_for_tls_channel_id->second.push_back(
728 PendingMessage(source_port_id, message));
729 // A channel should only be holding pending messages because it is in one
730 // of these states.
731 DCHECK(!ContainsKey(pending_lazy_background_page_channels_, channel_id));
732 return;
734 EnqueuePendingMessageForLazyBackgroundLoad(source_port_id,
735 channel_id,
736 message);
739 void MessageService::EnqueuePendingMessageForLazyBackgroundLoad(
740 int source_port_id,
741 int channel_id,
742 const Message& message) {
743 PendingLazyBackgroundPageChannelMap::iterator pending =
744 pending_lazy_background_page_channels_.find(channel_id);
745 if (pending != pending_lazy_background_page_channels_.end()) {
746 lazy_background_task_queue_->AddPendingTask(
747 pending->second.first, pending->second.second,
748 base::Bind(&MessageService::PendingLazyBackgroundPagePostMessage,
749 weak_factory_.GetWeakPtr(), source_port_id, message));
753 void MessageService::DispatchMessage(int source_port_id,
754 MessageChannel* channel,
755 const Message& message) {
756 // Figure out which port the ID corresponds to.
757 int dest_port_id = GET_OPPOSITE_PORT_ID(source_port_id);
758 MessagePort* port = IS_OPENER_PORT_ID(dest_port_id) ?
759 channel->opener.get() : channel->receiver.get();
761 port->DispatchOnMessage(message, dest_port_id);
764 bool MessageService::MaybeAddPendingLazyBackgroundPageOpenChannelTask(
765 BrowserContext* context,
766 const Extension* extension,
767 scoped_ptr<OpenChannelParams>* params,
768 const PendingMessagesQueue& pending_messages) {
769 if (!BackgroundInfo::HasLazyBackgroundPage(extension))
770 return false;
772 // If the extension uses spanning incognito mode, make sure we're always
773 // using the original profile since that is what the extension process
774 // will use.
775 if (!IncognitoInfo::IsSplitMode(extension))
776 context = ExtensionsBrowserClient::Get()->GetOriginalContext(context);
778 if (!lazy_background_task_queue_->ShouldEnqueueTask(context, extension))
779 return false;
781 int channel_id = GET_CHANNEL_ID((*params)->receiver_port_id);
782 pending_lazy_background_page_channels_[channel_id] =
783 PendingLazyBackgroundPageChannel(context, extension->id());
784 int source_id = (*params)->source_process_id;
785 lazy_background_task_queue_->AddPendingTask(
786 context, extension->id(),
787 base::Bind(&MessageService::PendingLazyBackgroundPageOpenChannel,
788 weak_factory_.GetWeakPtr(), base::Passed(params), source_id));
790 for (const PendingMessage& message : pending_messages) {
791 EnqueuePendingMessageForLazyBackgroundLoad(message.first, channel_id,
792 message.second);
794 return true;
797 void MessageService::OnOpenChannelAllowed(scoped_ptr<OpenChannelParams> params,
798 bool allowed) {
799 int channel_id = GET_CHANNEL_ID(params->receiver_port_id);
801 PendingChannelMap::iterator pending_for_incognito =
802 pending_incognito_channels_.find(channel_id);
803 if (pending_for_incognito == pending_incognito_channels_.end()) {
804 NOTREACHED();
805 return;
807 PendingMessagesQueue pending_messages;
808 pending_messages.swap(pending_for_incognito->second);
809 pending_incognito_channels_.erase(pending_for_incognito);
811 // Re-lookup the source process since it may no longer be valid.
812 content::RenderProcessHost* source =
813 content::RenderProcessHost::FromID(params->source_process_id);
814 if (!source) {
815 return;
818 if (!allowed) {
819 DispatchOnDisconnect(source, params->receiver_port_id,
820 kReceivingEndDoesntExistError);
821 return;
824 BrowserContext* context = source->GetBrowserContext();
826 // Note: we use the source's profile here. If the source is an incognito
827 // process, we will use the incognito EPM to find the right extension process,
828 // which depends on whether the extension uses spanning or split mode.
829 params->receiver.reset(new ExtensionMessagePort(
830 GetExtensionProcess(context, params->target_extension_id),
831 MSG_ROUTING_CONTROL, params->target_extension_id));
833 // If the target requests the TLS channel id, begin the lookup for it.
834 // The target might also be a lazy background page, checked next, but the
835 // loading of lazy background pages continues asynchronously, so enqueue
836 // messages awaiting TLS channel ID first.
837 if (params->include_tls_channel_id) {
838 // Transfer pending messages to the next pending channel list.
839 pending_tls_channel_id_channels_[channel_id].swap(pending_messages);
840 // Capture this reference before params is invalidated by base::Passed().
841 const GURL& source_url = params->source_url;
842 property_provider_.GetChannelID(
843 Profile::FromBrowserContext(context), source_url,
844 base::Bind(&MessageService::GotChannelID, weak_factory_.GetWeakPtr(),
845 base::Passed(&params)));
846 return;
849 ExtensionRegistry* registry = ExtensionRegistry::Get(context);
850 const Extension* target_extension =
851 registry->enabled_extensions().GetByID(params->target_extension_id);
852 if (!target_extension) {
853 DispatchOnDisconnect(source, params->receiver_port_id,
854 kReceivingEndDoesntExistError);
855 return;
858 // The target might be a lazy background page. In that case, we have to check
859 // if it is loaded and ready, and if not, queue up the task and load the
860 // page.
861 if (!MaybeAddPendingLazyBackgroundPageOpenChannelTask(
862 context, target_extension, &params, pending_messages)) {
863 OpenChannelImpl(params.Pass());
864 DispatchPendingMessages(pending_messages, channel_id);
868 void MessageService::GotChannelID(scoped_ptr<OpenChannelParams> params,
869 const std::string& tls_channel_id) {
870 params->tls_channel_id.assign(tls_channel_id);
871 int channel_id = GET_CHANNEL_ID(params->receiver_port_id);
873 PendingChannelMap::iterator pending_for_tls_channel_id =
874 pending_tls_channel_id_channels_.find(channel_id);
875 if (pending_for_tls_channel_id == pending_tls_channel_id_channels_.end()) {
876 NOTREACHED();
877 return;
879 PendingMessagesQueue pending_messages;
880 pending_messages.swap(pending_for_tls_channel_id->second);
881 pending_tls_channel_id_channels_.erase(pending_for_tls_channel_id);
883 // Re-lookup the source process since it may no longer be valid.
884 content::RenderProcessHost* source =
885 content::RenderProcessHost::FromID(params->source_process_id);
886 if (!source) {
887 return;
890 BrowserContext* context = source->GetBrowserContext();
891 ExtensionRegistry* registry = ExtensionRegistry::Get(context);
892 const Extension* target_extension =
893 registry->enabled_extensions().GetByID(params->target_extension_id);
894 if (!target_extension) {
895 DispatchOnDisconnect(source, params->receiver_port_id,
896 kReceivingEndDoesntExistError);
897 return;
900 if (!MaybeAddPendingLazyBackgroundPageOpenChannelTask(
901 context, target_extension, &params, pending_messages)) {
902 OpenChannelImpl(params.Pass());
903 DispatchPendingMessages(pending_messages, channel_id);
907 void MessageService::PendingLazyBackgroundPageOpenChannel(
908 scoped_ptr<OpenChannelParams> params,
909 int source_process_id,
910 ExtensionHost* host) {
911 if (!host)
912 return; // TODO(mpcomplete): notify source of disconnect?
914 params->receiver.reset(new ExtensionMessagePort(host->render_process_host(),
915 MSG_ROUTING_CONTROL,
916 params->target_extension_id));
917 OpenChannelImpl(params.Pass());
920 void MessageService::DispatchOnDisconnect(content::RenderProcessHost* source,
921 int port_id,
922 const std::string& error_message) {
923 ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, "");
924 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(port_id), error_message);
927 void MessageService::DispatchPendingMessages(const PendingMessagesQueue& queue,
928 int channel_id) {
929 MessageChannelMap::iterator channel_iter = channels_.find(channel_id);
930 if (channel_iter != channels_.end()) {
931 for (const PendingMessage& message : queue) {
932 DispatchMessage(message.first, channel_iter->second, message.second);
937 } // namespace extensions