| 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
|
|
|
|
|