Add new certificateProvider extension API.
[chromium-blink-merge.git] / chrome / browser / extensions / api / messaging / message_service.cc
blobe08249fc0af602cf140ce5ec18bd0696d7b85356
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/browser_thread.h"
27 #include "content/public/browser/notification_service.h"
28 #include "content/public/browser/render_frame_host.h"
29 #include "content/public/browser/render_process_host.h"
30 #include "content/public/browser/render_view_host.h"
31 #include "content/public/browser/render_widget_host.h"
32 #include "content/public/browser/render_widget_host_view.h"
33 #include "content/public/browser/site_instance.h"
34 #include "content/public/browser/web_contents.h"
35 #include "content/public/common/child_process_host.h"
36 #include "extensions/browser/event_router.h"
37 #include "extensions/browser/extension_host.h"
38 #include "extensions/browser/extension_registry.h"
39 #include "extensions/browser/extension_system.h"
40 #include "extensions/browser/extensions_browser_client.h"
41 #include "extensions/browser/guest_view/web_view/web_view_guest.h"
42 #include "extensions/browser/lazy_background_task_queue.h"
43 #include "extensions/browser/pref_names.h"
44 #include "extensions/browser/process_manager.h"
45 #include "extensions/common/extension.h"
46 #include "extensions/common/manifest_constants.h"
47 #include "extensions/common/manifest_handlers/background_info.h"
48 #include "extensions/common/manifest_handlers/externally_connectable.h"
49 #include "extensions/common/manifest_handlers/incognito_info.h"
50 #include "extensions/common/permissions/permissions_data.h"
51 #include "net/base/completion_callback.h"
52 #include "url/gurl.h"
54 using content::BrowserContext;
55 using content::BrowserThread;
56 using content::SiteInstance;
57 using content::WebContents;
59 // Since we have 2 ports for every channel, we just index channels by half the
60 // port ID.
61 #define GET_CHANNEL_ID(port_id) ((port_id) / 2)
62 #define GET_CHANNEL_OPENER_ID(channel_id) ((channel_id) * 2)
63 #define GET_CHANNEL_RECEIVERS_ID(channel_id) ((channel_id) * 2 + 1)
65 // Port1 is always even, port2 is always odd.
66 #define IS_OPENER_PORT_ID(port_id) (((port_id) & 1) == 0)
68 // Change even to odd and vice versa, to get the other side of a given channel.
69 #define GET_OPPOSITE_PORT_ID(source_port_id) ((source_port_id) ^ 1)
71 namespace extensions {
73 MessageService::PolicyPermission MessageService::IsNativeMessagingHostAllowed(
74 const PrefService* pref_service,
75 const std::string& native_host_name) {
76 DCHECK_CURRENTLY_ON(BrowserThread::UI);
78 PolicyPermission allow_result = ALLOW_ALL;
79 if (pref_service->IsManagedPreference(
80 pref_names::kNativeMessagingUserLevelHosts)) {
81 if (!pref_service->GetBoolean(pref_names::kNativeMessagingUserLevelHosts))
82 allow_result = ALLOW_SYSTEM_ONLY;
85 // All native messaging hosts are allowed if there is no blacklist.
86 if (!pref_service->IsManagedPreference(pref_names::kNativeMessagingBlacklist))
87 return allow_result;
88 const base::ListValue* blacklist =
89 pref_service->GetList(pref_names::kNativeMessagingBlacklist);
90 if (!blacklist)
91 return allow_result;
93 // Check if the name or the wildcard is in the blacklist.
94 base::StringValue name_value(native_host_name);
95 base::StringValue wildcard_value("*");
96 if (blacklist->Find(name_value) == blacklist->end() &&
97 blacklist->Find(wildcard_value) == blacklist->end()) {
98 return allow_result;
101 // The native messaging host is blacklisted. Check the whitelist.
102 if (pref_service->IsManagedPreference(
103 pref_names::kNativeMessagingWhitelist)) {
104 const base::ListValue* whitelist =
105 pref_service->GetList(pref_names::kNativeMessagingWhitelist);
106 if (whitelist && whitelist->Find(name_value) != whitelist->end())
107 return allow_result;
110 return DISALLOW;
113 const char kReceivingEndDoesntExistError[] =
114 "Could not establish connection. Receiving end does not exist.";
115 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
116 const char kMissingPermissionError[] =
117 "Access to native messaging requires nativeMessaging permission.";
118 const char kProhibitedByPoliciesError[] =
119 "Access to the native messaging host was disabled by the system "
120 "administrator.";
121 #endif
123 struct MessageService::MessageChannel {
124 scoped_ptr<MessagePort> opener;
125 scoped_ptr<MessagePort> receiver;
128 struct MessageService::OpenChannelParams {
129 int source_process_id;
130 scoped_ptr<base::DictionaryValue> source_tab;
131 int source_frame_id;
132 int target_tab_id;
133 int target_frame_id;
134 scoped_ptr<MessagePort> receiver;
135 int receiver_port_id;
136 std::string source_extension_id;
137 std::string target_extension_id;
138 GURL source_url;
139 std::string channel_name;
140 bool include_tls_channel_id;
141 std::string tls_channel_id;
142 bool include_guest_process_info;
144 // Takes ownership of receiver.
145 OpenChannelParams(int source_process_id,
146 scoped_ptr<base::DictionaryValue> source_tab,
147 int source_frame_id,
148 int target_tab_id,
149 int target_frame_id,
150 MessagePort* receiver,
151 int receiver_port_id,
152 const std::string& source_extension_id,
153 const std::string& target_extension_id,
154 const GURL& source_url,
155 const std::string& channel_name,
156 bool include_tls_channel_id,
157 bool include_guest_process_info)
158 : source_process_id(source_process_id),
159 source_frame_id(source_frame_id),
160 target_tab_id(target_tab_id),
161 target_frame_id(target_frame_id),
162 receiver(receiver),
163 receiver_port_id(receiver_port_id),
164 source_extension_id(source_extension_id),
165 target_extension_id(target_extension_id),
166 source_url(source_url),
167 channel_name(channel_name),
168 include_tls_channel_id(include_tls_channel_id),
169 include_guest_process_info(include_guest_process_info) {
170 if (source_tab)
171 this->source_tab = source_tab.Pass();
174 private:
175 DISALLOW_COPY_AND_ASSIGN(OpenChannelParams);
178 namespace {
180 static base::StaticAtomicSequenceNumber g_next_channel_id;
182 static content::RenderProcessHost* GetExtensionProcess(
183 BrowserContext* context,
184 const std::string& extension_id) {
185 scoped_refptr<SiteInstance> site_instance =
186 ProcessManager::Get(context)->GetSiteInstanceForURL(
187 Extension::GetBaseURLFromExtensionId(extension_id));
188 return site_instance->HasProcess() ? site_instance->GetProcess() : NULL;
191 } // namespace
193 content::RenderProcessHost*
194 MessageService::MessagePort::GetRenderProcessHost() {
195 return NULL;
198 // static
199 void MessageService::AllocatePortIdPair(int* port1, int* port2) {
200 DCHECK_CURRENTLY_ON(BrowserThread::IO);
202 unsigned channel_id =
203 static_cast<unsigned>(g_next_channel_id.GetNext()) % (kint32max/2);
204 unsigned port1_id = channel_id * 2;
205 unsigned port2_id = channel_id * 2 + 1;
207 // Sanity checks to make sure our channel<->port converters are correct.
208 DCHECK(IS_OPENER_PORT_ID(port1_id));
209 DCHECK_EQ(GET_OPPOSITE_PORT_ID(port1_id), port2_id);
210 DCHECK_EQ(GET_OPPOSITE_PORT_ID(port2_id), port1_id);
211 DCHECK_EQ(GET_CHANNEL_ID(port1_id), GET_CHANNEL_ID(port2_id));
212 DCHECK_EQ(GET_CHANNEL_ID(port1_id), channel_id);
213 DCHECK_EQ(GET_CHANNEL_OPENER_ID(channel_id), port1_id);
214 DCHECK_EQ(GET_CHANNEL_RECEIVERS_ID(channel_id), port2_id);
216 *port1 = port1_id;
217 *port2 = port2_id;
220 MessageService::MessageService(BrowserContext* context)
221 : lazy_background_task_queue_(
222 LazyBackgroundTaskQueue::Get(context)),
223 weak_factory_(this) {
224 DCHECK_CURRENTLY_ON(BrowserThread::UI);
226 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
227 content::NotificationService::AllBrowserContextsAndSources());
228 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
229 content::NotificationService::AllBrowserContextsAndSources());
232 MessageService::~MessageService() {
233 DCHECK_CURRENTLY_ON(BrowserThread::UI);
235 STLDeleteContainerPairSecondPointers(channels_.begin(), channels_.end());
236 channels_.clear();
239 static base::LazyInstance<BrowserContextKeyedAPIFactory<MessageService> >
240 g_factory = LAZY_INSTANCE_INITIALIZER;
242 // static
243 BrowserContextKeyedAPIFactory<MessageService>*
244 MessageService::GetFactoryInstance() {
245 return g_factory.Pointer();
248 // static
249 MessageService* MessageService::Get(BrowserContext* context) {
250 return BrowserContextKeyedAPIFactory<MessageService>::Get(context);
253 void MessageService::OpenChannelToExtension(
254 int source_process_id, int source_routing_id, int receiver_port_id,
255 const std::string& source_extension_id,
256 const std::string& target_extension_id,
257 const GURL& source_url,
258 const std::string& channel_name,
259 bool include_tls_channel_id) {
260 DCHECK_CURRENTLY_ON(BrowserThread::UI);
262 content::RenderProcessHost* source =
263 content::RenderProcessHost::FromID(source_process_id);
264 if (!source)
265 return;
266 BrowserContext* context = source->GetBrowserContext();
268 ExtensionRegistry* registry = ExtensionRegistry::Get(context);
269 const Extension* target_extension =
270 registry->enabled_extensions().GetByID(target_extension_id);
271 if (!target_extension) {
272 DispatchOnDisconnect(
273 source, receiver_port_id, kReceivingEndDoesntExistError);
274 return;
277 bool is_web_connection = false;
279 if (source_extension_id != target_extension_id) {
280 // It's an external connection. Check the externally_connectable manifest
281 // key if it's present. If it's not, we allow connection from any extension
282 // but not webpages.
283 ExternallyConnectableInfo* externally_connectable =
284 static_cast<ExternallyConnectableInfo*>(
285 target_extension->GetManifestData(
286 manifest_keys::kExternallyConnectable));
287 bool is_externally_connectable = false;
289 if (externally_connectable) {
290 if (source_extension_id.empty()) {
291 // No source extension ID so the source was a web page. Check that the
292 // URL matches.
293 is_web_connection = true;
294 is_externally_connectable =
295 externally_connectable->matches.MatchesURL(source_url);
296 // Only include the TLS channel ID for externally connected web pages.
297 include_tls_channel_id &=
298 is_externally_connectable &&
299 externally_connectable->accepts_tls_channel_id;
300 } else {
301 // Source extension ID so the source was an extension. Check that the
302 // extension matches.
303 is_externally_connectable =
304 externally_connectable->IdCanConnect(source_extension_id);
306 } else {
307 // Default behaviour. Any extension, no webpages.
308 is_externally_connectable = !source_extension_id.empty();
311 if (!is_externally_connectable) {
312 // Important: use kReceivingEndDoesntExistError here so that we don't
313 // leak information about this extension to callers. This way it's
314 // indistinguishable from the extension just not existing.
315 DispatchOnDisconnect(
316 source, receiver_port_id, kReceivingEndDoesntExistError);
317 return;
321 WebContents* source_contents = tab_util::GetWebContentsByFrameID(
322 source_process_id, source_routing_id);
324 bool include_guest_process_info = false;
326 // Include info about the opener's tab (if it was a tab).
327 scoped_ptr<base::DictionaryValue> source_tab;
328 int source_frame_id = -1;
329 if (source_contents && ExtensionTabUtil::GetTabId(source_contents) >= 0) {
330 // Only the tab id is useful to platform apps for internal use. The
331 // unnecessary bits will be stripped out in
332 // MessagingBindings::DispatchOnConnect().
333 source_tab.reset(ExtensionTabUtil::CreateTabValue(source_contents));
335 content::RenderFrameHost* rfh =
336 content::RenderFrameHost::FromID(source_process_id, source_routing_id);
337 // Main frame's frameId is 0.
338 if (rfh)
339 source_frame_id = !rfh->GetParent() ? 0 : source_routing_id;
340 } else {
341 // Check to see if it was a WebView making the request.
342 // Sending messages from WebViews to extensions breaks webview isolation,
343 // so only allow component extensions to receive messages from WebViews.
344 bool is_web_view = !!WebViewGuest::FromWebContents(source_contents);
345 if (is_web_view && extensions::Manifest::IsComponentLocation(
346 target_extension->location())) {
347 include_guest_process_info = true;
348 auto* rfh = content::RenderFrameHost::FromID(source_process_id,
349 source_routing_id);
350 // Include |source_frame_id| so that we can retrieve the guest's frame
351 // routing id in OpenChannelImpl.
352 if (rfh)
353 source_frame_id = source_routing_id;
357 scoped_ptr<OpenChannelParams> params(new OpenChannelParams(
358 source_process_id, source_tab.Pass(), source_frame_id, -1,
359 -1, // no target_tab_id/target_frame_id for connections to extensions
360 nullptr, receiver_port_id, source_extension_id, target_extension_id,
361 source_url, channel_name, include_tls_channel_id,
362 include_guest_process_info));
364 pending_incognito_channels_[GET_CHANNEL_ID(params->receiver_port_id)] =
365 PendingMessagesQueue();
366 if (context->IsOffTheRecord() &&
367 !util::IsIncognitoEnabled(target_extension_id, context)) {
368 // Give the user a chance to accept an incognito connection from the web if
369 // they haven't already, with the conditions:
370 // - Only for spanning-mode incognito. We don't want the complication of
371 // spinning up an additional process here which might need to do some
372 // setup that we're not expecting.
373 // - Only for extensions that can't normally be enabled in incognito, since
374 // that surface (e.g. chrome://extensions) should be the only one for
375 // enabling in incognito. In practice this means platform apps only.
376 if (!is_web_connection || IncognitoInfo::IsSplitMode(target_extension) ||
377 target_extension->can_be_incognito_enabled()) {
378 OnOpenChannelAllowed(params.Pass(), false);
379 return;
382 // If the target extension isn't even listening for connect/message events,
383 // there is no need to go any further and the connection should be
384 // rejected without showing a prompt. See http://crbug.com/442497
385 EventRouter* event_router = EventRouter::Get(context);
386 const char* const events[] = {"runtime.onConnectExternal",
387 "runtime.onMessageExternal",
388 "extension.onRequestExternal",
389 nullptr};
390 bool has_event_listener = false;
391 for (const char* const* event = events; *event; event++) {
392 has_event_listener |=
393 event_router->ExtensionHasEventListener(target_extension_id, *event);
395 if (!has_event_listener) {
396 OnOpenChannelAllowed(params.Pass(), false);
397 return;
400 // This check may show a dialog.
401 IncognitoConnectability::Get(context)
402 ->Query(target_extension, source_contents, source_url,
403 base::Bind(&MessageService::OnOpenChannelAllowed,
404 weak_factory_.GetWeakPtr(), base::Passed(&params)));
405 return;
408 OnOpenChannelAllowed(params.Pass(), true);
411 void MessageService::OpenChannelToNativeApp(
412 int source_process_id,
413 int source_routing_id,
414 int receiver_port_id,
415 const std::string& source_extension_id,
416 const std::string& native_app_name) {
417 DCHECK_CURRENTLY_ON(BrowserThread::UI);
419 content::RenderProcessHost* source =
420 content::RenderProcessHost::FromID(source_process_id);
421 if (!source)
422 return;
424 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
425 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
426 ExtensionService* extension_service =
427 ExtensionSystem::Get(profile)->extension_service();
428 bool has_permission = false;
429 if (extension_service) {
430 const Extension* extension =
431 extension_service->GetExtensionById(source_extension_id, false);
432 has_permission = extension &&
433 extension->permissions_data()->HasAPIPermission(
434 APIPermission::kNativeMessaging);
437 if (!has_permission) {
438 DispatchOnDisconnect(source, receiver_port_id, kMissingPermissionError);
439 return;
442 PrefService* pref_service = profile->GetPrefs();
444 // Verify that the host is not blocked by policies.
445 PolicyPermission policy_permission =
446 IsNativeMessagingHostAllowed(pref_service, native_app_name);
447 if (policy_permission == DISALLOW) {
448 DispatchOnDisconnect(source, receiver_port_id, kProhibitedByPoliciesError);
449 return;
452 scoped_ptr<MessageChannel> channel(new MessageChannel());
453 channel->opener.reset(new ExtensionMessagePort(source, MSG_ROUTING_CONTROL,
454 source_extension_id));
456 // Get handle of the native view and pass it to the native messaging host.
457 content::RenderFrameHost* render_frame_host =
458 content::RenderFrameHost::FromID(source_process_id, source_routing_id);
459 gfx::NativeView native_view =
460 render_frame_host ? render_frame_host->GetNativeView() : nullptr;
462 std::string error = kReceivingEndDoesntExistError;
463 scoped_ptr<NativeMessageHost> native_host = NativeMessageHost::Create(
464 native_view,
465 source_extension_id,
466 native_app_name,
467 policy_permission == ALLOW_ALL,
468 &error);
470 // Abandon the channel.
471 if (!native_host.get()) {
472 LOG(ERROR) << "Failed to create native process.";
473 DispatchOnDisconnect(source, receiver_port_id, error);
474 return;
476 channel->receiver.reset(new NativeMessagePort(
477 weak_factory_.GetWeakPtr(), receiver_port_id, native_host.Pass()));
479 // Keep the opener alive until the channel is closed.
480 channel->opener->IncrementLazyKeepaliveCount();
482 AddChannel(channel.release(), receiver_port_id);
483 #else // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
484 const char kNativeMessagingNotSupportedError[] =
485 "Native Messaging is not supported on this platform.";
486 DispatchOnDisconnect(
487 source, receiver_port_id, kNativeMessagingNotSupportedError);
488 #endif // !(defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX))
491 void MessageService::OpenChannelToTab(int source_process_id,
492 int receiver_port_id,
493 int tab_id,
494 int frame_id,
495 const std::string& extension_id,
496 const std::string& channel_name) {
497 DCHECK_CURRENTLY_ON(BrowserThread::UI);
499 content::RenderProcessHost* source =
500 content::RenderProcessHost::FromID(source_process_id);
501 if (!source)
502 return;
503 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
505 WebContents* contents = NULL;
506 scoped_ptr<MessagePort> receiver;
507 if (!ExtensionTabUtil::GetTabById(tab_id, profile, true, NULL, NULL,
508 &contents, NULL) ||
509 contents->GetController().NeedsReload()) {
510 // The tab isn't loaded yet. Don't attempt to connect.
511 DispatchOnDisconnect(
512 source, receiver_port_id, kReceivingEndDoesntExistError);
513 return;
516 int receiver_routing_id;
517 if (frame_id > 0) {
518 // Positive frame ID is child frame.
519 int receiver_process_id = contents->GetRenderProcessHost()->GetID();
520 if (!content::RenderFrameHost::FromID(receiver_process_id, frame_id)) {
521 // Frame does not exist.
522 DispatchOnDisconnect(
523 source, receiver_port_id, kReceivingEndDoesntExistError);
524 return;
526 receiver_routing_id = frame_id;
527 } else if (frame_id == 0) {
528 // Frame ID 0 is main frame.
529 receiver_routing_id = contents->GetMainFrame()->GetRoutingID();
530 } else {
531 DCHECK_EQ(-1, frame_id);
532 // If the frame ID is not set (i.e. -1), then the channel has to be opened
533 // in every frame.
534 // TODO(robwu): Update logic so that frames that are not hosted in the main
535 // frame's process can also receive the port.
536 receiver_routing_id = MSG_ROUTING_CONTROL;
538 receiver.reset(new ExtensionMessagePort(contents->GetRenderProcessHost(),
539 receiver_routing_id, extension_id));
541 const Extension* extension = nullptr;
542 if (!extension_id.empty()) {
543 // Source extension == target extension so the extension must exist, or
544 // where did the IPC come from?
545 extension = ExtensionRegistry::Get(profile)->enabled_extensions().GetByID(
546 extension_id);
547 DCHECK(extension);
550 scoped_ptr<OpenChannelParams> params(new OpenChannelParams(
551 source_process_id,
552 scoped_ptr<base::DictionaryValue>(), // Source tab doesn't make sense
553 // for opening to tabs.
554 -1, // If there is no tab, then there is no frame either.
555 tab_id, frame_id, receiver.release(), receiver_port_id, extension_id,
556 extension_id,
557 GURL(), // Source URL doesn't make sense for opening to tabs.
558 channel_name,
559 false, // Connections to tabs don't get TLS channel IDs.
560 false)); // Connections to tabs aren't webview guests.
561 OpenChannelImpl(contents->GetBrowserContext(), params.Pass(), extension,
562 false /* did_enqueue */);
565 void MessageService::OpenChannelImpl(BrowserContext* browser_context,
566 scoped_ptr<OpenChannelParams> params,
567 const Extension* target_extension,
568 bool did_enqueue) {
569 DCHECK_CURRENTLY_ON(BrowserThread::UI);
570 DCHECK_EQ(target_extension != nullptr, !params->target_extension_id.empty());
572 content::RenderProcessHost* source =
573 content::RenderProcessHost::FromID(params->source_process_id);
574 if (!source)
575 return; // Closed while in flight.
577 if (!params->receiver || !params->receiver->GetRenderProcessHost()) {
578 DispatchOnDisconnect(source, params->receiver_port_id,
579 kReceivingEndDoesntExistError);
580 return;
583 MessageChannel* channel(new MessageChannel);
584 channel->opener.reset(new ExtensionMessagePort(source, MSG_ROUTING_CONTROL,
585 params->source_extension_id));
586 channel->receiver.reset(params->receiver.release());
587 AddChannel(channel, params->receiver_port_id);
589 int guest_process_id = content::ChildProcessHost::kInvalidUniqueID;
590 int guest_render_frame_routing_id = MSG_ROUTING_NONE;
591 if (params->include_guest_process_info) {
592 guest_process_id = params->source_process_id;
593 guest_render_frame_routing_id = params->source_frame_id;
594 auto* guest_rfh = content::RenderFrameHost::FromID(
595 guest_process_id, guest_render_frame_routing_id);
596 // Reset the |source_frame_id| parameter.
597 params->source_frame_id = -1;
599 DCHECK(guest_rfh == nullptr ||
600 WebViewGuest::FromWebContents(
601 WebContents::FromRenderFrameHost(guest_rfh)) != nullptr);
604 // Send the connect event to the receiver. Give it the opener's port ID (the
605 // opener has the opposite port ID).
606 channel->receiver->DispatchOnConnect(
607 params->receiver_port_id, params->channel_name, params->source_tab.Pass(),
608 params->source_frame_id, params->target_tab_id, params->target_frame_id,
609 guest_process_id, guest_render_frame_routing_id,
610 params->source_extension_id, params->target_extension_id,
611 params->source_url, params->tls_channel_id);
613 // Report the event to the event router, if the target is an extension.
615 // First, determine what event this will be (runtime.onConnect vs
616 // runtime.onMessage etc), and what the event target is (view vs background
617 // page etc).
619 // Yes - even though this is opening a channel, they may actually be
620 // runtime.onRequest/onMessage events because those single-use events are
621 // built using the connect framework (see messaging.js).
623 // Likewise, if you're wondering about native messaging events, these are
624 // only initiated *by* the extension, so aren't really events, just the
625 // endpoint of a communication channel.
626 if (target_extension) {
627 events::HistogramValue histogram_value = events::UNKNOWN;
628 bool is_external =
629 params->source_extension_id != params->target_extension_id;
630 if (params->channel_name == "chrome.runtime.onRequest") {
631 histogram_value = is_external ? events::RUNTIME_ON_REQUEST_EXTERNAL
632 : events::RUNTIME_ON_REQUEST;
633 } else if (params->channel_name == "chrome.runtime.onMessage") {
634 histogram_value = is_external ? events::RUNTIME_ON_MESSAGE_EXTERNAL
635 : events::RUNTIME_ON_MESSAGE;
636 } else {
637 histogram_value = is_external ? events::RUNTIME_ON_CONNECT_EXTERNAL
638 : events::RUNTIME_ON_CONNECT;
640 EventRouter::Get(browser_context)
641 ->ReportEvent(histogram_value, target_extension, did_enqueue);
644 // Keep both ends of the channel alive until the channel is closed.
645 channel->opener->IncrementLazyKeepaliveCount();
646 channel->receiver->IncrementLazyKeepaliveCount();
649 void MessageService::AddChannel(MessageChannel* channel, int receiver_port_id) {
650 DCHECK_CURRENTLY_ON(BrowserThread::UI);
652 int channel_id = GET_CHANNEL_ID(receiver_port_id);
653 CHECK(channels_.find(channel_id) == channels_.end());
654 channels_[channel_id] = channel;
655 pending_lazy_background_page_channels_.erase(channel_id);
658 void MessageService::CloseChannel(int port_id,
659 const std::string& error_message) {
660 DCHECK_CURRENTLY_ON(BrowserThread::UI);
662 // Note: The channel might be gone already, if the other side closed first.
663 int channel_id = GET_CHANNEL_ID(port_id);
664 MessageChannelMap::iterator it = channels_.find(channel_id);
665 if (it == channels_.end()) {
666 PendingLazyBackgroundPageChannelMap::iterator pending =
667 pending_lazy_background_page_channels_.find(channel_id);
668 if (pending != pending_lazy_background_page_channels_.end()) {
669 lazy_background_task_queue_->AddPendingTask(
670 pending->second.first, pending->second.second,
671 base::Bind(&MessageService::PendingLazyBackgroundPageCloseChannel,
672 weak_factory_.GetWeakPtr(), port_id, error_message));
674 return;
676 CloseChannelImpl(it, port_id, error_message, true);
679 void MessageService::CloseChannelImpl(
680 MessageChannelMap::iterator channel_iter,
681 int closing_port_id,
682 const std::string& error_message,
683 bool notify_other_port) {
684 DCHECK_CURRENTLY_ON(BrowserThread::UI);
686 MessageChannel* channel = channel_iter->second;
688 // Notify the other side.
689 if (notify_other_port) {
690 MessagePort* port = IS_OPENER_PORT_ID(closing_port_id) ?
691 channel->receiver.get() : channel->opener.get();
692 port->DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(closing_port_id),
693 error_message);
696 // Balance the IncrementLazyKeepaliveCount() in OpenChannelImpl.
697 channel->opener->DecrementLazyKeepaliveCount();
698 channel->receiver->DecrementLazyKeepaliveCount();
700 delete channel_iter->second;
701 channels_.erase(channel_iter);
704 void MessageService::PostMessage(int source_port_id, const Message& message) {
705 DCHECK_CURRENTLY_ON(BrowserThread::UI);
707 int channel_id = GET_CHANNEL_ID(source_port_id);
708 MessageChannelMap::iterator iter = channels_.find(channel_id);
709 if (iter == channels_.end()) {
710 // If this channel is pending, queue up the PostMessage to run once
711 // the channel opens.
712 EnqueuePendingMessage(source_port_id, channel_id, message);
713 return;
716 DispatchMessage(source_port_id, iter->second, message);
719 void MessageService::Observe(int type,
720 const content::NotificationSource& source,
721 const content::NotificationDetails& details) {
722 DCHECK_CURRENTLY_ON(BrowserThread::UI);
724 switch (type) {
725 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
726 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
727 content::RenderProcessHost* renderer =
728 content::Source<content::RenderProcessHost>(source).ptr();
729 OnProcessClosed(renderer);
730 break;
732 default:
733 NOTREACHED();
734 return;
738 void MessageService::OnProcessClosed(content::RenderProcessHost* process) {
739 DCHECK_CURRENTLY_ON(BrowserThread::UI);
741 // Close any channels that share this renderer. We notify the opposite
742 // port that its pair has closed.
743 for (MessageChannelMap::iterator it = channels_.begin();
744 it != channels_.end(); ) {
745 MessageChannelMap::iterator current = it++;
747 content::RenderProcessHost* opener_process =
748 current->second->opener->GetRenderProcessHost();
749 content::RenderProcessHost* receiver_process =
750 current->second->receiver->GetRenderProcessHost();
752 // Only notify the other side if it has a different porocess host.
753 bool notify_other_port = opener_process && receiver_process &&
754 opener_process != receiver_process;
756 if (opener_process == process) {
757 CloseChannelImpl(current, GET_CHANNEL_OPENER_ID(current->first),
758 std::string(), notify_other_port);
759 } else if (receiver_process == process) {
760 CloseChannelImpl(current, GET_CHANNEL_RECEIVERS_ID(current->first),
761 std::string(), notify_other_port);
766 void MessageService::EnqueuePendingMessage(int source_port_id,
767 int channel_id,
768 const Message& message) {
769 DCHECK_CURRENTLY_ON(BrowserThread::UI);
771 PendingChannelMap::iterator pending_for_incognito =
772 pending_incognito_channels_.find(channel_id);
773 if (pending_for_incognito != pending_incognito_channels_.end()) {
774 pending_for_incognito->second.push_back(
775 PendingMessage(source_port_id, message));
776 // A channel should only be holding pending messages because it is in one
777 // of these states.
778 DCHECK(!ContainsKey(pending_tls_channel_id_channels_, channel_id));
779 DCHECK(!ContainsKey(pending_lazy_background_page_channels_, channel_id));
780 return;
782 PendingChannelMap::iterator pending_for_tls_channel_id =
783 pending_tls_channel_id_channels_.find(channel_id);
784 if (pending_for_tls_channel_id != pending_tls_channel_id_channels_.end()) {
785 pending_for_tls_channel_id->second.push_back(
786 PendingMessage(source_port_id, message));
787 // A channel should only be holding pending messages because it is in one
788 // of these states.
789 DCHECK(!ContainsKey(pending_lazy_background_page_channels_, channel_id));
790 return;
792 EnqueuePendingMessageForLazyBackgroundLoad(source_port_id,
793 channel_id,
794 message);
797 void MessageService::EnqueuePendingMessageForLazyBackgroundLoad(
798 int source_port_id,
799 int channel_id,
800 const Message& message) {
801 DCHECK_CURRENTLY_ON(BrowserThread::UI);
803 PendingLazyBackgroundPageChannelMap::iterator pending =
804 pending_lazy_background_page_channels_.find(channel_id);
805 if (pending != pending_lazy_background_page_channels_.end()) {
806 lazy_background_task_queue_->AddPendingTask(
807 pending->second.first, pending->second.second,
808 base::Bind(&MessageService::PendingLazyBackgroundPagePostMessage,
809 weak_factory_.GetWeakPtr(), source_port_id, message));
813 void MessageService::DispatchMessage(int source_port_id,
814 MessageChannel* channel,
815 const Message& message) {
816 DCHECK_CURRENTLY_ON(BrowserThread::UI);
818 // Figure out which port the ID corresponds to.
819 int dest_port_id = GET_OPPOSITE_PORT_ID(source_port_id);
820 MessagePort* port = IS_OPENER_PORT_ID(dest_port_id) ?
821 channel->opener.get() : channel->receiver.get();
823 port->DispatchOnMessage(message, dest_port_id);
826 bool MessageService::MaybeAddPendingLazyBackgroundPageOpenChannelTask(
827 BrowserContext* context,
828 const Extension* extension,
829 scoped_ptr<OpenChannelParams>* params,
830 const PendingMessagesQueue& pending_messages) {
831 DCHECK_CURRENTLY_ON(BrowserThread::UI);
833 if (!BackgroundInfo::HasLazyBackgroundPage(extension))
834 return false;
836 // If the extension uses spanning incognito mode, make sure we're always
837 // using the original profile since that is what the extension process
838 // will use.
839 if (!IncognitoInfo::IsSplitMode(extension))
840 context = ExtensionsBrowserClient::Get()->GetOriginalContext(context);
842 if (!lazy_background_task_queue_->ShouldEnqueueTask(context, extension))
843 return false;
845 int channel_id = GET_CHANNEL_ID((*params)->receiver_port_id);
846 pending_lazy_background_page_channels_[channel_id] =
847 PendingLazyBackgroundPageChannel(context, extension->id());
848 int source_id = (*params)->source_process_id;
849 lazy_background_task_queue_->AddPendingTask(
850 context, extension->id(),
851 base::Bind(&MessageService::PendingLazyBackgroundPageOpenChannel,
852 weak_factory_.GetWeakPtr(), base::Passed(params), source_id));
854 for (const PendingMessage& message : pending_messages) {
855 EnqueuePendingMessageForLazyBackgroundLoad(message.first, channel_id,
856 message.second);
858 return true;
861 void MessageService::OnOpenChannelAllowed(scoped_ptr<OpenChannelParams> params,
862 bool allowed) {
863 DCHECK_CURRENTLY_ON(BrowserThread::UI);
865 int channel_id = GET_CHANNEL_ID(params->receiver_port_id);
867 PendingChannelMap::iterator pending_for_incognito =
868 pending_incognito_channels_.find(channel_id);
869 if (pending_for_incognito == pending_incognito_channels_.end()) {
870 NOTREACHED();
871 return;
873 PendingMessagesQueue pending_messages;
874 pending_messages.swap(pending_for_incognito->second);
875 pending_incognito_channels_.erase(pending_for_incognito);
877 // Re-lookup the source process since it may no longer be valid.
878 content::RenderProcessHost* source =
879 content::RenderProcessHost::FromID(params->source_process_id);
880 if (!source) {
881 return;
884 if (!allowed) {
885 DispatchOnDisconnect(source, params->receiver_port_id,
886 kReceivingEndDoesntExistError);
887 return;
890 BrowserContext* context = source->GetBrowserContext();
892 // Note: we use the source's profile here. If the source is an incognito
893 // process, we will use the incognito EPM to find the right extension process,
894 // which depends on whether the extension uses spanning or split mode.
895 params->receiver.reset(new ExtensionMessagePort(
896 GetExtensionProcess(context, params->target_extension_id),
897 MSG_ROUTING_CONTROL, params->target_extension_id));
899 // If the target requests the TLS channel id, begin the lookup for it.
900 // The target might also be a lazy background page, checked next, but the
901 // loading of lazy background pages continues asynchronously, so enqueue
902 // messages awaiting TLS channel ID first.
903 if (params->include_tls_channel_id) {
904 // Transfer pending messages to the next pending channel list.
905 pending_tls_channel_id_channels_[channel_id].swap(pending_messages);
906 // Capture this reference before params is invalidated by base::Passed().
907 const GURL& source_url = params->source_url;
908 property_provider_.GetChannelID(
909 Profile::FromBrowserContext(context), source_url,
910 base::Bind(&MessageService::GotChannelID, weak_factory_.GetWeakPtr(),
911 base::Passed(&params)));
912 return;
915 ExtensionRegistry* registry = ExtensionRegistry::Get(context);
916 const Extension* target_extension =
917 registry->enabled_extensions().GetByID(params->target_extension_id);
918 if (!target_extension) {
919 DispatchOnDisconnect(source, params->receiver_port_id,
920 kReceivingEndDoesntExistError);
921 return;
924 // The target might be a lazy background page. In that case, we have to check
925 // if it is loaded and ready, and if not, queue up the task and load the
926 // page.
927 if (!MaybeAddPendingLazyBackgroundPageOpenChannelTask(
928 context, target_extension, &params, pending_messages)) {
929 OpenChannelImpl(context, params.Pass(), target_extension,
930 false /* did_enqueue */);
931 DispatchPendingMessages(pending_messages, channel_id);
935 void MessageService::GotChannelID(scoped_ptr<OpenChannelParams> params,
936 const std::string& tls_channel_id) {
937 DCHECK_CURRENTLY_ON(BrowserThread::UI);
939 params->tls_channel_id.assign(tls_channel_id);
940 int channel_id = GET_CHANNEL_ID(params->receiver_port_id);
942 PendingChannelMap::iterator pending_for_tls_channel_id =
943 pending_tls_channel_id_channels_.find(channel_id);
944 if (pending_for_tls_channel_id == pending_tls_channel_id_channels_.end()) {
945 NOTREACHED();
946 return;
948 PendingMessagesQueue pending_messages;
949 pending_messages.swap(pending_for_tls_channel_id->second);
950 pending_tls_channel_id_channels_.erase(pending_for_tls_channel_id);
952 // Re-lookup the source process since it may no longer be valid.
953 content::RenderProcessHost* source =
954 content::RenderProcessHost::FromID(params->source_process_id);
955 if (!source) {
956 return;
959 BrowserContext* context = source->GetBrowserContext();
960 ExtensionRegistry* registry = ExtensionRegistry::Get(context);
961 const Extension* target_extension =
962 registry->enabled_extensions().GetByID(params->target_extension_id);
963 if (!target_extension) {
964 DispatchOnDisconnect(source, params->receiver_port_id,
965 kReceivingEndDoesntExistError);
966 return;
969 if (!MaybeAddPendingLazyBackgroundPageOpenChannelTask(
970 context, target_extension, &params, pending_messages)) {
971 OpenChannelImpl(context, params.Pass(), target_extension,
972 false /* did_enqueue */);
973 DispatchPendingMessages(pending_messages, channel_id);
977 void MessageService::PendingLazyBackgroundPageOpenChannel(
978 scoped_ptr<OpenChannelParams> params,
979 int source_process_id,
980 ExtensionHost* host) {
981 DCHECK_CURRENTLY_ON(BrowserThread::UI);
983 if (!host)
984 return; // TODO(mpcomplete): notify source of disconnect?
986 params->receiver.reset(new ExtensionMessagePort(host->render_process_host(),
987 MSG_ROUTING_CONTROL,
988 params->target_extension_id));
989 OpenChannelImpl(host->browser_context(), params.Pass(), host->extension(),
990 true /* did_enqueue */);
993 void MessageService::DispatchOnDisconnect(content::RenderProcessHost* source,
994 int port_id,
995 const std::string& error_message) {
996 DCHECK_CURRENTLY_ON(BrowserThread::UI);
998 ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, "");
999 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(port_id), error_message);
1002 void MessageService::DispatchPendingMessages(const PendingMessagesQueue& queue,
1003 int channel_id) {
1004 DCHECK_CURRENTLY_ON(BrowserThread::UI);
1006 MessageChannelMap::iterator channel_iter = channels_.find(channel_id);
1007 if (channel_iter != channels_.end()) {
1008 for (const PendingMessage& message : queue) {
1009 DispatchMessage(message.first, channel_iter->second, message.second);
1014 } // namespace extensions