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

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

Issue 10818013: Native Messaging! (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: nit Created 8 years, 3 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
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, 165 source_contents,
224 profile->GetExtensionService()->extensions()->GetByID( 166 profile->GetExtensionService()->extensions()->GetByID(
225 source_extension_id))); 167 source_extension_id)));
226 base::JSONWriter::Write(tab_value.get(), &tab_json); 168 base::JSONWriter::Write(tab_value.get(), &tab_json);
227 } 169 }
228 170
229 OpenChannelParams params(source, tab_json, receiver, receiver_port_id, 171 OpenChannelParams* params = new OpenChannelParams(source, tab_json, receiver,
230 source_extension_id, target_extension_id, 172 receiver_port_id,
231 channel_name); 173 source_extension_id,
174 target_extension_id,
175 channel_name);
232 176
233 // The target might be a lazy background page. In that case, we have to check 177 // The target might be a lazy background page. In that case, we have to check
234 // if it is loaded and ready, and if not, queue up the task and load the 178 // if it is loaded and ready, and if not, queue up the task and load the
235 // page. 179 // page.
236 if (MaybeAddPendingOpenChannelTask(profile, params)) 180 if (MaybeAddPendingOpenChannelTask(profile, params)) {
237 return; 181 return;
182 }
238 183
239 OpenChannelImpl(params); 184 OpenChannelImpl(scoped_ptr<OpenChannelParams>(params));
185 }
186
187 void MessageService::OpenChannelToNativeApp(
188 int source_process_id,
189 int source_routing_id,
190 int receiver_port_id,
191 const std::string& source_extension_id,
192 const std::string& native_app_name,
193 const std::string& channel_name,
194 const std::string& connect_message) {
195 content::RenderProcessHost* source =
196 content::RenderProcessHost::FromID(source_process_id);
197 if (!source)
198 return;
199 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
200
201 WebContents* source_contents = tab_util::GetWebContentsByID(
202 source_process_id, source_routing_id);
203
204 // Include info about the opener's tab (if it was a tab).
205 std::string tab_json = "null";
206 if (source_contents) {
207 scoped_ptr<DictionaryValue> tab_value(ExtensionTabUtil::CreateTabValue(
208 source_contents,
209 profile->GetExtensionService()->extensions()->GetByID(
210 source_extension_id)));
211 base::JSONWriter::Write(tab_value.get(), &tab_json);
212 }
213
214 scoped_ptr<MessageChannel> channel(new MessageChannel());
215 channel->opener.reset(new ExtensionMessagePort(source, MSG_ROUTING_CONTROL,
216 source_extension_id));
217
218 NativeMessageProcessHost::MessageType type =
219 channel_name == "chrome.extension.sendNativeMessage" ?
220 NativeMessageProcessHost::TYPE_SEND_MESSAGE_REQUEST :
221 NativeMessageProcessHost::TYPE_CONNECT;
222
223 content::BrowserThread::PostTask(
224 content::BrowserThread::FILE,
225 FROM_HERE,
226 base::Bind(&NativeMessageProcessHost::Create,
227 base::WeakPtr<NativeMessageProcessHost::Client>(
228 weak_factory_.GetWeakPtr()),
229 native_app_name, connect_message, receiver_port_id,
230 type,
231 base::Bind(&MessageService::FinalizeOpenChannelToNativeApp,
232 weak_factory_.GetWeakPtr(),
233 receiver_port_id,
234 channel_name,
235 base::Passed(&channel),
236 tab_json)));
237 }
238
239 void MessageService::FinalizeOpenChannelToNativeApp(
240 int receiver_port_id,
241 const std::string& channel_name,
242 scoped_ptr<MessageChannel> channel,
243 const std::string& tab_json,
244 NativeMessageProcessHost::ScopedHost native_process) {
245 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
246
247 // Abandon the channel
248 if (!native_process.get()) {
249 LOG(ERROR) << "Failed to create native process.";
250 return;
251 }
252 channel->receiver.reset(new NativeMessagePort(native_process.release()));
253
254 // Keep the opener alive until the channel is closed.
255 channel->opener->IncrementLazyKeepaliveCount();
256
257 AddChannel(channel.release(), receiver_port_id);
240 } 258 }
241 259
242 void MessageService::OpenChannelToTab( 260 void MessageService::OpenChannelToTab(
243 int source_process_id, int source_routing_id, int receiver_port_id, 261 int source_process_id, int source_routing_id, int receiver_port_id,
244 int tab_id, const std::string& extension_id, 262 int tab_id, const std::string& extension_id,
245 const std::string& channel_name) { 263 const std::string& channel_name) {
246 content::RenderProcessHost* source = 264 content::RenderProcessHost* source =
247 content::RenderProcessHost::FromID(source_process_id); 265 content::RenderProcessHost::FromID(source_process_id);
248 if (!source) 266 if (!source)
249 return; 267 return;
250 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext()); 268 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
251 269
252 TabContents* contents = NULL; 270 TabContents* contents = NULL;
253 MessagePort receiver; 271 scoped_ptr<MessagePort> receiver;
254 if (ExtensionTabUtil::GetTabById(tab_id, profile, true, 272 if (ExtensionTabUtil::GetTabById(tab_id, profile, true,
255 NULL, NULL, &contents, NULL)) { 273 NULL, NULL, &contents, NULL)) {
256 receiver.process = contents->web_contents()->GetRenderProcessHost(); 274 receiver.reset(new ExtensionMessagePort(
257 receiver.routing_id = 275 contents->web_contents()->GetRenderProcessHost(),
258 contents->web_contents()->GetRenderViewHost()->GetRoutingID(); 276 contents->web_contents()->GetRenderViewHost()->GetRoutingID(),
259 receiver.extension_id = extension_id; 277 extension_id));
260 } 278 }
261 279
262 if (contents && contents->web_contents()->GetController().NeedsReload()) { 280 if (contents && contents->web_contents()->GetController().NeedsReload()) {
263 // The tab isn't loaded yet. Don't attempt to connect. Treat this as a 281 // The tab isn't loaded yet. Don't attempt to connect. Treat this as a
264 // disconnect. 282 // disconnect.
265 DispatchOnDisconnect(MessagePort(source, MSG_ROUTING_CONTROL, extension_id), 283 ExtensionMessagePort port(source, MSG_ROUTING_CONTROL, extension_id);
266 GET_OPPOSITE_PORT_ID(receiver_port_id), true); 284 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(receiver_port_id), true);
267 return; 285 return;
268 } 286 }
269 287
270 WebContents* source_contents = tab_util::GetWebContentsByID( 288 WebContents* source_contents = tab_util::GetWebContentsByID(
271 source_process_id, source_routing_id); 289 source_process_id, source_routing_id);
272 290
273 // Include info about the opener's tab (if it was a tab). 291 // Include info about the opener's tab (if it was a tab).
274 std::string tab_json = "null"; 292 std::string tab_json = "null";
275 if (source_contents) { 293 if (source_contents) {
276 scoped_ptr<DictionaryValue> tab_value(ExtensionTabUtil::CreateTabValue( 294 scoped_ptr<DictionaryValue> tab_value(ExtensionTabUtil::CreateTabValue(
277 source_contents, 295 source_contents,
278 profile->GetExtensionService()->extensions()->GetByID( 296 profile->GetExtensionService()->extensions()->GetByID(
279 extension_id))); 297 extension_id)));
280 base::JSONWriter::Write(tab_value.get(), &tab_json); 298 base::JSONWriter::Write(tab_value.get(), &tab_json);
281 } 299 }
282 300
283 OpenChannelParams params(source, tab_json, receiver, receiver_port_id, 301 scoped_ptr<OpenChannelParams> params(new OpenChannelParams(source, tab_json,
284 extension_id, extension_id, channel_name); 302 receiver.release(),
285 OpenChannelImpl(params); 303 receiver_port_id,
304 extension_id,
305 extension_id,
306 channel_name));
307 OpenChannelImpl(params.Pass());
286 } 308 }
287 309
288 bool MessageService::OpenChannelImpl(const OpenChannelParams& params) { 310 bool MessageService::OpenChannelImpl(scoped_ptr<OpenChannelParams> params) {
289 if (!params.source) 311 if (!params->source)
290 return false; // Closed while in flight. 312 return false; // Closed while in flight.
291 313
292 if (!params.receiver.process) { 314 if (!params->receiver.get() || !params->receiver->GetRenderProcessHost()) {
293 // Treat it as a disconnect. 315 // Treat it as a disconnect.
294 DispatchOnDisconnect(MessagePort(params.source, MSG_ROUTING_CONTROL, ""), 316 ExtensionMessagePort port(params->source, MSG_ROUTING_CONTROL, "");
295 GET_OPPOSITE_PORT_ID(params.receiver_port_id), true); 317 port.DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(params->receiver_port_id),
318 true);
296 return false; 319 return false;
297 } 320 }
298 321
299 // Add extra paranoid CHECKs, since we have crash reports of this being NULL. 322 // Add extra paranoid CHECKs, since we have crash reports of this being NULL.
300 // http://code.google.com/p/chromium/issues/detail?id=19067 323 // http://code.google.com/p/chromium/issues/detail?id=19067
301 CHECK(params.receiver.process); 324 CHECK(params->receiver->GetRenderProcessHost());
302 325
303 MessageChannel* channel(new MessageChannel); 326 MessageChannel* channel(new MessageChannel);
304 channel->opener = MessagePort(params.source, MSG_ROUTING_CONTROL, 327 channel->opener.reset(new ExtensionMessagePort(params->source,
305 params.source_extension_id); 328 MSG_ROUTING_CONTROL,
306 channel->receiver = params.receiver; 329 params->source_extension_id));
330 channel->receiver.reset(params->receiver.release());
307 331
308 CHECK(params.receiver.process); 332 CHECK(channel->receiver->GetRenderProcessHost());
309 333
310 int channel_id = GET_CHANNEL_ID(params.receiver_port_id); 334 AddChannel(channel, params->receiver_port_id);
335
336 CHECK(channel->receiver->GetRenderProcessHost());
337
338 // Send the connect event to the receiver. Give it the opener's port ID (the
339 // opener has the opposite port ID).
340 channel->receiver->DispatchOnConnect(params->receiver_port_id,
341 params->channel_name, params->tab_json,
342 params->source_extension_id,
343 params->target_extension_id);
344
345 // Keep both ends of the channel alive until the channel is closed.
346 channel->opener->IncrementLazyKeepaliveCount();
347 channel->receiver->IncrementLazyKeepaliveCount();
348 return true;
349 }
350
351 void MessageService::AddChannel(MessageChannel* channel, int receiver_port_id) {
352 int channel_id = GET_CHANNEL_ID(receiver_port_id);
311 CHECK(channels_.find(channel_id) == channels_.end()); 353 CHECK(channels_.find(channel_id) == channels_.end());
312 channels_[channel_id] = channel; 354 channels_[channel_id] = channel;
313 pending_channels_.erase(channel_id); 355 pending_channels_.erase(channel_id);
314
315 CHECK(params.receiver.process);
316
317 // Send the connect event to the receiver. Give it the opener's port ID (the
318 // opener has the opposite port ID).
319 DispatchOnConnect(params.receiver, params.receiver_port_id,
320 params.channel_name, params.tab_json,
321 params.source_extension_id, params.target_extension_id);
322
323 // Keep both ends of the channel alive until the channel is closed.
324 IncrementLazyKeepaliveCount(&channel->opener);
325 IncrementLazyKeepaliveCount(&channel->receiver);
326 return true;
327 } 356 }
328 357
329 void MessageService::CloseChannel(int port_id, bool connection_error) { 358 void MessageService::CloseChannel(int port_id, bool connection_error) {
330 // Note: The channel might be gone already, if the other side closed first. 359 // Note: The channel might be gone already, if the other side closed first.
331 int channel_id = GET_CHANNEL_ID(port_id); 360 int channel_id = GET_CHANNEL_ID(port_id);
332 MessageChannelMap::iterator it = channels_.find(channel_id); 361 MessageChannelMap::iterator it = channels_.find(channel_id);
333 if (it == channels_.end()) { 362 if (it == channels_.end()) {
334 PendingChannelMap::iterator pending = pending_channels_.find(channel_id); 363 PendingChannelMap::iterator pending = pending_channels_.find(channel_id);
335 if (pending != pending_channels_.end()) { 364 if (pending != pending_channels_.end()) {
336 lazy_background_task_queue_->AddPendingTask( 365 lazy_background_task_queue_->AddPendingTask(
337 pending->second.first, pending->second.second, 366 pending->second.first, pending->second.second,
338 base::Bind(&MessageService::PendingCloseChannel, 367 base::Bind(&MessageService::PendingCloseChannel,
339 base::Unretained(this), port_id, connection_error)); 368 weak_factory_.GetWeakPtr(), port_id, connection_error));
340 } 369 }
341 return; 370 return;
342 } 371 }
343 CloseChannelImpl(it, port_id, connection_error, true); 372 CloseChannelImpl(it, port_id, connection_error, true);
344 } 373 }
345 374
346 void MessageService::CloseChannelImpl( 375 void MessageService::CloseChannelImpl(
347 MessageChannelMap::iterator channel_iter, int closing_port_id, 376 MessageChannelMap::iterator channel_iter, int closing_port_id,
348 bool connection_error, bool notify_other_port) { 377 bool connection_error, bool notify_other_port) {
349 MessageChannel* channel = channel_iter->second; 378 MessageChannel* channel = channel_iter->second;
350 379
351 // Notify the other side. 380 // Notify the other side.
352 if (notify_other_port) { 381 if (notify_other_port) {
353 const MessagePort& port = IS_OPENER_PORT_ID(closing_port_id) ? 382 MessagePort* port = IS_OPENER_PORT_ID(closing_port_id) ?
354 channel->receiver : channel->opener; 383 channel->receiver.get() : channel->opener.get();
355 DispatchOnDisconnect(port, GET_OPPOSITE_PORT_ID(closing_port_id), 384 port->DispatchOnDisconnect(GET_OPPOSITE_PORT_ID(closing_port_id),
356 connection_error); 385 connection_error);
357 } 386 }
358 387
359 // Balance the addrefs in OpenChannelImpl. 388 // Balance the IncrementLazyKeepaliveCount() in OpenChannelImpl.
360 DecrementLazyKeepaliveCount(&channel->opener); 389 channel->opener->DecrementLazyKeepaliveCount();
361 DecrementLazyKeepaliveCount(&channel->receiver); 390 channel->receiver->DecrementLazyKeepaliveCount();
362 391
363 delete channel_iter->second; 392 delete channel_iter->second;
364 channels_.erase(channel_iter); 393 channels_.erase(channel_iter);
365 } 394 }
366 395
367 void MessageService::PostMessageFromRenderer( 396 void MessageService::PostMessage(
368 int source_port_id, const std::string& message) { 397 int source_port_id, const std::string& message) {
369 int channel_id = GET_CHANNEL_ID(source_port_id); 398 int channel_id = GET_CHANNEL_ID(source_port_id);
370 MessageChannelMap::iterator iter = channels_.find(channel_id); 399 MessageChannelMap::iterator iter = channels_.find(channel_id);
371 if (iter == channels_.end()) { 400 if (iter == channels_.end()) {
372 // If this channel is pending, queue up the PostMessage to run once 401 // If this channel is pending, queue up the PostMessage to run once
373 // the channel opens. 402 // the channel opens.
374 PendingChannelMap::iterator pending = pending_channels_.find(channel_id); 403 PendingChannelMap::iterator pending = pending_channels_.find(channel_id);
375 if (pending != pending_channels_.end()) { 404 if (pending != pending_channels_.end()) {
376 lazy_background_task_queue_->AddPendingTask( 405 lazy_background_task_queue_->AddPendingTask(
377 pending->second.first, pending->second.second, 406 pending->second.first, pending->second.second,
378 base::Bind(&MessageService::PendingPostMessage, 407 base::Bind(&MessageService::PendingPostMessage,
379 base::Unretained(this), source_port_id, message)); 408 weak_factory_.GetWeakPtr(), source_port_id, message));
380 } 409 }
381 return; 410 return;
382 } 411 }
383 412
384 // Figure out which port the ID corresponds to. 413 // Figure out which port the ID corresponds to.
385 int dest_port_id = GET_OPPOSITE_PORT_ID(source_port_id); 414 int dest_port_id = GET_OPPOSITE_PORT_ID(source_port_id);
386 const MessagePort& port = IS_OPENER_PORT_ID(dest_port_id) ? 415 MessagePort* port = IS_OPENER_PORT_ID(dest_port_id) ?
387 iter->second->opener : iter->second->receiver; 416 iter->second->opener.get() : iter->second->receiver.get();
388 417
389 DispatchOnMessage(port, message, dest_port_id); 418 port->DispatchOnMessage(message, dest_port_id);
419 }
420
421 void MessageService::PostMessageFromNativeProcess(int port_id,
422 const std::string& message) {
423 PostMessage(port_id, message);
390 } 424 }
391 425
392 void MessageService::Observe(int type, 426 void MessageService::Observe(int type,
393 const content::NotificationSource& source, 427 const content::NotificationSource& source,
394 const content::NotificationDetails& details) { 428 const content::NotificationDetails& details) {
395 switch (type) { 429 switch (type) {
396 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: 430 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED:
397 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { 431 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
398 content::RenderProcessHost* renderer = 432 content::RenderProcessHost* renderer =
399 content::Source<content::RenderProcessHost>(source).ptr(); 433 content::Source<content::RenderProcessHost>(source).ptr();
400 OnProcessClosed(renderer); 434 OnProcessClosed(renderer);
401 break; 435 break;
402 } 436 }
403 default: 437 default:
404 NOTREACHED(); 438 NOTREACHED();
405 return; 439 return;
406 } 440 }
407 } 441 }
408 442
409 void MessageService::OnProcessClosed(content::RenderProcessHost* process) { 443 void MessageService::OnProcessClosed(content::RenderProcessHost* process) {
410 // Close any channels that share this renderer. We notify the opposite 444 // Close any channels that share this renderer. We notify the opposite
411 // port that his pair has closed. 445 // port that his pair has closed.
412 for (MessageChannelMap::iterator it = channels_.begin(); 446 for (MessageChannelMap::iterator it = channels_.begin();
413 it != channels_.end(); ) { 447 it != channels_.end(); ) {
414 MessageChannelMap::iterator current = it++; 448 MessageChannelMap::iterator current = it++;
415 // If both sides are the same renderer, and it is closing, there is no
416 // "other" port, so there's no need to notify it.
417 bool notify_other_port =
418 current->second->opener.process != current->second->receiver.process;
419 449
420 if (current->second->opener.process == process) { 450 content::RenderProcessHost* opener_process =
451 current->second->opener->GetRenderProcessHost();
452 content::RenderProcessHost* receiver_process =
453 current->second->receiver->GetRenderProcessHost();
454
455 bool notify_other_port = opener_process &&
456 opener_process == receiver_process;
457
458 if (opener_process == process) {
421 CloseChannelImpl(current, GET_CHANNEL_OPENER_ID(current->first), 459 CloseChannelImpl(current, GET_CHANNEL_OPENER_ID(current->first),
422 false, notify_other_port); 460 false, notify_other_port);
423 } else if (current->second->receiver.process == process) { 461 } else if (receiver_process == process) {
424 CloseChannelImpl(current, GET_CHANNEL_RECEIVERS_ID(current->first), 462 CloseChannelImpl(current, GET_CHANNEL_RECEIVERS_ID(current->first),
425 false, notify_other_port); 463 false, notify_other_port);
426 } 464 }
427 } 465 }
428 } 466 }
429 467
430 bool MessageService::MaybeAddPendingOpenChannelTask( 468 bool MessageService::MaybeAddPendingOpenChannelTask(
431 Profile* profile, 469 Profile* profile,
432 const OpenChannelParams& params) { 470 OpenChannelParams* params) {
433 ExtensionService* service = profile->GetExtensionService(); 471 ExtensionService* service = profile->GetExtensionService();
434 const std::string& extension_id = params.target_extension_id; 472 const std::string& extension_id = params->target_extension_id;
435 const Extension* extension = service->extensions()->GetByID( 473 const Extension* extension = service->extensions()->GetByID(extension_id);
436 extension_id);
437 if (extension && extension->has_lazy_background_page()) { 474 if (extension && extension->has_lazy_background_page()) {
438 // If the extension uses spanning incognito mode, make sure we're always 475 // If the extension uses spanning incognito mode, make sure we're always
439 // using the original profile since that is what the extension process 476 // using the original profile since that is what the extension process
440 // will use. 477 // will use.
441 if (!extension->incognito_split_mode()) 478 if (!extension->incognito_split_mode())
442 profile = profile->GetOriginalProfile(); 479 profile = profile->GetOriginalProfile();
443 480
444 if (lazy_background_task_queue_->ShouldEnqueueTask(profile, extension)) { 481 if (lazy_background_task_queue_->ShouldEnqueueTask(profile, extension)) {
482 pending_channels_[GET_CHANNEL_ID(params->receiver_port_id)] =
483 PendingChannel(profile, extension_id);
484 scoped_ptr<OpenChannelParams> scoped_params(params);
445 lazy_background_task_queue_->AddPendingTask(profile, extension_id, 485 lazy_background_task_queue_->AddPendingTask(profile, extension_id,
446 base::Bind(&MessageService::PendingOpenChannel, 486 base::Bind(&MessageService::PendingOpenChannel,
447 base::Unretained(this), params, params.source->GetID())); 487 weak_factory_.GetWeakPtr(), base::Passed(&scoped_params),
448 pending_channels_[GET_CHANNEL_ID(params.receiver_port_id)] = 488 params->source->GetID()));
449 PendingChannel(profile, extension_id);
450 return true; 489 return true;
451 } 490 }
452 } 491 }
453 492
454 return false; 493 return false;
455 } 494 }
456 495
457 void MessageService::PendingOpenChannel(const OpenChannelParams& params_in, 496 void MessageService::PendingOpenChannel(scoped_ptr<OpenChannelParams> params,
458 int source_process_id, 497 int source_process_id,
459 ExtensionHost* host) { 498 ExtensionHost* host) {
460 if (!host) 499 if (!host)
461 return; // TODO(mpcomplete): notify source of disconnect? 500 return; // TODO(mpcomplete): notify source of disconnect?
462 501
463 // Re-lookup the source process since it may no longer be valid. 502 // Re-lookup the source process since it may no longer be valid.
464 OpenChannelParams params = params_in; 503 content::RenderProcessHost* source =
465 params.source = content::RenderProcessHost::FromID(source_process_id); 504 content::RenderProcessHost::FromID(source_process_id);
466 if (!params.source) 505 if (!source)
467 return; 506 return;
468 507
469 params.receiver = MessagePort(host->render_process_host(), 508 params->source = source;
470 MSG_ROUTING_CONTROL, 509 params->receiver.reset(new ExtensionMessagePort(host->render_process_host(),
471 params.target_extension_id); 510 MSG_ROUTING_CONTROL,
472 OpenChannelImpl(params); 511 params->target_extension_id));
512 OpenChannelImpl(params.Pass());
473 } 513 }
474 514
475 } // namespace extensions 515 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698