Index: chrome/browser/extensions/api/messaging/message_service.cc |
=================================================================== |
--- chrome/browser/extensions/api/messaging/message_service.cc (revision 158832) |
+++ chrome/browser/extensions/api/messaging/message_service.cc (working copy) |
@@ -10,6 +10,8 @@ |
#include "base/json/json_writer.h" |
#include "base/stl_util.h" |
#include "base/values.h" |
+#include "chrome/browser/extensions/api/messaging/extension_message_port.h" |
+#include "chrome/browser/extensions/api/messaging/native_message_port.h" |
#include "chrome/browser/extensions/extension_host.h" |
#include "chrome/browser/extensions/extension_process_manager.h" |
#include "chrome/browser/extensions/extension_service.h" |
@@ -24,6 +26,7 @@ |
#include "chrome/common/extensions/extension.h" |
#include "chrome/common/extensions/extension_messages.h" |
#include "chrome/common/view_type.h" |
+#include "content/public/browser/browser_thread.h" |
#include "content/public/browser/notification_service.h" |
#include "content/public/browser/render_process_host.h" |
#include "content/public/browser/render_view_host.h" |
@@ -47,42 +50,24 @@ |
namespace extensions { |
-struct MessageService::MessagePort { |
- content::RenderProcessHost* process; |
- int routing_id; |
- std::string extension_id; |
- void* background_host_ptr; // used in IncrementLazyKeepaliveCount |
- |
- MessagePort() |
- : process(NULL), |
- routing_id(MSG_ROUTING_CONTROL), |
- background_host_ptr(NULL) {} |
- MessagePort(content::RenderProcessHost* process, |
- int routing_id, |
- const std::string& extension_id) |
- : process(process), |
- routing_id(routing_id), |
- extension_id(extension_id), |
- background_host_ptr(NULL) {} |
-}; |
- |
struct MessageService::MessageChannel { |
- MessageService::MessagePort opener; |
- MessageService::MessagePort receiver; |
+ scoped_ptr<MessagePort> opener; |
+ scoped_ptr<MessagePort> receiver; |
}; |
struct MessageService::OpenChannelParams { |
content::RenderProcessHost* source; |
std::string tab_json; |
- MessagePort receiver; |
+ scoped_ptr<MessagePort> receiver; |
int receiver_port_id; |
std::string source_extension_id; |
std::string target_extension_id; |
std::string channel_name; |
+ // Takes ownership of receiver. |
OpenChannelParams(content::RenderProcessHost* source, |
const std::string& tab_json, |
- const MessagePort& receiver, |
+ MessagePort* receiver, |
int receiver_port_id, |
const std::string& source_extension_id, |
const std::string& target_extension_id, |
@@ -100,31 +85,6 @@ |
static base::StaticAtomicSequenceNumber g_next_channel_id; |
-static void DispatchOnConnect(const MessageService::MessagePort& port, |
- int dest_port_id, |
- const std::string& channel_name, |
- const std::string& tab_json, |
- const std::string& source_extension_id, |
- const std::string& target_extension_id) { |
- port.process->Send(new ExtensionMsg_DispatchOnConnect( |
- port.routing_id, dest_port_id, channel_name, |
- tab_json, source_extension_id, target_extension_id)); |
-} |
- |
-static void DispatchOnDisconnect(const MessageService::MessagePort& port, |
- int source_port_id, |
- bool connection_error) { |
- port.process->Send(new ExtensionMsg_DispatchOnDisconnect( |
- port.routing_id, source_port_id, connection_error)); |
-} |
- |
-static void DispatchOnMessage(const MessageService::MessagePort& port, |
- const std::string& message, |
- int target_port_id) { |
- port.process->Send(new ExtensionMsg_DeliverMessage( |
- port.routing_id, target_port_id, message)); |
-} |
- |
static content::RenderProcessHost* GetExtensionProcess( |
Profile* profile, const std::string& extension_id) { |
SiteInstance* site_instance = |
@@ -137,32 +97,13 @@ |
return site_instance->GetProcess(); |
} |
-static void IncrementLazyKeepaliveCount(MessageService::MessagePort* port) { |
- Profile* profile = |
- Profile::FromBrowserContext(port->process->GetBrowserContext()); |
- ExtensionProcessManager* pm = |
- ExtensionSystem::Get(profile)->process_manager(); |
- ExtensionHost* host = pm->GetBackgroundHostForExtension(port->extension_id); |
- if (host && host->extension()->has_lazy_background_page()) |
- pm->IncrementLazyKeepaliveCount(host->extension()); |
+} // namespace |
- // Keep track of the background host, so when we decrement, we only do so if |
- // the host hasn't reloaded. |
- port->background_host_ptr = host; |
+content::RenderProcessHost* |
+ MessageService::MessagePort::GetRenderProcessHost() { |
+ return NULL; |
} |
-static void DecrementLazyKeepaliveCount(MessageService::MessagePort* port) { |
- Profile* profile = |
- Profile::FromBrowserContext(port->process->GetBrowserContext()); |
- ExtensionProcessManager* pm = |
- ExtensionSystem::Get(profile)->process_manager(); |
- ExtensionHost* host = pm->GetBackgroundHostForExtension(port->extension_id); |
- if (host && host == port->background_host_ptr) |
- pm->DecrementLazyKeepaliveCount(host->extension()); |
-} |
- |
-} // namespace |
- |
// static |
void MessageService::AllocatePortIdPair(int* port1, int* port2) { |
int channel_id = g_next_channel_id.GetNext(); |
@@ -184,7 +125,8 @@ |
MessageService::MessageService( |
LazyBackgroundTaskQueue* queue) |
- : lazy_background_task_queue_(queue) { |
+ : lazy_background_task_queue_(queue), |
+ weak_factory_(this) { |
registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, |
content::NotificationService::AllBrowserContextsAndSources()); |
registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, |
@@ -210,9 +152,9 @@ |
// Note: we use the source's profile here. If the source is an incognito |
// process, we will use the incognito EPM to find the right extension process, |
// which depends on whether the extension uses spanning or split mode. |
- MessagePort receiver(GetExtensionProcess(profile, target_extension_id), |
- MSG_ROUTING_CONTROL, |
- target_extension_id); |
+ MessagePort* receiver = new ExtensionMessagePort( |
+ GetExtensionProcess(profile, target_extension_id), MSG_ROUTING_CONTROL, |
+ target_extension_id); |
WebContents* source_contents = tab_util::GetWebContentsByID( |
source_process_id, source_routing_id); |
@@ -224,19 +166,92 @@ |
base::JSONWriter::Write(tab_value.get(), &tab_json); |
} |
- OpenChannelParams params(source, tab_json, receiver, receiver_port_id, |
- source_extension_id, target_extension_id, |
- channel_name); |
+ OpenChannelParams* params = new OpenChannelParams(source, tab_json, receiver, |
+ receiver_port_id, |
+ source_extension_id, |
+ target_extension_id, |
+ channel_name); |
// The target might be a lazy background page. In that case, we have to check |
// if it is loaded and ready, and if not, queue up the task and load the |
// page. |
- if (MaybeAddPendingOpenChannelTask(profile, params)) |
+ if (MaybeAddPendingOpenChannelTask(profile, params)) { |
return; |
+ } |
- OpenChannelImpl(params); |
+ OpenChannelImpl(scoped_ptr<OpenChannelParams>(params)); |
} |
+void MessageService::OpenChannelToNativeApp( |
+ int source_process_id, |
+ int source_routing_id, |
+ int receiver_port_id, |
+ const std::string& source_extension_id, |
+ const std::string& native_app_name, |
+ const std::string& channel_name, |
+ const std::string& connect_message) { |
+ content::RenderProcessHost* source = |
+ content::RenderProcessHost::FromID(source_process_id); |
+ if (!source) |
+ return; |
+ |
+ WebContents* source_contents = tab_util::GetWebContentsByID( |
+ source_process_id, source_routing_id); |
+ |
+ // Include info about the opener's tab (if it was a tab). |
+ std::string tab_json = "null"; |
+ if (source_contents) { |
+ scoped_ptr<DictionaryValue> tab_value(ExtensionTabUtil::CreateTabValue( |
+ source_contents, ExtensionTabUtil::INCLUDE_PRIVACY_SENSITIVE_FIELDS)); |
+ base::JSONWriter::Write(tab_value.get(), &tab_json); |
+ } |
+ |
+ scoped_ptr<MessageChannel> channel(new MessageChannel()); |
+ channel->opener.reset(new ExtensionMessagePort(source, MSG_ROUTING_CONTROL, |
+ source_extension_id)); |
+ |
+ NativeMessageProcessHost::MessageType type = |
+ channel_name == "chrome.extension.sendNativeMessage" ? |
+ NativeMessageProcessHost::TYPE_SEND_MESSAGE_REQUEST : |
+ NativeMessageProcessHost::TYPE_CONNECT; |
+ |
+ content::BrowserThread::PostTask( |
+ content::BrowserThread::FILE, |
+ FROM_HERE, |
+ base::Bind(&NativeMessageProcessHost::Create, |
+ base::WeakPtr<NativeMessageProcessHost::Client>( |
+ weak_factory_.GetWeakPtr()), |
+ native_app_name, connect_message, receiver_port_id, |
+ type, |
+ base::Bind(&MessageService::FinalizeOpenChannelToNativeApp, |
+ weak_factory_.GetWeakPtr(), |
+ receiver_port_id, |
+ channel_name, |
+ base::Passed(&channel), |
+ tab_json))); |
+} |
+ |
+void MessageService::FinalizeOpenChannelToNativeApp( |
+ int receiver_port_id, |
+ const std::string& channel_name, |
+ scoped_ptr<MessageChannel> channel, |
+ const std::string& tab_json, |
+ NativeMessageProcessHost::ScopedHost native_process) { |
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
+ |
+ // Abandon the channel |
+ if (!native_process.get()) { |
+ LOG(ERROR) << "Failed to create native process."; |
+ return; |
+ } |
+ channel->receiver.reset(new NativeMessagePort(native_process.release())); |
+ |
+ // Keep the opener alive until the channel is closed. |
+ channel->opener->IncrementLazyKeepaliveCount(); |
+ |
+ AddChannel(channel.release(), receiver_port_id); |
+} |
+ |
void MessageService::OpenChannelToTab( |
int source_process_id, int source_routing_id, int receiver_port_id, |
int tab_id, const std::string& extension_id, |
@@ -248,20 +263,20 @@ |
Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext()); |
TabContents* contents = NULL; |
- MessagePort receiver; |
+ scoped_ptr<MessagePort> receiver; |
if (ExtensionTabUtil::GetTabById(tab_id, profile, true, |
NULL, NULL, &contents, NULL)) { |
- receiver.process = contents->web_contents()->GetRenderProcessHost(); |
- receiver.routing_id = |
- contents->web_contents()->GetRenderViewHost()->GetRoutingID(); |
- receiver.extension_id = extension_id; |
+ receiver.reset(new ExtensionMessagePort( |
+ contents->web_contents()->GetRenderProcessHost(), |
+ contents->web_contents()->GetRenderViewHost()->GetRoutingID(), |
+ extension_id)); |
} |
if (contents && contents->web_contents()->GetController().NeedsReload()) { |
// The tab isn't loaded yet. Don't attempt to connect. Treat this as a |
// disconnect. |
- DispatchOnDisconnect(MessagePort(source, MSG_ROUTING_CONTROL, extension_id), |
- GET_OPPOSITE_PORT_ID(receiver_port_id), true); |
+ ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, extension_id); |
+ port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(receiver_port_id), true); |
return; |
} |
@@ -276,52 +291,63 @@ |
base::JSONWriter::Write(tab_value.get(), &tab_json); |
} |
- OpenChannelParams params(source, tab_json, receiver, receiver_port_id, |
- extension_id, extension_id, channel_name); |
- OpenChannelImpl(params); |
+ scoped_ptr<OpenChannelParams> params(new OpenChannelParams(source, tab_json, |
+ receiver.release(), |
+ receiver_port_id, |
+ extension_id, |
+ extension_id, |
+ channel_name)); |
+ OpenChannelImpl(params.Pass()); |
} |
-bool MessageService::OpenChannelImpl(const OpenChannelParams& params) { |
- if (!params.source) |
+bool MessageService::OpenChannelImpl(scoped_ptr<OpenChannelParams> params) { |
+ if (!params->source) |
return false; // Closed while in flight. |
- if (!params.receiver.process) { |
+ if (!params->receiver.get() || !params->receiver->GetRenderProcessHost()) { |
// Treat it as a disconnect. |
- DispatchOnDisconnect(MessagePort(params.source, MSG_ROUTING_CONTROL, ""), |
- GET_OPPOSITE_PORT_ID(params.receiver_port_id), true); |
+ ExtensionMessagePort port(params->source, MSG_ROUTING_CONTROL, ""); |
+ port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(params->receiver_port_id), |
+ true); |
return false; |
} |
// Add extra paranoid CHECKs, since we have crash reports of this being NULL. |
// http://code.google.com/p/chromium/issues/detail?id=19067 |
- CHECK(params.receiver.process); |
+ CHECK(params->receiver->GetRenderProcessHost()); |
MessageChannel* channel(new MessageChannel); |
- channel->opener = MessagePort(params.source, MSG_ROUTING_CONTROL, |
- params.source_extension_id); |
- channel->receiver = params.receiver; |
+ channel->opener.reset(new ExtensionMessagePort(params->source, |
+ MSG_ROUTING_CONTROL, |
+ params->source_extension_id)); |
+ channel->receiver.reset(params->receiver.release()); |
- CHECK(params.receiver.process); |
+ CHECK(channel->receiver->GetRenderProcessHost()); |
- int channel_id = GET_CHANNEL_ID(params.receiver_port_id); |
- CHECK(channels_.find(channel_id) == channels_.end()); |
- channels_[channel_id] = channel; |
- pending_channels_.erase(channel_id); |
+ AddChannel(channel, params->receiver_port_id); |
- CHECK(params.receiver.process); |
+ CHECK(channel->receiver->GetRenderProcessHost()); |
// Send the connect event to the receiver. Give it the opener's port ID (the |
// opener has the opposite port ID). |
- DispatchOnConnect(params.receiver, params.receiver_port_id, |
- params.channel_name, params.tab_json, |
- params.source_extension_id, params.target_extension_id); |
+ channel->receiver->DispatchOnConnect(params->receiver_port_id, |
+ params->channel_name, params->tab_json, |
+ params->source_extension_id, |
+ params->target_extension_id); |
// Keep both ends of the channel alive until the channel is closed. |
- IncrementLazyKeepaliveCount(&channel->opener); |
- IncrementLazyKeepaliveCount(&channel->receiver); |
+ channel->opener->IncrementLazyKeepaliveCount(); |
+ channel->receiver->IncrementLazyKeepaliveCount(); |
return true; |
} |
+void MessageService::AddChannel(MessageChannel* channel, int receiver_port_id) { |
+ int channel_id = GET_CHANNEL_ID(receiver_port_id); |
+ CHECK(channels_.find(channel_id) == channels_.end()); |
+ channels_[channel_id] = channel; |
+ pending_channels_.erase(channel_id); |
+} |
+ |
void MessageService::CloseChannel(int port_id, bool connection_error) { |
// Note: The channel might be gone already, if the other side closed first. |
int channel_id = GET_CHANNEL_ID(port_id); |
@@ -332,7 +358,7 @@ |
lazy_background_task_queue_->AddPendingTask( |
pending->second.first, pending->second.second, |
base::Bind(&MessageService::PendingCloseChannel, |
- base::Unretained(this), port_id, connection_error)); |
+ weak_factory_.GetWeakPtr(), port_id, connection_error)); |
} |
return; |
} |
@@ -346,21 +372,21 @@ |
// Notify the other side. |
if (notify_other_port) { |
- const MessagePort& port = IS_OPENER_PORT_ID(closing_port_id) ? |
- channel->receiver : channel->opener; |
- DispatchOnDisconnect(port, GET_OPPOSITE_PORT_ID(closing_port_id), |
- connection_error); |
+ MessagePort* port = IS_OPENER_PORT_ID(closing_port_id) ? |
+ channel->receiver.get() : channel->opener.get(); |
+ port->DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(closing_port_id), |
+ connection_error); |
} |
- // Balance the addrefs in OpenChannelImpl. |
- DecrementLazyKeepaliveCount(&channel->opener); |
- DecrementLazyKeepaliveCount(&channel->receiver); |
+ // Balance the IncrementLazyKeepaliveCount() in OpenChannelImpl. |
+ channel->opener->DecrementLazyKeepaliveCount(); |
+ channel->receiver->DecrementLazyKeepaliveCount(); |
delete channel_iter->second; |
channels_.erase(channel_iter); |
} |
-void MessageService::PostMessageFromRenderer( |
+void MessageService::PostMessage( |
int source_port_id, const std::string& message) { |
int channel_id = GET_CHANNEL_ID(source_port_id); |
MessageChannelMap::iterator iter = channels_.find(channel_id); |
@@ -372,19 +398,24 @@ |
lazy_background_task_queue_->AddPendingTask( |
pending->second.first, pending->second.second, |
base::Bind(&MessageService::PendingPostMessage, |
- base::Unretained(this), source_port_id, message)); |
+ weak_factory_.GetWeakPtr(), source_port_id, message)); |
} |
return; |
} |
// Figure out which port the ID corresponds to. |
int dest_port_id = GET_OPPOSITE_PORT_ID(source_port_id); |
- const MessagePort& port = IS_OPENER_PORT_ID(dest_port_id) ? |
- iter->second->opener : iter->second->receiver; |
+ MessagePort* port = IS_OPENER_PORT_ID(dest_port_id) ? |
+ iter->second->opener.get() : iter->second->receiver.get(); |
- DispatchOnMessage(port, message, dest_port_id); |
+ port->DispatchOnMessage(message, dest_port_id); |
} |
+void MessageService::PostMessageFromNativeProcess(int port_id, |
+ const std::string& message) { |
+ PostMessage(port_id, message); |
+} |
+ |
void MessageService::Observe(int type, |
const content::NotificationSource& source, |
const content::NotificationDetails& details) { |
@@ -408,28 +439,31 @@ |
for (MessageChannelMap::iterator it = channels_.begin(); |
it != channels_.end(); ) { |
MessageChannelMap::iterator current = it++; |
- // If both sides are the same renderer, and it is closing, there is no |
- // "other" port, so there's no need to notify it. |
- bool notify_other_port = |
- current->second->opener.process != current->second->receiver.process; |
- if (current->second->opener.process == process) { |
+ content::RenderProcessHost* opener_process = |
+ current->second->opener->GetRenderProcessHost(); |
+ content::RenderProcessHost* receiver_process = |
+ current->second->receiver->GetRenderProcessHost(); |
+ |
+ bool notify_other_port = opener_process && |
+ opener_process == receiver_process; |
+ |
+ if (opener_process == process) { |
CloseChannelImpl(current, GET_CHANNEL_OPENER_ID(current->first), |
- false, notify_other_port); |
- } else if (current->second->receiver.process == process) { |
+ false, notify_other_port); |
+ } else if (receiver_process == process) { |
CloseChannelImpl(current, GET_CHANNEL_RECEIVERS_ID(current->first), |
- false, notify_other_port); |
+ false, notify_other_port); |
} |
} |
} |
bool MessageService::MaybeAddPendingOpenChannelTask( |
Profile* profile, |
- const OpenChannelParams& params) { |
+ OpenChannelParams* params) { |
ExtensionService* service = profile->GetExtensionService(); |
- const std::string& extension_id = params.target_extension_id; |
- const Extension* extension = service->extensions()->GetByID( |
- extension_id); |
+ const std::string& extension_id = params->target_extension_id; |
+ const Extension* extension = service->extensions()->GetByID(extension_id); |
if (extension && extension->has_lazy_background_page()) { |
// If the extension uses spanning incognito mode, make sure we're always |
// using the original profile since that is what the extension process |
@@ -438,11 +472,13 @@ |
profile = profile->GetOriginalProfile(); |
if (lazy_background_task_queue_->ShouldEnqueueTask(profile, extension)) { |
+ pending_channels_[GET_CHANNEL_ID(params->receiver_port_id)] = |
+ PendingChannel(profile, extension_id); |
+ scoped_ptr<OpenChannelParams> scoped_params(params); |
lazy_background_task_queue_->AddPendingTask(profile, extension_id, |
base::Bind(&MessageService::PendingOpenChannel, |
- base::Unretained(this), params, params.source->GetID())); |
- pending_channels_[GET_CHANNEL_ID(params.receiver_port_id)] = |
- PendingChannel(profile, extension_id); |
+ weak_factory_.GetWeakPtr(), base::Passed(&scoped_params), |
+ params->source->GetID())); |
return true; |
} |
} |
@@ -450,22 +486,23 @@ |
return false; |
} |
-void MessageService::PendingOpenChannel(const OpenChannelParams& params_in, |
+void MessageService::PendingOpenChannel(scoped_ptr<OpenChannelParams> params, |
int source_process_id, |
ExtensionHost* host) { |
if (!host) |
return; // TODO(mpcomplete): notify source of disconnect? |
// Re-lookup the source process since it may no longer be valid. |
- OpenChannelParams params = params_in; |
- params.source = content::RenderProcessHost::FromID(source_process_id); |
- if (!params.source) |
+ content::RenderProcessHost* source = |
+ content::RenderProcessHost::FromID(source_process_id); |
+ if (!source) |
return; |
- params.receiver = MessagePort(host->render_process_host(), |
- MSG_ROUTING_CONTROL, |
- params.target_extension_id); |
- OpenChannelImpl(params); |
+ params->source = source; |
+ params->receiver.reset(new ExtensionMessagePort(host->render_process_host(), |
+ MSG_ROUTING_CONTROL, |
+ params->target_extension_id)); |
+ OpenChannelImpl(params.Pass()); |
} |
} // namespace extensions |