Home | History | Annotate | Download | only in messaging
      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