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

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

Powered by Google App Engine
This is Rietveld 408576698