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