1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
// Copyright (c) 2012 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.
#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_MESSAGE_SERVICE_H_
#define CHROME_BROWSER_EXTENSIONS_EXTENSION_MESSAGE_SERVICE_H_
#pragma once
#include <map>
#include <set>
#include <string>
#include "base/compiler_specific.h"
#include "base/memory/linked_ptr.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
class ExtensionHost;
class LazyBackgroundTaskQueue;
class Profile;
namespace content {
class RenderProcessHost;
class WebContents;
}
// This class manages message and event passing between renderer processes.
// It maintains a list of processes that are listening to events and a set of
// open channels.
//
// Messaging works this way:
// - An extension-owned script context (like a background page or a content
// script) adds an event listener to the "onConnect" event.
// - Another context calls "extension.connect()" to open a channel to the
// extension process, or an extension context calls "tabs.connect(tabId)" to
// open a channel to the content scripts for the given tab. The EMS notifies
// the target process/tab, which then calls the onConnect event in every
// context owned by the connecting extension in that process/tab.
// - Once the channel is established, either side can call postMessage to send
// a message to the opposite side of the channel, which may have multiple
// listeners.
//
// Terminology:
// channel: connection between two ports
// port: an IPC::Message::Process interface and an optional routing_id (in the
// case that the port is a tab). The Process is usually either a
// RenderProcessHost or a RenderViewHost.
class ExtensionMessageService : public content::NotificationObserver {
public:
// A messaging channel. Note that the opening port can be the same as the
// receiver, if an extension background page wants to talk to its tab (for
// example).
struct MessageChannel;
struct MessagePort;
// Javascript function name constants.
static const char kDispatchOnConnect[];
static const char kDispatchOnDisconnect[];
// Allocates a pair of port ids.
// NOTE: this can be called from any thread.
static void AllocatePortIdPair(int* port1, int* port2);
explicit ExtensionMessageService(LazyBackgroundTaskQueue* queue);
virtual ~ExtensionMessageService();
// Given an extension's ID, opens a channel between the given renderer "port"
// and every listening context owned by that extension. |channel_name| is
// an optional identifier for use by extension developers.
void OpenChannelToExtension(
int source_process_id, int source_routing_id, int receiver_port_id,
const std::string& source_extension_id,
const std::string& target_extension_id,
const std::string& channel_name);
// Same as above, but opens a channel to the tab with the given ID. Messages
// are restricted to that tab, so if there are multiple tabs in that process,
// only the targeted tab will receive messages.
void OpenChannelToTab(
int source_process_id, int source_routing_id, int receiver_port_id,
int tab_id, const std::string& extension_id,
const std::string& channel_name);
// Closes the message channel associated with the given port, and notifies
// the other side.
void CloseChannel(int port_id);
// Sends a message from a renderer to the given port.
void PostMessageFromRenderer(int port_id, const std::string& message);
private:
friend class MockExtensionMessageService;
struct OpenChannelParams;
// A map of channel ID to its channel object.
typedef std::map<int, MessageChannel*> MessageChannelMap;
// A map of channel ID to information about the extension that is waiting
// for that channel to open. Used for lazy background pages.
typedef std::string ExtensionID;
typedef std::pair<Profile*, ExtensionID> PendingChannel;
typedef std::map<int, PendingChannel> PendingChannelMap;
// Common among OpenChannel* variants.
bool OpenChannelImpl(const OpenChannelParams& params);
void CloseChannelImpl(MessageChannelMap::iterator channel_iter,
int port_id,
bool notify_other_port);
// content::NotificationObserver interface.
virtual void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) OVERRIDE;
// A process that might be in our list of channels has closed.
void OnProcessClosed(content::RenderProcessHost* process);
// Potentially registers a pending task with the LazyBackgroundTaskQueue
// to open a channel. Returns true if a task was queued.
bool MaybeAddPendingOpenChannelTask(Profile* profile,
const OpenChannelParams& params);
// Callbacks for LazyBackgroundTaskQueue tasks. The queue passes in an
// ExtensionHost to its task callbacks, though some of our callbacks don't
// use that argument.
void PendingOpenChannel(const OpenChannelParams& params,
int source_process_id,
ExtensionHost* host);
void PendingCloseChannel(int port_id, ExtensionHost*) {
CloseChannel(port_id);
}
void PendingPostMessage(int port_id,
const std::string& message,
ExtensionHost*) {
PostMessageFromRenderer(port_id, message);
}
content::NotificationRegistrar registrar_;
MessageChannelMap channels_;
PendingChannelMap pending_channels_;
// Weak pointer. Guaranteed to outlive this class.
LazyBackgroundTaskQueue* lazy_background_task_queue_;
DISALLOW_COPY_AND_ASSIGN(ExtensionMessageService);
};
#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_MESSAGE_SERVICE_H_
|