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 #ifndef CHROME_BROWSER_EXTENSIONS_API_MESSAGING_MESSAGE_SERVICE_H_ 6 #define CHROME_BROWSER_EXTENSIONS_API_MESSAGING_MESSAGE_SERVICE_H_ 7 8 #include <map> 9 #include <set> 10 #include <string> 11 12 #include "base/compiler_specific.h" 13 #include "base/memory/scoped_ptr.h" 14 #include "base/memory/weak_ptr.h" 15 #include "chrome/browser/extensions/api/messaging/native_message_process_host.h" 16 #include "chrome/browser/extensions/api/profile_keyed_api_factory.h" 17 #include "content/public/browser/notification_observer.h" 18 #include "content/public/browser/notification_registrar.h" 19 20 class GURL; 21 class Profile; 22 23 namespace base { 24 class DictionaryValue; 25 } 26 27 namespace content { 28 class RenderProcessHost; 29 class WebContents; 30 } 31 32 namespace extensions { 33 class Extension; 34 class ExtensionHost; 35 class LazyBackgroundTaskQueue; 36 37 // This class manages message and event passing between renderer processes. 38 // It maintains a list of processes that are listening to events and a set of 39 // open channels. 40 // 41 // Messaging works this way: 42 // - An extension-owned script context (like a background page or a content 43 // script) adds an event listener to the "onConnect" event. 44 // - Another context calls "runtime.connect()" to open a channel to the 45 // extension process, or an extension context calls "tabs.connect(tabId)" to 46 // open a channel to the content scripts for the given tab. The EMS notifies 47 // the target process/tab, which then calls the onConnect event in every 48 // context owned by the connecting extension in that process/tab. 49 // - Once the channel is established, either side can call postMessage to send 50 // a message to the opposite side of the channel, which may have multiple 51 // listeners. 52 // 53 // Terminology: 54 // channel: connection between two ports 55 // port: an IPC::Message::Process interface and an optional routing_id (in the 56 // case that the port is a tab). The Process is usually either a 57 // RenderProcessHost or a RenderViewHost. 58 class MessageService : public ProfileKeyedAPI, 59 public content::NotificationObserver, 60 public NativeMessageProcessHost::Client { 61 public: 62 // A messaging channel. Note that the opening port can be the same as the 63 // receiver, if an extension background page wants to talk to its tab (for 64 // example). 65 struct MessageChannel; 66 67 // One side of the communication handled by extensions::MessageService. 68 class MessagePort { 69 public: 70 virtual ~MessagePort() {} 71 // Notify the port that the channel has been opened. 72 virtual void DispatchOnConnect(int dest_port_id, 73 const std::string& channel_name, 74 const base::DictionaryValue& source_tab, 75 const std::string& source_extension_id, 76 const std::string& target_extension_id, 77 const GURL& source_url) {} 78 79 // Notify the port that the channel has been closed. If |error_message| is 80 // non-empty, it indicates an error occurred while opening the connection. 81 virtual void DispatchOnDisconnect(int source_port_id, 82 const std::string& error_message) {} 83 84 // Dispatch a message to this end of the communication. 85 virtual void DispatchOnMessage(const std::string& message, 86 int target_port_id) = 0; 87 88 // MessagPorts that target extensions will need to adjust their keepalive 89 // counts for their lazy background page. 90 virtual void IncrementLazyKeepaliveCount() {} 91 virtual void DecrementLazyKeepaliveCount() {} 92 93 // Get the RenderProcessHost (if any) associated with the port. 94 virtual content::RenderProcessHost* GetRenderProcessHost(); 95 96 protected: 97 MessagePort() {} 98 99 private: 100 DISALLOW_COPY_AND_ASSIGN(MessagePort); 101 }; 102 103 // Allocates a pair of port ids. 104 // NOTE: this can be called from any thread. 105 static void AllocatePortIdPair(int* port1, int* port2); 106 107 explicit MessageService(Profile* profile); 108 virtual ~MessageService(); 109 110 // ProfileKeyedAPI implementation. 111 static ProfileKeyedAPIFactory<MessageService>* GetFactoryInstance(); 112 113 // Convenience method to get the MessageService for a profile. 114 static MessageService* Get(Profile* profile); 115 116 // Given an extension's ID, opens a channel between the given renderer "port" 117 // and every listening context owned by that extension. |channel_name| is 118 // an optional identifier for use by extension developers. 119 void OpenChannelToExtension( 120 int source_process_id, int source_routing_id, int receiver_port_id, 121 const std::string& source_extension_id, 122 const std::string& target_extension_id, 123 const GURL& source_url, 124 const std::string& channel_name); 125 126 // Same as above, but opens a channel to the tab with the given ID. Messages 127 // are restricted to that tab, so if there are multiple tabs in that process, 128 // only the targeted tab will receive messages. 129 void OpenChannelToTab( 130 int source_process_id, int source_routing_id, int receiver_port_id, 131 int tab_id, const std::string& extension_id, 132 const std::string& channel_name); 133 134 void OpenChannelToNativeApp( 135 int source_process_id, 136 int source_routing_id, 137 int receiver_port_id, 138 const std::string& source_extension_id, 139 const std::string& native_app_name); 140 141 // Closes the message channel associated with the given port, and notifies 142 // the other side. 143 virtual void CloseChannel(int port_id, 144 const std::string& error_message) OVERRIDE; 145 146 // Sends a message to the given port. 147 void PostMessage(int port_id, const std::string& message); 148 149 // NativeMessageProcessHost::Client 150 virtual void PostMessageFromNativeProcess( 151 int port_id, 152 const std::string& message) OVERRIDE; 153 154 private: 155 friend class MockMessageService; 156 friend class ProfileKeyedAPIFactory<MessageService>; 157 struct OpenChannelParams; 158 159 // A map of channel ID to its channel object. 160 typedef std::map<int, MessageChannel*> MessageChannelMap; 161 162 // A map of channel ID to information about the extension that is waiting 163 // for that channel to open. Used for lazy background pages. 164 typedef std::string ExtensionID; 165 typedef std::pair<Profile*, ExtensionID> PendingChannel; 166 typedef std::map<int, PendingChannel> PendingChannelMap; 167 168 // Common among OpenChannel* variants. 169 bool OpenChannelImpl(scoped_ptr<OpenChannelParams> params); 170 171 void CloseChannelImpl(MessageChannelMap::iterator channel_iter, 172 int port_id, 173 const std::string& error_message, 174 bool notify_other_port); 175 176 // Have MessageService take ownership of |channel|, and remove any pending 177 // channels with the same id. 178 void AddChannel(MessageChannel* channel, int receiver_port_id); 179 180 // content::NotificationObserver interface. 181 virtual void Observe(int type, 182 const content::NotificationSource& source, 183 const content::NotificationDetails& details) OVERRIDE; 184 185 // A process that might be in our list of channels has closed. 186 void OnProcessClosed(content::RenderProcessHost* process); 187 188 // Potentially registers a pending task with the LazyBackgroundTaskQueue 189 // to open a channel. Returns true if a task was queued. 190 // Takes ownership of |params| if true is returned. 191 bool MaybeAddPendingOpenChannelTask(Profile* profile, 192 const Extension* extension, 193 OpenChannelParams* params); 194 195 // Callbacks for LazyBackgroundTaskQueue tasks. The queue passes in an 196 // ExtensionHost to its task callbacks, though some of our callbacks don't 197 // use that argument. 198 void PendingOpenChannel(scoped_ptr<OpenChannelParams> params, 199 int source_process_id, 200 extensions::ExtensionHost* host); 201 void PendingCloseChannel(int port_id, 202 const std::string& error_message, 203 extensions::ExtensionHost* host) { 204 if (host) 205 CloseChannel(port_id, error_message); 206 } 207 void PendingPostMessage(int port_id, 208 const std::string& message, 209 extensions::ExtensionHost* host) { 210 if (host) 211 PostMessage(port_id, message); 212 } 213 214 // Immediate dispatches a disconnect to |source| for |port_id|. Sets source's 215 // runtime.lastMessage to |error_message|, if any. 216 void DispatchOnDisconnect(content::RenderProcessHost* source, 217 int port_id, 218 const std::string& error_message); 219 220 // ProfileKeyedAPI implementation. 221 static const char* service_name() { 222 return "MessageService"; 223 } 224 static const bool kServiceRedirectedInIncognito = true; 225 static const bool kServiceIsCreatedWithBrowserContext = false; 226 static const bool kServiceIsNULLWhileTesting = true; 227 228 content::NotificationRegistrar registrar_; 229 MessageChannelMap channels_; 230 PendingChannelMap pending_channels_; 231 232 // Weak pointer. Guaranteed to outlive this class. 233 LazyBackgroundTaskQueue* lazy_background_task_queue_; 234 235 base::WeakPtrFactory<MessageService> weak_factory_; 236 237 DISALLOW_COPY_AND_ASSIGN(MessageService); 238 }; 239 240 } // namespace extensions 241 242 #endif // CHROME_BROWSER_EXTENSIONS_API_MESSAGING_MESSAGE_SERVICE_H_ 243