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