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