diff options
author | sdoyon@chromium.org <sdoyon@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-26 19:30:15 +0000 |
---|---|---|
committer | sdoyon@chromium.org <sdoyon@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-08-26 19:30:15 +0000 |
commit | a1ec6d1f82699b1e06cca1bca9efdb4ed212c2c3 (patch) | |
tree | 75e77bb933a9ce8149df5053fa82fe619c42c044 | |
parent | 51a0f7d1e4a47ff6dbc739687237f17a62bc8333 (diff) | |
download | chromium_src-a1ec6d1f82699b1e06cca1bca9efdb4ed212c2c3.zip chromium_src-a1ec6d1f82699b1e06cca1bca9efdb4ed212c2c3.tar.gz chromium_src-a1ec6d1f82699b1e06cca1bca9efdb4ed212c2c3.tar.bz2 |
Extension ports devtools remote service.
Wires message ports to extensions through the devtools remote socket.
BUG=none
TEST=none
Review URL: http://codereview.chromium.org/174226
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@24499 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/automation/extension_port_container.cc | 7 | ||||
-rw-r--r-- | chrome/browser/debugger/debugger_wrapper.cc | 4 | ||||
-rw-r--r-- | chrome/browser/debugger/extension_ports_remote_service.cc | 383 | ||||
-rw-r--r-- | chrome/browser/debugger/extension_ports_remote_service.h | 105 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_message_service.cc | 66 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_message_service.h | 38 | ||||
-rw-r--r-- | chrome/chrome.gyp | 2 |
7 files changed, 565 insertions, 40 deletions
diff --git a/chrome/browser/automation/extension_port_container.cc b/chrome/browser/automation/extension_port_container.cc index f0ff246..034988a 100644 --- a/chrome/browser/automation/extension_port_container.cc +++ b/chrome/browser/automation/extension_port_container.cc @@ -65,11 +65,8 @@ bool ExtensionPortContainer::Connect(const std::string &extension_id, const std::string& channel_name) { DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); - port_id_ = service_->OpenAutomationChannelToExtension(process_id, - routing_id, - extension_id, - channel_name, - this); + port_id_ = service_->OpenSpecialChannelToExtension( + extension_id, channel_name, this); if (port_id_ == -1) { // In this case a disconnect message has been dispatched. return false; diff --git a/chrome/browser/debugger/debugger_wrapper.cc b/chrome/browser/debugger/debugger_wrapper.cc index fa2fac6..c551846 100644 --- a/chrome/browser/debugger/debugger_wrapper.cc +++ b/chrome/browser/debugger/debugger_wrapper.cc @@ -7,6 +7,7 @@ #include "chrome/browser/debugger/debugger_remote_service.h" #include "chrome/browser/debugger/devtools_protocol_handler.h" #include "chrome/browser/debugger/devtools_remote_service.h" +#include "chrome/browser/debugger/extension_ports_remote_service.h" DebuggerWrapper::DebuggerWrapper(int port) { if (port > 0) { @@ -17,6 +18,9 @@ DebuggerWrapper::DebuggerWrapper(int port) { proto_handler_->RegisterDestination( new DebuggerRemoteService(proto_handler_), DebuggerRemoteService::kToolName); + proto_handler_->RegisterDestination( + new ExtensionPortsRemoteService(proto_handler_), + ExtensionPortsRemoteService::kToolName); proto_handler_->Start(); } } diff --git a/chrome/browser/debugger/extension_ports_remote_service.cc b/chrome/browser/debugger/extension_ports_remote_service.cc new file mode 100644 index 0000000..a6bfa22 --- /dev/null +++ b/chrome/browser/debugger/extension_ports_remote_service.cc @@ -0,0 +1,383 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Implementation of the ExtensionPortsRemoteService. + +// Inspired significantly from debugger_remote_service +// and ../automation/extension_port_container. + +#include "chrome/browser/debugger/extension_ports_remote_service.h" + +#include "base/json_reader.h" +#include "base/json_writer.h" +#include "base/message_loop.h" +#include "base/string_util.h" +#include "base/values.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/debugger/devtools_manager.h" +#include "chrome/browser/debugger/devtools_protocol_handler.h" +#include "chrome/browser/debugger/devtools_remote_message.h" +#include "chrome/browser/debugger/inspectable_tab_proxy.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/profile_manager.h" +#include "chrome/browser/tab_contents/tab_contents.h" +#include "chrome/common/devtools_messages.h" +#include "chrome/common/render_messages.h" + +namespace { + +// Protocol is as follows: +// +// From external client: +// {"command": "connect", +// "data": { +// "extensionId": "<extension_id string>", +// "channelName": "<port name string>", (optional) +// "tabId": <numerical tab ID> (optional) +// } +// } +// To connect to a background page or tool strip, the tabId should be omitted. +// Tab IDs can be enumerated with the list_tabs DevToolsService command. +// +// Response: +// {"command": "connect", +// "result": 0, (assuming success) +// "data": { +// "portId": <numerical port ID> +// } +// } +// +// Posting a message from external client: +// Put the target message port ID in the devtools destination field. +// {"command": "postMessage", +// "data": <message body - arbitrary JSON> +// } +// Response: +// {"command": "postMessage", +// "result": 0 (Assuming success) +// } +// Note this is a confirmation from the devtools protocol layer, not +// a response from the extension. +// +// Message from an extension to the external client: +// The message port ID is in the devtools destination field. +// {"command": "onMessage", +// "result": 0, (Always 0) +// "data": <message body - arbitrary JSON> +// } +// +// The "disconnect" command from the external client, and +// "onDisconnect" notification from the ExtensionMessageService, are +// similar: with the message port ID in the destination field, but no +// "data" field in this case. + +// Commands: +static const std::string kConnect = "connect"; +static const std::string kDisconnect = "disconnect"; +static const std::string kPostMessage = "postMessage"; +// Events: +static const std::string kOnMessage = "onMessage"; +static const std::string kOnDisconnect = "onDisconnect"; + +// Constants for the JSON message fields. +// The type is wstring because the constant is used to get a +// DictionaryValue field (which requires a wide string). + +// Mandatory. +static const std::wstring kCommandWide = L"command"; + +// Always present in messages sent to the external client. +static const std::wstring kResultWide = L"result"; + +// Field for command-specific parameters. Not strictly necessary, but +// makes it more similar to the remote debugger protocol, which should +// allow easier reuse of client code. +static const std::wstring kDataWide = L"data"; + +// Fields within the "data" dictionary: + +// Required for "connect": +static const std::wstring kExtensionIdWide = L"extensionId"; +// Optional in "connect": +static const std::wstring kChannelNameWide = L"channelName"; +static const std::wstring kTabIdWide = L"tabId"; + +// Present under "data" in replies to a successful "connect" . +static const std::wstring kPortIdWide = L"portId"; + +} // namespace + +const std::string ExtensionPortsRemoteService::kToolName = "ExtensionPorts"; + +ExtensionPortsRemoteService::ExtensionPortsRemoteService( + DevToolsProtocolHandler* delegate) + : delegate_(delegate), service_(NULL) { + // We need an ExtensionMessageService instance. It hangs off of + // |profile|. But we do not have a particular tab or RenderViewHost + // as context. I'll just use the first active profile not in + // incognito mode. But this is probably not the right way. + ProfileManager* profile_manager = g_browser_process->profile_manager(); + if (!profile_manager) { + LOG(WARNING) << "No profile manager for ExtensionPortsRemoteService"; + return; + } + for (ProfileManager::ProfileVector::const_iterator it + = profile_manager->begin(); + it != profile_manager->end(); + ++it) { + if (!(*it)->IsOffTheRecord()) { + service_ = (*it)->GetExtensionMessageService(); + break; + } + } + if (!service_) + LOG(WARNING) << "No usable profile for ExtensionPortsRemoteService"; +} + +void ExtensionPortsRemoteService::HandleMessage( + const DevToolsRemoteMessage& message) { + DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); + const std::string destinationString = message.destination(); + scoped_ptr<Value> request(JSONReader::Read(message.content(), true)); + if (request.get() == NULL) { + // Bad JSON + NOTREACHED(); + return; + } + DictionaryValue* content; + if (!request->IsType(Value::TYPE_DICTIONARY)) { + NOTREACHED(); // Broken protocol :( + return; + } + content = static_cast<DictionaryValue*>(request.get()); + if (!content->HasKey(kCommandWide)) { + NOTREACHED(); // Broken protocol :( + return; + } + std::string command; + DictionaryValue response; + + content->GetString(kCommandWide, &command); + response.SetString(kCommandWide, command); + + if (!service_) { + // This happens if we failed to obtain an ExtensionMessageService + // during initialization. + NOTREACHED(); + response.SetInteger(kResultWide, RESULT_NO_SERVICE); + SendResponse(response, message.tool(), message.destination()); + return; + } + + int destination = -1; + if (destinationString.size() != 0) + StringToInt(destinationString, &destination); + + if (command == kConnect) { + if (destination != -1) // destination should be empty for this command. + response.SetInteger(kResultWide, RESULT_UNKNOWN_COMMAND); + else + ConnectCommand(content, &response); + } else if (command == kDisconnect) { + if (destination == -1) // Destination required for this command. + response.SetInteger(kResultWide, RESULT_UNKNOWN_COMMAND); + else + DisconnectCommand(destination, &response); + } else if (command == kPostMessage) { + if (destination == -1) // Destination required for this command. + response.SetInteger(kResultWide, RESULT_UNKNOWN_COMMAND); + else + PostMessageCommand(destination, content, &response); + } else { + // Unknown command + NOTREACHED(); + response.SetInteger(kResultWide, RESULT_UNKNOWN_COMMAND); + } + SendResponse(response, message.tool(), message.destination()); +} + +void ExtensionPortsRemoteService::OnConnectionLost() { + LOG(INFO) << "OnConnectionLost"; + DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); + DCHECK(service_); + for (PortIdSet::iterator it = openPortIds_.begin(); + it != openPortIds_.end(); + ++it) + service_->CloseChannel(*it); + openPortIds_.clear(); +} + +void ExtensionPortsRemoteService::SendResponse( + const Value& response, const std::string& tool, + const std::string& destination) { + std::string response_content; + JSONWriter::Write(&response, false, &response_content); + scoped_ptr<DevToolsRemoteMessage> response_message( + DevToolsRemoteMessageBuilder::instance().Create( + tool, destination, response_content)); + delegate_->Send(*response_message.get()); +} + +bool ExtensionPortsRemoteService::Send(IPC::Message *message) { + DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); + + IPC_BEGIN_MESSAGE_MAP(ExtensionPortsRemoteService, *message) + IPC_MESSAGE_HANDLER(ViewMsg_ExtensionMessageInvoke, + OnExtensionMessageInvoke) + IPC_MESSAGE_UNHANDLED_ERROR() + IPC_END_MESSAGE_MAP() + + delete message; + return true; +} + +void ExtensionPortsRemoteService::OnExtensionMessageInvoke( + const std::string& function_name, const ListValue& args) { + if (function_name == ExtensionMessageService::kDispatchOnMessage) { + DCHECK_EQ(args.GetSize(), 2u); + std::string message; + int port_id; + if (args.GetString(0, &message) && args.GetInteger(1, &port_id)) + OnExtensionMessage(message, port_id); + } else if (function_name == ExtensionMessageService::kDispatchOnDisconnect) { + DCHECK_EQ(args.GetSize(), 1u); + int port_id; + if (args.GetInteger(0, &port_id)) + OnExtensionPortDisconnected(port_id); + } else if (function_name == ExtensionMessageService::kDispatchOnConnect) { + // There is no way for this service to be addressed and receive + // connections. + NOTREACHED() << function_name << " shouldn't be called."; + } else { + NOTREACHED() << function_name << " shouldn't be called."; + } +} + +void ExtensionPortsRemoteService::OnExtensionMessage( + const std::string& message, int port_id) { + LOG(INFO) << "Message event: from port " << port_id + << ", < " << message << ">"; + // Transpose the information into a JSON message for the external client. + DictionaryValue content; + content.SetString(kCommandWide, kOnMessage); + content.SetInteger(kResultWide, RESULT_OK); + // Turn the stringified message body back into JSON. + Value* data = JSONReader::Read(message, false); + if (!data) { + NOTREACHED(); + return; + } + content.Set(kDataWide, data); + SendResponse(content, kToolName, IntToString(port_id)); +} + +void ExtensionPortsRemoteService::OnExtensionPortDisconnected(int port_id) { + LOG(INFO) << "Disconnect event for port " << port_id; + openPortIds_.erase(port_id); + DictionaryValue content; + content.SetString(kCommandWide, kOnDisconnect); + content.SetInteger(kResultWide, RESULT_OK); + SendResponse(content, kToolName, IntToString(port_id)); +} + +void ExtensionPortsRemoteService::ConnectCommand( + DictionaryValue* content, DictionaryValue* response) { + // Parse out the parameters. + DictionaryValue* data; + if (!content->GetDictionary(kDataWide, &data)) { + response->SetInteger(kResultWide, RESULT_PARAMETER_ERROR); + return; + } + std::string extension_id; + if (!data->GetString(kExtensionIdWide, &extension_id)) { + response->SetInteger(kResultWide, RESULT_PARAMETER_ERROR); + return; + } + std::string channel_name = ""; + data->GetString(kChannelNameWide, &channel_name); // optional. + int tab_id = -1; + data->GetInteger(kTabIdWide, &tab_id); // optional. + int port_id; + if (tab_id != -1) { // Resolve the tab ID. + const InspectableTabProxy::ControllersMap& navcon_map = + delegate_->inspectable_tab_proxy()->controllers_map(); + InspectableTabProxy::ControllersMap::const_iterator it = + navcon_map.find(tab_id); + TabContents* tab_contents = NULL; + if (it != navcon_map.end()) + tab_contents = it->second->tab_contents(); + if (!tab_contents) { + LOG(INFO) << "tab not found: " << tab_id; + response->SetInteger(kResultWide, RESULT_TAB_NOT_FOUND); + return; + } + // Ask the ExtensionMessageService to open the channel. + LOG(INFO) << "Connect: extension_id <" << extension_id + << ">, channel_name <" << channel_name << ">" + << ", tab " << tab_id; + DCHECK(service_); + port_id = service_->OpenSpecialChannelToTab( + extension_id, channel_name, tab_contents, this); + } else { // no tab: channel to an extension' background page / toolstrip. + // Ask the ExtensionMessageService to open the channel. + LOG(INFO) << "Connect: extension_id <" << extension_id + << ">, channel_name <" << channel_name << ">"; + DCHECK(service_); + port_id = service_->OpenSpecialChannelToExtension( + extension_id, channel_name, this); + } + if (port_id == -1) { + // Failure: probably the extension ID doesn't exist. + LOG(INFO) << "Connect failed"; + response->SetInteger(kResultWide, RESULT_CONNECT_FAILED); + return; + } + LOG(INFO) << "Connected: port " << port_id; + openPortIds_.insert(port_id); + // Reply to external client with the port ID assigned to the new channel. + DictionaryValue* reply_data = new DictionaryValue(); + reply_data->SetInteger(kPortIdWide, port_id); + response->Set(kDataWide, reply_data); + response->SetInteger(kResultWide, RESULT_OK); +} + +void ExtensionPortsRemoteService::DisconnectCommand( + int port_id, DictionaryValue* response) { + LOG(INFO) << "Disconnect port " << port_id; + PortIdSet::iterator portEntry = openPortIds_.find(port_id); + if (portEntry == openPortIds_.end()) { // unknown port ID. + LOG(INFO) << "unknown port: " << port_id; + response->SetInteger(kResultWide, RESULT_UNKNOWN_PORT); + return; + } + DCHECK(service_); + service_->CloseChannel(port_id); + openPortIds_.erase(portEntry); + response->SetInteger(kResultWide, RESULT_OK); +} + +void ExtensionPortsRemoteService::PostMessageCommand( + int port_id, DictionaryValue* content, DictionaryValue* response) { + Value* data; + if (!content->Get(kDataWide, &data)) { + response->SetInteger(kResultWide, RESULT_PARAMETER_ERROR); + return; + } + std::string message; + // Stringified the JSON message body. + JSONWriter::Write(data, false, &message); + LOG(INFO) << "postMessage: port " << port_id + << ", message: <" << message << ">"; + PortIdSet::iterator portEntry = openPortIds_.find(port_id); + if (portEntry == openPortIds_.end()) { // Unknown port ID. + LOG(INFO) << "unknown port: " << port_id; + response->SetInteger(kResultWide, RESULT_UNKNOWN_PORT); + return; + } + // Post the message through the ExtensionMessageService. + DCHECK(service_); + service_->PostMessageFromRenderer(port_id, message); + // Confirm to the external client that we sent its message. + response->SetInteger(kResultWide, RESULT_OK); +} diff --git a/chrome/browser/debugger/extension_ports_remote_service.h b/chrome/browser/debugger/extension_ports_remote_service.h new file mode 100644 index 0000000..1bf9a7a --- /dev/null +++ b/chrome/browser/debugger/extension_ports_remote_service.h @@ -0,0 +1,105 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// ExtensionsPorts service: wires extension message ports through the +// devtools remote protocol, allowing an external client program to +// exchange messages with Chrome extensions. + +#ifndef CHROME_BROWSER_DEBUGGER_EXTENSION_PORTS_REMOTE_SERVICE_H_ +#define CHROME_BROWSER_DEBUGGER_EXTENSION_PORTS_REMOTE_SERVICE_H_ + +#include <set> +#include <string> + +#include "base/basictypes.h" +#include "base/ref_counted.h" +#include "chrome/browser/debugger/devtools_remote.h" +#include "chrome/browser/extensions/extension_message_service.h" +#include "ipc/ipc_message.h" + +class DevToolsProtocolHandler; +class DevToolsRemoteMessage; +class DictionaryValue; +class ListValue; +class Value; + +class ExtensionPortsRemoteService : public DevToolsRemoteListener, + public IPC::Message::Sender { + public: + // Specifies a tool name ("ExtensionPorts") handled by this class. + static const std::string kToolName; + + // |delegate| (never NULL) is the protocol handler instance which + // dispatches messages to this service. + // The ownership of |delegate| is NOT transferred to this class. + explicit ExtensionPortsRemoteService(DevToolsProtocolHandler* delegate); + virtual ~ExtensionPortsRemoteService() {} + + // DevToolsRemoteListener methods: + + // Processes |message| from the external client (where the tool is + // "ExtensionPorts"). + virtual void HandleMessage(const DevToolsRemoteMessage& message); + + // Gets invoked on the external client socket connection loss. + // Closes open message ports. + virtual void OnConnectionLost(); + + // IPC::Message::Sender methods: + + // This is the callback through which the ExtensionMessageService + // passes us messages from extensions as well as disconnect events. + virtual bool Send(IPC::Message* msg); + + private: + // Operation result returned in the "result" field in messages sent + // to the external client. + typedef enum { + RESULT_OK = 0, + RESULT_UNKNOWN_COMMAND, + RESULT_NO_SERVICE, + RESULT_PARAMETER_ERROR, + RESULT_UNKNOWN_PORT, + RESULT_TAB_NOT_FOUND, + RESULT_CONNECT_FAILED, // probably extension ID not found. + } Result; + + // Sends a JSON message with the |response| to the external client. + // |tool| and |destination| are used as the respective header values. + void SendResponse(const Value& response, + const std::string& tool, + const std::string& destination); + + // Handles a message from the ExtensionMessageService. + void OnExtensionMessageInvoke( + const std::string& function_name, const ListValue& args); + // Handles a message sent from an extension through the + // ExtensionMessageService, to be passed to the external client. + void OnExtensionMessage(const std::string& message, int port_id); + // Handles a disconnect event sent from the ExtensionMessageService. + void OnExtensionPortDisconnected(int port_id); + + // Implementation for the commands we can receive from the external client. + // Opens a channel to an extension. + void ConnectCommand(DictionaryValue* content, DictionaryValue* response); + // Disconnects a message port. + void DisconnectCommand(int port_id, DictionaryValue* response); + // Sends a message to an extension through an established message port. + void PostMessageCommand(int port_id, DictionaryValue* content, + DictionaryValue* response); + + // The delegate is used to send responses and events back to the + // external client, and to resolve tab IDs. + DevToolsProtocolHandler* delegate_; + + // Set of message port IDs we successfully opened. + typedef std::set<int> PortIdSet; + PortIdSet openPortIds_; + + scoped_refptr<ExtensionMessageService> service_; + + DISALLOW_COPY_AND_ASSIGN(ExtensionPortsRemoteService); +}; + +#endif // CHROME_BROWSER_DEBUGGER_EXTENSION_PORTS_REMOTE_SERVICE_H_ diff --git a/chrome/browser/extensions/extension_message_service.cc b/chrome/browser/extensions/extension_message_service.cc index edc2cf9..3b7e1fa 100644 --- a/chrome/browser/extensions/extension_message_service.cc +++ b/chrome/browser/extensions/extension_message_service.cc @@ -240,9 +240,11 @@ void ExtensionMessageService::OpenChannelToExtensionOnUIThread( MessagePort receiver( profile_->GetExtensionProcessManager()->GetExtensionProcess(extension_id), MSG_ROUTING_CONTROL); - OpenChannelOnUIThreadImpl(source, source_process_id, source_routing_id, - receiver, receiver_port_id, extension_id, - channel_name); + TabContents* source_contents = tab_util::GetTabContentsByID( + source_process_id, source_routing_id); + OpenChannelOnUIThreadImpl(source, source_contents, + receiver, receiver_port_id, + extension_id, channel_name); } void ExtensionMessageService::OpenChannelToTabOnUIThread( @@ -257,13 +259,15 @@ void ExtensionMessageService::OpenChannelToTabOnUIThread( receiver.sender = contents->render_view_host(); receiver.routing_id = contents->render_view_host()->routing_id(); } - OpenChannelOnUIThreadImpl(source, source_process_id, source_routing_id, - receiver, receiver_port_id, extension_id, - channel_name); + TabContents* source_contents = tab_util::GetTabContentsByID( + source_process_id, source_routing_id); + OpenChannelOnUIThreadImpl(source, source_contents, + receiver, receiver_port_id, + extension_id, channel_name); } bool ExtensionMessageService::OpenChannelOnUIThreadImpl( - IPC::Message::Sender* source, int source_process_id, int source_routing_id, + IPC::Message::Sender* source, TabContents* source_contents, const MessagePort& receiver, int receiver_port_id, const std::string& extension_id, const std::string& channel_name) { DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); @@ -295,10 +299,9 @@ bool ExtensionMessageService::OpenChannelOnUIThreadImpl( // Include info about the opener's tab (if it was a tab). std::string tab_json = "null"; - TabContents* contents = tab_util::GetTabContentsByID(source_process_id, - source_routing_id); - if (contents) { - DictionaryValue* tab_value = ExtensionTabUtil::CreateTabValue(contents); + if (source_contents) { + DictionaryValue* tab_value = + ExtensionTabUtil::CreateTabValue(source_contents); JSONWriter::Write(tab_value, false, &tab_json); } @@ -312,9 +315,9 @@ bool ExtensionMessageService::OpenChannelOnUIThreadImpl( return true; } -int ExtensionMessageService::OpenAutomationChannelToExtension( - int source_process_id, int routing_id, const std::string& extension_id, - const std::string& channel_name, IPC::Message::Sender* source) { +int ExtensionMessageService::OpenSpecialChannelToExtension( + const std::string& extension_id, const std::string& channel_name, + IPC::Message::Sender* source) { DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); DCHECK(profile_); @@ -323,17 +326,34 @@ int ExtensionMessageService::OpenAutomationChannelToExtension( // Create a channel ID for both sides of the channel. AllocatePortIdPair(&port1_id, &port2_id); - // TODO(siggi): The source process- and routing ids are used to - // describe the originating tab to the target extension. - // This isn't really appropriate here, the originating tab - // information should be supplied by the caller for - // automation-initiated ports. MessagePort receiver( - profile_->GetExtensionProcessManager()->GetExtensionProcess(extension_id), + profile_->GetExtensionProcessManager()-> + GetExtensionProcess(extension_id), MSG_ROUTING_CONTROL); - if (!OpenChannelOnUIThreadImpl(source, source_process_id, routing_id, - receiver, port2_id, extension_id, - channel_name)) + if (!OpenChannelOnUIThreadImpl( + source, NULL, receiver, port2_id, extension_id, channel_name)) + return -1; + + return port1_id; +} + +int ExtensionMessageService::OpenSpecialChannelToTab( + const std::string& extension_id, const std::string& channel_name, + TabContents* target_tab_contents, IPC::Message::Sender* source) { + DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); + DCHECK(target_tab_contents); + + int port1_id = -1; + int port2_id = -1; + // Create a channel ID for both sides of the channel. + AllocatePortIdPair(&port1_id, &port2_id); + + MessagePort receiver( + target_tab_contents->render_view_host(), + target_tab_contents->render_view_host()->routing_id()); + if (!OpenChannelOnUIThreadImpl(source, NULL, + receiver, port2_id, + extension_id, channel_name)) return -1; return port1_id; diff --git a/chrome/browser/extensions/extension_message_service.h b/chrome/browser/extensions/extension_message_service.h index 32ed945..debef75 100644 --- a/chrome/browser/extensions/extension_message_service.h +++ b/chrome/browser/extensions/extension_message_service.h @@ -20,6 +20,7 @@ class MessageLoop; class Profile; class RenderProcessHost; class ResourceMessageFilter; +class TabContents; class URLRequestContext; // This class manages message and event passing between renderer processes. @@ -83,14 +84,27 @@ class ExtensionMessageService void DispatchEventToRenderers( const std::string& event_name, const std::string& event_args); - // Given an extension's ID, opens a channel between the given automation - // "port" and that extension. Returns a channel ID to be used for posting - // messages between the processes, or -1 if the extension doesn't exist. - int OpenAutomationChannelToExtension(int source_process_id, - int routing_id, - const std::string& extension_id, - const std::string& channel_name, - IPC::Message::Sender* source); + // Given an extension ID, opens a channel between the given + // automation "port" or DevTools service and that extension. the + // channel will be open to the extension process hosting the + // background page and tool strip. + // + // Returns a port ID to be used for posting messages between the + // processes, or -1 if the extension doesn't exist. + int OpenSpecialChannelToExtension( + const std::string& extension_id, const std::string& channel_name, + IPC::Message::Sender* source); + + // Given an extension ID, opens a channel between the given DevTools + // service and the content script for that extension running in the + // designated tab. + // + // Returns a port ID identifying the DevTools end of the channel, to + // be used for posting messages. May return -1 on failure, although + // the code doesn't detect whether the extension actually exists. + int OpenSpecialChannelToTab( + const std::string& extension_id, const std::string& channel_name, + TabContents* target_tab_contents, IPC::Message::Sender* source); // --- IO thread only: @@ -138,11 +152,11 @@ class ExtensionMessageService int tab_id, const std::string& extension_id, const std::string& channel_name); - // Common between OpenChannelOnUIThread and OpenAutomationChannelToExtension. + // Common between OpenChannelOnUIThread and OpenSpecialChannelToExtension. bool OpenChannelOnUIThreadImpl( - IPC::Message::Sender* source, int source_process_id, int source_routing_id, - const MessagePort& receiver, int receiver_port_id, - const std::string& extension_id, const std::string& channel_name); + IPC::Message::Sender* source, TabContents* source_contents, + const MessagePort& receiver, int receiver_port_id, + const std::string& extension_id, const std::string& channel_name); // NotificationObserver interface. void Observe(NotificationType type, diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index f84eb1a..162cce0 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -2602,6 +2602,8 @@ 'browser/debugger/devtools_remote_service.h', 'browser/debugger/devtools_window.cc', 'browser/debugger/devtools_window.h', + 'browser/debugger/extension_ports_remote_service.cc', + 'browser/debugger/extension_ports_remote_service.h', 'browser/debugger/inspectable_tab_proxy.cc', 'browser/debugger/inspectable_tab_proxy.h', ], |