Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(50)

Side by Side Diff: chrome/browser/extensions/api/messaging/message_service.cc

Issue 10991044: Revert 158830 - Revert 156678 - Native messaging now uses the MessageService back-end. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/api/messaging/message_service.h" 5 #include "chrome/browser/extensions/api/messaging/message_service.h"
6 6
7 #include "base/atomic_sequence_num.h" 7 #include "base/atomic_sequence_num.h"
8 #include "base/bind.h" 8 #include "base/bind.h"
9 #include "base/callback.h" 9 #include "base/callback.h"
10 #include "base/json/json_writer.h" 10 #include "base/json/json_writer.h"
11 #include "base/stl_util.h" 11 #include "base/stl_util.h"
12 #include "base/values.h" 12 #include "base/values.h"
13 #include "chrome/browser/extensions/api/messaging/extension_message_port.h"
14 #include "chrome/browser/extensions/api/messaging/native_message_port.h"
13 #include "chrome/browser/extensions/extension_host.h" 15 #include "chrome/browser/extensions/extension_host.h"
14 #include "chrome/browser/extensions/extension_process_manager.h" 16 #include "chrome/browser/extensions/extension_process_manager.h"
15 #include "chrome/browser/extensions/extension_service.h" 17 #include "chrome/browser/extensions/extension_service.h"
16 #include "chrome/browser/extensions/extension_system.h" 18 #include "chrome/browser/extensions/extension_system.h"
17 #include "chrome/browser/extensions/extension_tab_util.h" 19 #include "chrome/browser/extensions/extension_tab_util.h"
18 #include "chrome/browser/extensions/lazy_background_task_queue.h" 20 #include "chrome/browser/extensions/lazy_background_task_queue.h"
19 #include "chrome/browser/extensions/process_map.h" 21 #include "chrome/browser/extensions/process_map.h"
20 #include "chrome/browser/profiles/profile.h" 22 #include "chrome/browser/profiles/profile.h"
21 #include "chrome/browser/tab_contents/tab_util.h" 23 #include "chrome/browser/tab_contents/tab_util.h"
22 #include "chrome/browser/ui/tab_contents/tab_contents.h" 24 #include "chrome/browser/ui/tab_contents/tab_contents.h"
23 #include "chrome/common/chrome_notification_types.h" 25 #include "chrome/common/chrome_notification_types.h"
24 #include "chrome/common/extensions/extension.h" 26 #include "chrome/common/extensions/extension.h"
25 #include "chrome/common/extensions/extension_messages.h" 27 #include "chrome/common/extensions/extension_messages.h"
26 #include "chrome/common/view_type.h" 28 #include "chrome/common/view_type.h"
29 #include "content/public/browser/browser_thread.h"
27 #include "content/public/browser/notification_service.h" 30 #include "content/public/browser/notification_service.h"
28 #include "content/public/browser/render_process_host.h" 31 #include "content/public/browser/render_process_host.h"
29 #include "content/public/browser/render_view_host.h" 32 #include "content/public/browser/render_view_host.h"
30 #include "content/public/browser/site_instance.h" 33 #include "content/public/browser/site_instance.h"
31 #include "content/public/browser/web_contents.h" 34 #include "content/public/browser/web_contents.h"
32 35
33 using content::SiteInstance; 36 using content::SiteInstance;
34 using content::WebContents; 37 using content::WebContents;
35 38
36 // Since we have 2 ports for every channel, we just index channels by half the 39 // Since we have 2 ports for every channel, we just index channels by half the
37 // port ID. 40 // port ID.
38 #define GET_CHANNEL_ID(port_id) ((port_id) / 2) 41 #define GET_CHANNEL_ID(port_id) ((port_id) / 2)
39 #define GET_CHANNEL_OPENER_ID(channel_id) ((channel_id) * 2) 42 #define GET_CHANNEL_OPENER_ID(channel_id) ((channel_id) * 2)
40 #define GET_CHANNEL_RECEIVERS_ID(channel_id) ((channel_id) * 2 + 1) 43 #define GET_CHANNEL_RECEIVERS_ID(channel_id) ((channel_id) * 2 + 1)
41 44
42 // Port1 is always even, port2 is always odd. 45 // Port1 is always even, port2 is always odd.
43 #define IS_OPENER_PORT_ID(port_id) (((port_id) & 1) == 0) 46 #define IS_OPENER_PORT_ID(port_id) (((port_id) & 1) == 0)
44 47
45 // Change even to odd and vice versa, to get the other side of a given channel. 48 // Change even to odd and vice versa, to get the other side of a given channel.
46 #define GET_OPPOSITE_PORT_ID(source_port_id) ((source_port_id) ^ 1) 49 #define GET_OPPOSITE_PORT_ID(source_port_id) ((source_port_id) ^ 1)
47 50
48 namespace extensions { 51 namespace extensions {
49 52
50 struct MessageService::MessagePort {
51 content::RenderProcessHost* process;
52 int routing_id;
53 std::string extension_id;
54 void* background_host_ptr; // used in IncrementLazyKeepaliveCount
55
56 MessagePort()
57 : process(NULL),
58 routing_id(MSG_ROUTING_CONTROL),
59 background_host_ptr(NULL) {}
60 MessagePort(content::RenderProcessHost* process,
61 int routing_id,
62 const std::string& extension_id)
63 : process(process),
64 routing_id(routing_id),
65 extension_id(extension_id),
66 background_host_ptr(NULL) {}
67 };
68
69 struct MessageService::MessageChannel { 53 struct MessageService::MessageChannel {
70 MessageService::MessagePort opener; 54 scoped_ptr<MessagePort> opener;
71 MessageService::MessagePort receiver; 55 scoped_ptr<MessagePort> receiver;
72 }; 56 };
73 57
74 struct MessageService::OpenChannelParams { 58 struct MessageService::OpenChannelParams {
75 content::RenderProcessHost* source; 59 content::RenderProcessHost* source;
76 std::string tab_json; 60 std::string tab_json;
77 MessagePort receiver; 61 scoped_ptr<MessagePort> receiver;
78 int receiver_port_id; 62 int receiver_port_id;
79 std::string source_extension_id; 63 std::string source_extension_id;
80 std::string target_extension_id; 64 std::string target_extension_id;
81 std::string channel_name; 65 std::string channel_name;
82 66
67 // Takes ownership of receiver.
83 OpenChannelParams(content::RenderProcessHost* source, 68 OpenChannelParams(content::RenderProcessHost* source,
84 const std::string& tab_json, 69 const std::string& tab_json,
85 const MessagePort& receiver, 70 MessagePort* receiver,
86 int receiver_port_id, 71 int receiver_port_id,
87 const std::string& source_extension_id, 72 const std::string& source_extension_id,
88 const std::string& target_extension_id, 73 const std::string& target_extension_id,
89 const std::string& channel_name) 74 const std::string& channel_name)
90 : source(source), 75 : source(source),
91 tab_json(tab_json), 76 tab_json(tab_json),
92 receiver(receiver), 77 receiver(receiver),
93 receiver_port_id(receiver_port_id), 78 receiver_port_id(receiver_port_id),
94 source_extension_id(source_extension_id), 79 source_extension_id(source_extension_id),
95 target_extension_id(target_extension_id), 80 target_extension_id(target_extension_id),
96 channel_name(channel_name) {} 81 channel_name(channel_name) {}
97 }; 82 };
98 83
99 namespace { 84 namespace {
100 85
101 static base::StaticAtomicSequenceNumber g_next_channel_id; 86 static base::StaticAtomicSequenceNumber g_next_channel_id;
102 87
103 static void DispatchOnConnect(const MessageService::MessagePort& port,
104 int dest_port_id,
105 const std::string& channel_name,
106 const std::string& tab_json,
107 const std::string& source_extension_id,
108 const std::string& target_extension_id) {
109 port.process->Send(new ExtensionMsg_DispatchOnConnect(
110 port.routing_id, dest_port_id, channel_name,
111 tab_json, source_extension_id, target_extension_id));
112 }
113
114 static void DispatchOnDisconnect(const MessageService::MessagePort& port,
115 int source_port_id,
116 bool connection_error) {
117 port.process->Send(new ExtensionMsg_DispatchOnDisconnect(
118 port.routing_id, source_port_id, connection_error));
119 }
120
121 static void DispatchOnMessage(const MessageService::MessagePort& port,
122 const std::string& message,
123 int target_port_id) {
124 port.process->Send(new ExtensionMsg_DeliverMessage(
125 port.routing_id, target_port_id, message));
126 }
127
128 static content::RenderProcessHost* GetExtensionProcess( 88 static content::RenderProcessHost* GetExtensionProcess(
129 Profile* profile, const std::string& extension_id) { 89 Profile* profile, const std::string& extension_id) {
130 SiteInstance* site_instance = 90 SiteInstance* site_instance =
131 profile->GetExtensionProcessManager()->GetSiteInstanceForURL( 91 profile->GetExtensionProcessManager()->GetSiteInstanceForURL(
132 Extension::GetBaseURLFromExtensionId(extension_id)); 92 Extension::GetBaseURLFromExtensionId(extension_id));
133 93
134 if (!site_instance->HasProcess()) 94 if (!site_instance->HasProcess())
135 return NULL; 95 return NULL;
136 96
137 return site_instance->GetProcess(); 97 return site_instance->GetProcess();
138 } 98 }
139 99
140 static void IncrementLazyKeepaliveCount(MessageService::MessagePort* port) {
141 Profile* profile =
142 Profile::FromBrowserContext(port->process->GetBrowserContext());
143 ExtensionProcessManager* pm =
144 ExtensionSystem::Get(profile)->process_manager();
145 ExtensionHost* host = pm->GetBackgroundHostForExtension(port->extension_id);
146 if (host && host->extension()->has_lazy_background_page())
147 pm->IncrementLazyKeepaliveCount(host->extension());
148
149 // Keep track of the background host, so when we decrement, we only do so if
150 // the host hasn't reloaded.
151 port->background_host_ptr = host;
152 }
153
154 static void DecrementLazyKeepaliveCount(MessageService::MessagePort* port) {
155 Profile* profile =
156 Profile::FromBrowserContext(port->process->GetBrowserContext());
157 ExtensionProcessManager* pm =
158 ExtensionSystem::Get(profile)->process_manager();
159 ExtensionHost* host = pm->GetBackgroundHostForExtension(port->extension_id);
160 if (host && host == port->background_host_ptr)
161 pm->DecrementLazyKeepaliveCount(host->extension());
162 }
163
164 } // namespace 100 } // namespace
165 101
102 content::RenderProcessHost*
103 MessageService::MessagePort::GetRenderProcessHost() {
104 return NULL;
105 }
106
166 // static 107 // static
167 void MessageService::AllocatePortIdPair(int* port1, int* port2) { 108 void MessageService::AllocatePortIdPair(int* port1, int* port2) {
168 int channel_id = g_next_channel_id.GetNext(); 109 int channel_id = g_next_channel_id.GetNext();
169 int port1_id = channel_id * 2; 110 int port1_id = channel_id * 2;
170 int port2_id = channel_id * 2 + 1; 111 int port2_id = channel_id * 2 + 1;
171 112
172 // Sanity checks to make sure our channel<->port converters are correct. 113 // Sanity checks to make sure our channel<->port converters are correct.
173 DCHECK(IS_OPENER_PORT_ID(port1_id)); 114 DCHECK(IS_OPENER_PORT_ID(port1_id));
174 DCHECK(GET_OPPOSITE_PORT_ID(port1_id) == port2_id); 115 DCHECK(GET_OPPOSITE_PORT_ID(port1_id) == port2_id);
175 DCHECK(GET_OPPOSITE_PORT_ID(port2_id) == port1_id); 116 DCHECK(GET_OPPOSITE_PORT_ID(port2_id) == port1_id);
176 DCHECK(GET_CHANNEL_ID(port1_id) == GET_CHANNEL_ID(port2_id)); 117 DCHECK(GET_CHANNEL_ID(port1_id) == GET_CHANNEL_ID(port2_id));
177 DCHECK(GET_CHANNEL_ID(port1_id) == channel_id); 118 DCHECK(GET_CHANNEL_ID(port1_id) == channel_id);
178 DCHECK(GET_CHANNEL_OPENER_ID(channel_id) == port1_id); 119 DCHECK(GET_CHANNEL_OPENER_ID(channel_id) == port1_id);
179 DCHECK(GET_CHANNEL_RECEIVERS_ID(channel_id) == port2_id); 120 DCHECK(GET_CHANNEL_RECEIVERS_ID(channel_id) == port2_id);
180 121
181 *port1 = port1_id; 122 *port1 = port1_id;
182 *port2 = port2_id; 123 *port2 = port2_id;
183 } 124 }
184 125
185 MessageService::MessageService( 126 MessageService::MessageService(
186 LazyBackgroundTaskQueue* queue) 127 LazyBackgroundTaskQueue* queue)
187 : lazy_background_task_queue_(queue) { 128 : lazy_background_task_queue_(queue),
129 weak_factory_(this) {
188 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, 130 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
189 content::NotificationService::AllBrowserContextsAndSources()); 131 content::NotificationService::AllBrowserContextsAndSources());
190 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, 132 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
191 content::NotificationService::AllBrowserContextsAndSources()); 133 content::NotificationService::AllBrowserContextsAndSources());
192 } 134 }
193 135
194 MessageService::~MessageService() { 136 MessageService::~MessageService() {
195 STLDeleteContainerPairSecondPointers(channels_.begin(), channels_.end()); 137 STLDeleteContainerPairSecondPointers(channels_.begin(), channels_.end());
196 channels_.clear(); 138 channels_.clear();
197 } 139 }
198 140
199 void MessageService::OpenChannelToExtension( 141 void MessageService::OpenChannelToExtension(
200 int source_process_id, int source_routing_id, int receiver_port_id, 142 int source_process_id, int source_routing_id, int receiver_port_id,
201 const std::string& source_extension_id, 143 const std::string& source_extension_id,
202 const std::string& target_extension_id, 144 const std::string& target_extension_id,
203 const std::string& channel_name) { 145 const std::string& channel_name) {
204 content::RenderProcessHost* source = 146 content::RenderProcessHost* source =
205 content::RenderProcessHost::FromID(source_process_id); 147 content::RenderProcessHost::FromID(source_process_id);
206 if (!source) 148 if (!source)
207 return; 149 return;
208 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext()); 150 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
209 151
210 // Note: we use the source's profile here. If the source is an incognito 152 // Note: we use the source's profile here. If the source is an incognito
211 // process, we will use the incognito EPM to find the right extension process, 153 // process, we will use the incognito EPM to find the right extension process,
212 // which depends on whether the extension uses spanning or split mode. 154 // which depends on whether the extension uses spanning or split mode.
213 MessagePort receiver(GetExtensionProcess(profile, target_extension_id), 155 MessagePort* receiver = new ExtensionMessagePort(
214 MSG_ROUTING_CONTROL, 156 GetExtensionProcess(profile, target_extension_id), MSG_ROUTING_CONTROL,
215 target_extension_id); 157 target_extension_id);
216 WebContents* source_contents = tab_util::GetWebContentsByID( 158 WebContents* source_contents = tab_util::GetWebContentsByID(
217 source_process_id, source_routing_id); 159 source_process_id, source_routing_id);
218 160
219 // Include info about the opener's tab (if it was a tab). 161 // Include info about the opener's tab (if it was a tab).
220 std::string tab_json = "null"; 162 std::string tab_json = "null";
221 if (source_contents) { 163 if (source_contents) {
222 scoped_ptr<DictionaryValue> tab_value(ExtensionTabUtil::CreateTabValue( 164 scoped_ptr<DictionaryValue> tab_value(ExtensionTabUtil::CreateTabValue(
223 source_contents, ExtensionTabUtil::INCLUDE_PRIVACY_SENSITIVE_FIELDS)); 165 source_contents, ExtensionTabUtil::INCLUDE_PRIVACY_SENSITIVE_FIELDS));
224 base::JSONWriter::Write(tab_value.get(), &tab_json); 166 base::JSONWriter::Write(tab_value.get(), &tab_json);
225 } 167 }
226 168
227 OpenChannelParams params(source, tab_json, receiver, receiver_port_id, 169 OpenChannelParams* params = new OpenChannelParams(source, tab_json, receiver,
228 source_extension_id, target_extension_id, 170 receiver_port_id,
229 channel_name); 171 source_extension_id,
172 target_extension_id,
173 channel_name);
230 174
231 // The target might be a lazy background page. In that case, we have to check 175 // The target might be a lazy background page. In that case, we have to check
232 // if it is loaded and ready, and if not, queue up the task and load the 176 // if it is loaded and ready, and if not, queue up the task and load the
233 // page. 177 // page.
234 if (MaybeAddPendingOpenChannelTask(profile, params)) 178 if (MaybeAddPendingOpenChannelTask(profile, params)) {
179 return;
180 }
181
182 OpenChannelImpl(scoped_ptr<OpenChannelParams>(params));
183 }
184
185 void MessageService::OpenChannelToNativeApp(
186 int source_process_id,
187 int source_routing_id,
188 int receiver_port_id,
189 const std::string& source_extension_id,
190 const std::string& native_app_name,
191 const std::string& channel_name,
192 const std::string& connect_message) {
193 content::RenderProcessHost* source =
194 content::RenderProcessHost::FromID(source_process_id);
195 if (!source)
235 return; 196 return;
236 197
237 OpenChannelImpl(params); 198 WebContents* source_contents = tab_util::GetWebContentsByID(
199 source_process_id, source_routing_id);
200
201 // Include info about the opener's tab (if it was a tab).
202 std::string tab_json = "null";
203 if (source_contents) {
204 scoped_ptr<DictionaryValue> tab_value(ExtensionTabUtil::CreateTabValue(
205 source_contents, ExtensionTabUtil::INCLUDE_PRIVACY_SENSITIVE_FIELDS));
206 base::JSONWriter::Write(tab_value.get(), &tab_json);
207 }
208
209 scoped_ptr<MessageChannel> channel(new MessageChannel());
210 channel->opener.reset(new ExtensionMessagePort(source, MSG_ROUTING_CONTROL,
211 source_extension_id));
212
213 NativeMessageProcessHost::MessageType type =
214 channel_name == "chrome.extension.sendNativeMessage" ?
215 NativeMessageProcessHost::TYPE_SEND_MESSAGE_REQUEST :
216 NativeMessageProcessHost::TYPE_CONNECT;
217
218 content::BrowserThread::PostTask(
219 content::BrowserThread::FILE,
220 FROM_HERE,
221 base::Bind(&NativeMessageProcessHost::Create,
222 base::WeakPtr<NativeMessageProcessHost::Client>(
223 weak_factory_.GetWeakPtr()),
224 native_app_name, connect_message, receiver_port_id,
225 type,
226 base::Bind(&MessageService::FinalizeOpenChannelToNativeApp,
227 weak_factory_.GetWeakPtr(),
228 receiver_port_id,
229 channel_name,
230 base::Passed(&channel),
231 tab_json)));
232 }
233
234 void MessageService::FinalizeOpenChannelToNativeApp(
235 int receiver_port_id,
236 const std::string& channel_name,
237 scoped_ptr<MessageChannel> channel,
238 const std::string& tab_json,
239 NativeMessageProcessHost::ScopedHost native_process) {
240 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
241
242 // Abandon the channel
243 if (!native_process.get()) {
244 LOG(ERROR) << "Failed to create native process.";
245 return;
246 }
247 channel->receiver.reset(new NativeMessagePort(native_process.release()));
248
249 // Keep the opener alive until the channel is closed.
250 channel->opener->IncrementLazyKeepaliveCount();
251
252 AddChannel(channel.release(), receiver_port_id);
238 } 253 }
239 254
240 void MessageService::OpenChannelToTab( 255 void MessageService::OpenChannelToTab(
241 int source_process_id, int source_routing_id, int receiver_port_id, 256 int source_process_id, int source_routing_id, int receiver_port_id,
242 int tab_id, const std::string& extension_id, 257 int tab_id, const std::string& extension_id,
243 const std::string& channel_name) { 258 const std::string& channel_name) {
244 content::RenderProcessHost* source = 259 content::RenderProcessHost* source =
245 content::RenderProcessHost::FromID(source_process_id); 260 content::RenderProcessHost::FromID(source_process_id);
246 if (!source) 261 if (!source)
247 return; 262 return;
248 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext()); 263 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
249 264
250 TabContents* contents = NULL; 265 TabContents* contents = NULL;
251 MessagePort receiver; 266 scoped_ptr<MessagePort> receiver;
252 if (ExtensionTabUtil::GetTabById(tab_id, profile, true, 267 if (ExtensionTabUtil::GetTabById(tab_id, profile, true,
253 NULL, NULL, &contents, NULL)) { 268 NULL, NULL, &contents, NULL)) {
254 receiver.process = contents->web_contents()->GetRenderProcessHost(); 269 receiver.reset(new ExtensionMessagePort(
255 receiver.routing_id = 270 contents->web_contents()->GetRenderProcessHost(),
256 contents->web_contents()->GetRenderViewHost()->GetRoutingID(); 271 contents->web_contents()->GetRenderViewHost()->GetRoutingID(),
257 receiver.extension_id = extension_id; 272 extension_id));
258 } 273 }
259 274
260 if (contents && contents->web_contents()->GetController().NeedsReload()) { 275 if (contents && contents->web_contents()->GetController().NeedsReload()) {
261 // The tab isn't loaded yet. Don't attempt to connect. Treat this as a 276 // The tab isn't loaded yet. Don't attempt to connect. Treat this as a
262 // disconnect. 277 // disconnect.
263 DispatchOnDisconnect(MessagePort(source, MSG_ROUTING_CONTROL, extension_id), 278 ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, extension_id);
264 GET_OPPOSITE_PORT_ID(receiver_port_id), true); 279 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(receiver_port_id), true);
265 return; 280 return;
266 } 281 }
267 282
268 WebContents* source_contents = tab_util::GetWebContentsByID( 283 WebContents* source_contents = tab_util::GetWebContentsByID(
269 source_process_id, source_routing_id); 284 source_process_id, source_routing_id);
270 285
271 // Include info about the opener's tab (if it was a tab). 286 // Include info about the opener's tab (if it was a tab).
272 std::string tab_json = "null"; 287 std::string tab_json = "null";
273 if (source_contents) { 288 if (source_contents) {
274 scoped_ptr<DictionaryValue> tab_value(ExtensionTabUtil::CreateTabValue( 289 scoped_ptr<DictionaryValue> tab_value(ExtensionTabUtil::CreateTabValue(
275 source_contents, ExtensionTabUtil::INCLUDE_PRIVACY_SENSITIVE_FIELDS)); 290 source_contents, ExtensionTabUtil::INCLUDE_PRIVACY_SENSITIVE_FIELDS));
276 base::JSONWriter::Write(tab_value.get(), &tab_json); 291 base::JSONWriter::Write(tab_value.get(), &tab_json);
277 } 292 }
278 293
279 OpenChannelParams params(source, tab_json, receiver, receiver_port_id, 294 scoped_ptr<OpenChannelParams> params(new OpenChannelParams(source, tab_json,
280 extension_id, extension_id, channel_name); 295 receiver.release(),
281 OpenChannelImpl(params); 296 receiver_port_id,
297 extension_id,
298 extension_id,
299 channel_name));
300 OpenChannelImpl(params.Pass());
282 } 301 }
283 302
284 bool MessageService::OpenChannelImpl(const OpenChannelParams& params) { 303 bool MessageService::OpenChannelImpl(scoped_ptr<OpenChannelParams> params) {
285 if (!params.source) 304 if (!params->source)
286 return false; // Closed while in flight. 305 return false; // Closed while in flight.
287 306
288 if (!params.receiver.process) { 307 if (!params->receiver.get() || !params->receiver->GetRenderProcessHost()) {
289 // Treat it as a disconnect. 308 // Treat it as a disconnect.
290 DispatchOnDisconnect(MessagePort(params.source, MSG_ROUTING_CONTROL, ""), 309 ExtensionMessagePort port(params->source, MSG_ROUTING_CONTROL, "");
291 GET_OPPOSITE_PORT_ID(params.receiver_port_id), true); 310 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(params->receiver_port_id),
311 true);
292 return false; 312 return false;
293 } 313 }
294 314
295 // Add extra paranoid CHECKs, since we have crash reports of this being NULL. 315 // Add extra paranoid CHECKs, since we have crash reports of this being NULL.
296 // http://code.google.com/p/chromium/issues/detail?id=19067 316 // http://code.google.com/p/chromium/issues/detail?id=19067
297 CHECK(params.receiver.process); 317 CHECK(params->receiver->GetRenderProcessHost());
298 318
299 MessageChannel* channel(new MessageChannel); 319 MessageChannel* channel(new MessageChannel);
300 channel->opener = MessagePort(params.source, MSG_ROUTING_CONTROL, 320 channel->opener.reset(new ExtensionMessagePort(params->source,
301 params.source_extension_id); 321 MSG_ROUTING_CONTROL,
302 channel->receiver = params.receiver; 322 params->source_extension_id));
323 channel->receiver.reset(params->receiver.release());
303 324
304 CHECK(params.receiver.process); 325 CHECK(channel->receiver->GetRenderProcessHost());
305 326
306 int channel_id = GET_CHANNEL_ID(params.receiver_port_id); 327 AddChannel(channel, params->receiver_port_id);
328
329 CHECK(channel->receiver->GetRenderProcessHost());
330
331 // Send the connect event to the receiver. Give it the opener's port ID (the
332 // opener has the opposite port ID).
333 channel->receiver->DispatchOnConnect(params->receiver_port_id,
334 params->channel_name, params->tab_json,
335 params->source_extension_id,
336 params->target_extension_id);
337
338 // Keep both ends of the channel alive until the channel is closed.
339 channel->opener->IncrementLazyKeepaliveCount();
340 channel->receiver->IncrementLazyKeepaliveCount();
341 return true;
342 }
343
344 void MessageService::AddChannel(MessageChannel* channel, int receiver_port_id) {
345 int channel_id = GET_CHANNEL_ID(receiver_port_id);
307 CHECK(channels_.find(channel_id) == channels_.end()); 346 CHECK(channels_.find(channel_id) == channels_.end());
308 channels_[channel_id] = channel; 347 channels_[channel_id] = channel;
309 pending_channels_.erase(channel_id); 348 pending_channels_.erase(channel_id);
310
311 CHECK(params.receiver.process);
312
313 // Send the connect event to the receiver. Give it the opener's port ID (the
314 // opener has the opposite port ID).
315 DispatchOnConnect(params.receiver, params.receiver_port_id,
316 params.channel_name, params.tab_json,
317 params.source_extension_id, params.target_extension_id);
318
319 // Keep both ends of the channel alive until the channel is closed.
320 IncrementLazyKeepaliveCount(&channel->opener);
321 IncrementLazyKeepaliveCount(&channel->receiver);
322 return true;
323 } 349 }
324 350
325 void MessageService::CloseChannel(int port_id, bool connection_error) { 351 void MessageService::CloseChannel(int port_id, bool connection_error) {
326 // Note: The channel might be gone already, if the other side closed first. 352 // Note: The channel might be gone already, if the other side closed first.
327 int channel_id = GET_CHANNEL_ID(port_id); 353 int channel_id = GET_CHANNEL_ID(port_id);
328 MessageChannelMap::iterator it = channels_.find(channel_id); 354 MessageChannelMap::iterator it = channels_.find(channel_id);
329 if (it == channels_.end()) { 355 if (it == channels_.end()) {
330 PendingChannelMap::iterator pending = pending_channels_.find(channel_id); 356 PendingChannelMap::iterator pending = pending_channels_.find(channel_id);
331 if (pending != pending_channels_.end()) { 357 if (pending != pending_channels_.end()) {
332 lazy_background_task_queue_->AddPendingTask( 358 lazy_background_task_queue_->AddPendingTask(
333 pending->second.first, pending->second.second, 359 pending->second.first, pending->second.second,
334 base::Bind(&MessageService::PendingCloseChannel, 360 base::Bind(&MessageService::PendingCloseChannel,
335 base::Unretained(this), port_id, connection_error)); 361 weak_factory_.GetWeakPtr(), port_id, connection_error));
336 } 362 }
337 return; 363 return;
338 } 364 }
339 CloseChannelImpl(it, port_id, connection_error, true); 365 CloseChannelImpl(it, port_id, connection_error, true);
340 } 366 }
341 367
342 void MessageService::CloseChannelImpl( 368 void MessageService::CloseChannelImpl(
343 MessageChannelMap::iterator channel_iter, int closing_port_id, 369 MessageChannelMap::iterator channel_iter, int closing_port_id,
344 bool connection_error, bool notify_other_port) { 370 bool connection_error, bool notify_other_port) {
345 MessageChannel* channel = channel_iter->second; 371 MessageChannel* channel = channel_iter->second;
346 372
347 // Notify the other side. 373 // Notify the other side.
348 if (notify_other_port) { 374 if (notify_other_port) {
349 const MessagePort& port = IS_OPENER_PORT_ID(closing_port_id) ? 375 MessagePort* port = IS_OPENER_PORT_ID(closing_port_id) ?
350 channel->receiver : channel->opener; 376 channel->receiver.get() : channel->opener.get();
351 DispatchOnDisconnect(port, GET_OPPOSITE_PORT_ID(closing_port_id), 377 port->DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(closing_port_id),
352 connection_error); 378 connection_error);
353 } 379 }
354 380
355 // Balance the addrefs in OpenChannelImpl. 381 // Balance the IncrementLazyKeepaliveCount() in OpenChannelImpl.
356 DecrementLazyKeepaliveCount(&channel->opener); 382 channel->opener->DecrementLazyKeepaliveCount();
357 DecrementLazyKeepaliveCount(&channel->receiver); 383 channel->receiver->DecrementLazyKeepaliveCount();
358 384
359 delete channel_iter->second; 385 delete channel_iter->second;
360 channels_.erase(channel_iter); 386 channels_.erase(channel_iter);
361 } 387 }
362 388
363 void MessageService::PostMessageFromRenderer( 389 void MessageService::PostMessage(
364 int source_port_id, const std::string& message) { 390 int source_port_id, const std::string& message) {
365 int channel_id = GET_CHANNEL_ID(source_port_id); 391 int channel_id = GET_CHANNEL_ID(source_port_id);
366 MessageChannelMap::iterator iter = channels_.find(channel_id); 392 MessageChannelMap::iterator iter = channels_.find(channel_id);
367 if (iter == channels_.end()) { 393 if (iter == channels_.end()) {
368 // If this channel is pending, queue up the PostMessage to run once 394 // If this channel is pending, queue up the PostMessage to run once
369 // the channel opens. 395 // the channel opens.
370 PendingChannelMap::iterator pending = pending_channels_.find(channel_id); 396 PendingChannelMap::iterator pending = pending_channels_.find(channel_id);
371 if (pending != pending_channels_.end()) { 397 if (pending != pending_channels_.end()) {
372 lazy_background_task_queue_->AddPendingTask( 398 lazy_background_task_queue_->AddPendingTask(
373 pending->second.first, pending->second.second, 399 pending->second.first, pending->second.second,
374 base::Bind(&MessageService::PendingPostMessage, 400 base::Bind(&MessageService::PendingPostMessage,
375 base::Unretained(this), source_port_id, message)); 401 weak_factory_.GetWeakPtr(), source_port_id, message));
376 } 402 }
377 return; 403 return;
378 } 404 }
379 405
380 // Figure out which port the ID corresponds to. 406 // Figure out which port the ID corresponds to.
381 int dest_port_id = GET_OPPOSITE_PORT_ID(source_port_id); 407 int dest_port_id = GET_OPPOSITE_PORT_ID(source_port_id);
382 const MessagePort& port = IS_OPENER_PORT_ID(dest_port_id) ? 408 MessagePort* port = IS_OPENER_PORT_ID(dest_port_id) ?
383 iter->second->opener : iter->second->receiver; 409 iter->second->opener.get() : iter->second->receiver.get();
384 410
385 DispatchOnMessage(port, message, dest_port_id); 411 port->DispatchOnMessage(message, dest_port_id);
412 }
413
414 void MessageService::PostMessageFromNativeProcess(int port_id,
415 const std::string& message) {
416 PostMessage(port_id, message);
386 } 417 }
387 418
388 void MessageService::Observe(int type, 419 void MessageService::Observe(int type,
389 const content::NotificationSource& source, 420 const content::NotificationSource& source,
390 const content::NotificationDetails& details) { 421 const content::NotificationDetails& details) {
391 switch (type) { 422 switch (type) {
392 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: 423 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
393 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { 424 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
394 content::RenderProcessHost* renderer = 425 content::RenderProcessHost* renderer =
395 content::Source<content::RenderProcessHost>(source).ptr(); 426 content::Source<content::RenderProcessHost>(source).ptr();
396 OnProcessClosed(renderer); 427 OnProcessClosed(renderer);
397 break; 428 break;
398 } 429 }
399 default: 430 default:
400 NOTREACHED(); 431 NOTREACHED();
401 return; 432 return;
402 } 433 }
403 } 434 }
404 435
405 void MessageService::OnProcessClosed(content::RenderProcessHost* process) { 436 void MessageService::OnProcessClosed(content::RenderProcessHost* process) {
406 // Close any channels that share this renderer. We notify the opposite 437 // Close any channels that share this renderer. We notify the opposite
407 // port that his pair has closed. 438 // port that his pair has closed.
408 for (MessageChannelMap::iterator it = channels_.begin(); 439 for (MessageChannelMap::iterator it = channels_.begin();
409 it != channels_.end(); ) { 440 it != channels_.end(); ) {
410 MessageChannelMap::iterator current = it++; 441 MessageChannelMap::iterator current = it++;
411 // If both sides are the same renderer, and it is closing, there is no
412 // "other" port, so there's no need to notify it.
413 bool notify_other_port =
414 current->second->opener.process != current->second->receiver.process;
415 442
416 if (current->second->opener.process == process) { 443 content::RenderProcessHost* opener_process =
444 current->second->opener->GetRenderProcessHost();
445 content::RenderProcessHost* receiver_process =
446 current->second->receiver->GetRenderProcessHost();
447
448 bool notify_other_port = opener_process &&
449 opener_process == receiver_process;
450
451 if (opener_process == process) {
417 CloseChannelImpl(current, GET_CHANNEL_OPENER_ID(current->first), 452 CloseChannelImpl(current, GET_CHANNEL_OPENER_ID(current->first),
418 false, notify_other_port); 453 false, notify_other_port);
419 } else if (current->second->receiver.process == process) { 454 } else if (receiver_process == process) {
420 CloseChannelImpl(current, GET_CHANNEL_RECEIVERS_ID(current->first), 455 CloseChannelImpl(current, GET_CHANNEL_RECEIVERS_ID(current->first),
421 false, notify_other_port); 456 false, notify_other_port);
422 } 457 }
423 } 458 }
424 } 459 }
425 460
426 bool MessageService::MaybeAddPendingOpenChannelTask( 461 bool MessageService::MaybeAddPendingOpenChannelTask(
427 Profile* profile, 462 Profile* profile,
428 const OpenChannelParams& params) { 463 OpenChannelParams* params) {
429 ExtensionService* service = profile->GetExtensionService(); 464 ExtensionService* service = profile->GetExtensionService();
430 const std::string& extension_id = params.target_extension_id; 465 const std::string& extension_id = params->target_extension_id;
431 const Extension* extension = service->extensions()->GetByID( 466 const Extension* extension = service->extensions()->GetByID(extension_id);
432 extension_id);
433 if (extension && extension->has_lazy_background_page()) { 467 if (extension && extension->has_lazy_background_page()) {
434 // If the extension uses spanning incognito mode, make sure we're always 468 // If the extension uses spanning incognito mode, make sure we're always
435 // using the original profile since that is what the extension process 469 // using the original profile since that is what the extension process
436 // will use. 470 // will use.
437 if (!extension->incognito_split_mode()) 471 if (!extension->incognito_split_mode())
438 profile = profile->GetOriginalProfile(); 472 profile = profile->GetOriginalProfile();
439 473
440 if (lazy_background_task_queue_->ShouldEnqueueTask(profile, extension)) { 474 if (lazy_background_task_queue_->ShouldEnqueueTask(profile, extension)) {
475 pending_channels_[GET_CHANNEL_ID(params->receiver_port_id)] =
476 PendingChannel(profile, extension_id);
477 scoped_ptr<OpenChannelParams> scoped_params(params);
441 lazy_background_task_queue_->AddPendingTask(profile, extension_id, 478 lazy_background_task_queue_->AddPendingTask(profile, extension_id,
442 base::Bind(&MessageService::PendingOpenChannel, 479 base::Bind(&MessageService::PendingOpenChannel,
443 base::Unretained(this), params, params.source->GetID())); 480 weak_factory_.GetWeakPtr(), base::Passed(&scoped_params),
444 pending_channels_[GET_CHANNEL_ID(params.receiver_port_id)] = 481 params->source->GetID()));
445 PendingChannel(profile, extension_id);
446 return true; 482 return true;
447 } 483 }
448 } 484 }
449 485
450 return false; 486 return false;
451 } 487 }
452 488
453 void MessageService::PendingOpenChannel(const OpenChannelParams& params_in, 489 void MessageService::PendingOpenChannel(scoped_ptr<OpenChannelParams> params,
454 int source_process_id, 490 int source_process_id,
455 ExtensionHost* host) { 491 ExtensionHost* host) {
456 if (!host) 492 if (!host)
457 return; // TODO(mpcomplete): notify source of disconnect? 493 return; // TODO(mpcomplete): notify source of disconnect?
458 494
459 // Re-lookup the source process since it may no longer be valid. 495 // Re-lookup the source process since it may no longer be valid.
460 OpenChannelParams params = params_in; 496 content::RenderProcessHost* source =
461 params.source = content::RenderProcessHost::FromID(source_process_id); 497 content::RenderProcessHost::FromID(source_process_id);
462 if (!params.source) 498 if (!source)
463 return; 499 return;
464 500
465 params.receiver = MessagePort(host->render_process_host(), 501 params->source = source;
466 MSG_ROUTING_CONTROL, 502 params->receiver.reset(new ExtensionMessagePort(host->render_process_host(),
467 params.target_extension_id); 503 MSG_ROUTING_CONTROL,
468 OpenChannelImpl(params); 504 params->target_extension_id));
505 OpenChannelImpl(params.Pass());
469 } 506 }
470 507
471 } // namespace extensions 508 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698