Chromium Code Reviews| OLD | NEW |
|---|---|
| 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/message_service.h" | 5 #include "chrome/browser/extensions/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/extension_host.h" | 13 #include "chrome/browser/extensions/extension_host.h" |
| 14 #include "chrome/browser/extensions/extension_process_manager.h" | 14 #include "chrome/browser/extensions/extension_process_manager.h" |
| 15 #include "chrome/browser/extensions/extension_service.h" | 15 #include "chrome/browser/extensions/extension_service.h" |
| 16 #include "chrome/browser/extensions/extension_system.h" | 16 #include "chrome/browser/extensions/extension_system.h" |
| 17 #include "chrome/browser/extensions/extension_tab_util.h" | 17 #include "chrome/browser/extensions/extension_tab_util.h" |
| 18 #include "chrome/browser/extensions/lazy_background_task_queue.h" | 18 #include "chrome/browser/extensions/lazy_background_task_queue.h" |
| 19 #include "chrome/browser/extensions/native_message_process.h" | |
| 19 #include "chrome/browser/extensions/process_map.h" | 20 #include "chrome/browser/extensions/process_map.h" |
| 20 #include "chrome/browser/profiles/profile.h" | 21 #include "chrome/browser/profiles/profile.h" |
| 21 #include "chrome/browser/tab_contents/tab_util.h" | 22 #include "chrome/browser/tab_contents/tab_util.h" |
| 22 #include "chrome/browser/ui/tab_contents/tab_contents.h" | 23 #include "chrome/browser/ui/tab_contents/tab_contents.h" |
| 23 #include "chrome/common/chrome_notification_types.h" | 24 #include "chrome/common/chrome_notification_types.h" |
| 24 #include "chrome/common/extensions/extension.h" | 25 #include "chrome/common/extensions/extension.h" |
| 25 #include "chrome/common/extensions/extension_messages.h" | 26 #include "chrome/common/extensions/extension_messages.h" |
| 26 #include "chrome/common/view_type.h" | 27 #include "chrome/common/view_type.h" |
| 28 #include "content/public/browser/browser_thread.h" | |
| 27 #include "content/public/browser/notification_service.h" | 29 #include "content/public/browser/notification_service.h" |
| 28 #include "content/public/browser/render_process_host.h" | 30 #include "content/public/browser/render_process_host.h" |
| 29 #include "content/public/browser/render_view_host.h" | 31 #include "content/public/browser/render_view_host.h" |
| 30 #include "content/public/browser/site_instance.h" | 32 #include "content/public/browser/site_instance.h" |
| 31 #include "content/public/browser/web_contents.h" | 33 #include "content/public/browser/web_contents.h" |
| 32 | 34 |
| 33 using content::SiteInstance; | 35 using content::SiteInstance; |
| 34 using content::WebContents; | 36 using content::WebContents; |
| 35 | 37 |
| 36 // Since we have 2 ports for every channel, we just index channels by half the | 38 // Since we have 2 ports for every channel, we just index channels by half the |
| 37 // port ID. | 39 // port ID. |
| 38 #define GET_CHANNEL_ID(port_id) ((port_id) / 2) | 40 #define GET_CHANNEL_ID(port_id) ((port_id) / 2) |
| 39 #define GET_CHANNEL_OPENER_ID(channel_id) ((channel_id) * 2) | 41 #define GET_CHANNEL_OPENER_ID(channel_id) ((channel_id) * 2) |
| 40 #define GET_CHANNEL_RECEIVERS_ID(channel_id) ((channel_id) * 2 + 1) | 42 #define GET_CHANNEL_RECEIVERS_ID(channel_id) ((channel_id) * 2 + 1) |
| 41 | 43 |
| 42 // Port1 is always even, port2 is always odd. | 44 // Port1 is always even, port2 is always odd. |
| 43 #define IS_OPENER_PORT_ID(port_id) (((port_id) & 1) == 0) | 45 #define IS_OPENER_PORT_ID(port_id) (((port_id) & 1) == 0) |
| 44 | 46 |
| 45 // Change even to odd and vice versa, to get the other side of a given channel. | 47 // 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) | 48 #define GET_OPPOSITE_PORT_ID(source_port_id) ((source_port_id) ^ 1) |
| 47 | 49 |
| 48 namespace extensions { | 50 namespace extensions { |
| 49 | 51 |
| 50 struct MessageService::MessagePort { | 52 struct MessageService::MessagePort { |
|
Matt Perry
2012/08/09 02:13:00
maybe we should turn this into an interface that d
Aaron Boodman
2012/08/09 18:36:12
/me is shocked to here mpcomplete say 'interface'.
eaugusti
2012/08/13 23:22:34
Done.
| |
| 51 content::RenderProcessHost* process; | 53 content::RenderProcessHost* process; |
| 52 int routing_id; | 54 int routing_id; |
| 53 std::string extension_id; | 55 std::string extension_id; |
| 54 void* background_host_ptr; // used in IncrementLazyKeepaliveCount | 56 void* background_host_ptr; // used in IncrementLazyKeepaliveCount |
| 57 // HACK(eriq) | |
| 58 bool is_native; | |
| 59 linked_ptr<NativeMessageProcess> native_process; | |
|
Aaron Boodman
2012/08/09 18:36:12
linked_ptr here is unfortunate, as it makes the li
eaugusti
2012/08/13 23:22:34
Will now be a raw pointer.
| |
| 55 | 60 |
| 56 MessagePort() | 61 MessagePort() |
| 57 : process(NULL), | 62 : process(NULL), |
| 58 routing_id(MSG_ROUTING_CONTROL), | 63 routing_id(MSG_ROUTING_CONTROL), |
| 59 background_host_ptr(NULL) {} | 64 background_host_ptr(NULL), |
| 65 is_native(false) {} | |
| 60 MessagePort(content::RenderProcessHost* process, | 66 MessagePort(content::RenderProcessHost* process, |
| 61 int routing_id, | 67 int routing_id, |
| 62 const std::string& extension_id) | 68 const std::string& extension_id) |
| 63 : process(process), | 69 : process(process), |
| 64 routing_id(routing_id), | 70 routing_id(routing_id), |
| 65 extension_id(extension_id), | 71 extension_id(extension_id), |
| 66 background_host_ptr(NULL) {} | 72 background_host_ptr(NULL), |
| 73 is_native(false) {} | |
| 67 }; | 74 }; |
| 68 | 75 |
| 69 struct MessageService::MessageChannel { | 76 struct MessageService::MessageChannel { |
| 70 MessageService::MessagePort opener; | 77 MessageService::MessagePort opener; |
| 71 MessageService::MessagePort receiver; | 78 MessageService::MessagePort receiver; |
| 72 }; | 79 }; |
| 73 | 80 |
| 74 struct MessageService::OpenChannelParams { | 81 struct MessageService::OpenChannelParams { |
| 75 content::RenderProcessHost* source; | 82 content::RenderProcessHost* source; |
| 76 std::string tab_json; | 83 std::string tab_json; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 114 static void DispatchOnDisconnect(const MessageService::MessagePort& port, | 121 static void DispatchOnDisconnect(const MessageService::MessagePort& port, |
| 115 int source_port_id, | 122 int source_port_id, |
| 116 bool connection_error) { | 123 bool connection_error) { |
| 117 port.process->Send(new ExtensionMsg_DispatchOnDisconnect( | 124 port.process->Send(new ExtensionMsg_DispatchOnDisconnect( |
| 118 port.routing_id, source_port_id, connection_error)); | 125 port.routing_id, source_port_id, connection_error)); |
| 119 } | 126 } |
| 120 | 127 |
| 121 static void DispatchOnMessage(const MessageService::MessagePort& port, | 128 static void DispatchOnMessage(const MessageService::MessagePort& port, |
| 122 const std::string& message, | 129 const std::string& message, |
| 123 int target_port_id) { | 130 int target_port_id) { |
| 124 port.process->Send(new ExtensionMsg_DeliverMessage( | 131 if (port.is_native) { |
| 125 port.routing_id, target_port_id, message)); | 132 port.native_process->Send(message); |
| 133 } else { | |
| 134 port.process->Send(new ExtensionMsg_DeliverMessage( | |
| 135 port.routing_id, target_port_id, message)); | |
| 136 } | |
| 126 } | 137 } |
| 127 | 138 |
| 128 static content::RenderProcessHost* GetExtensionProcess( | 139 static content::RenderProcessHost* GetExtensionProcess( |
| 129 Profile* profile, const std::string& extension_id) { | 140 Profile* profile, const std::string& extension_id) { |
| 130 SiteInstance* site_instance = | 141 SiteInstance* site_instance = |
| 131 profile->GetExtensionProcessManager()->GetSiteInstanceForURL( | 142 profile->GetExtensionProcessManager()->GetSiteInstanceForURL( |
| 132 Extension::GetBaseURLFromExtensionId(extension_id)); | 143 Extension::GetBaseURLFromExtensionId(extension_id)); |
| 133 | 144 |
| 134 if (!site_instance->HasProcess()) | 145 if (!site_instance->HasProcess()) |
| 135 return NULL; | 146 return NULL; |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 230 | 241 |
| 231 // The target might be a lazy background page. In that case, we have to check | 242 // 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 | 243 // if it is loaded and ready, and if not, queue up the task and load the |
| 233 // page. | 244 // page. |
| 234 if (MaybeAddPendingOpenChannelTask(profile, params)) | 245 if (MaybeAddPendingOpenChannelTask(profile, params)) |
| 235 return; | 246 return; |
| 236 | 247 |
| 237 OpenChannelImpl(params); | 248 OpenChannelImpl(params); |
| 238 } | 249 } |
| 239 | 250 |
| 251 void MessageService::OpenChannelToNativeApp( | |
| 252 int source_process_id, | |
| 253 int source_routing_id, | |
| 254 int receiver_port_id, | |
| 255 const std::string& source_extension_id, | |
| 256 const std::string& native_app_name, | |
| 257 const std::string& channel_name, | |
| 258 const std::string& connect_message) { | |
| 259 content::RenderProcessHost* source = | |
| 260 content::RenderProcessHost::FromID(source_process_id); | |
| 261 if (!source) | |
| 262 return; | |
| 263 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext()); | |
| 264 | |
| 265 // Note: we use the source's profile here. If the source is an incognito | |
| 266 // process, we will use the incognito EPM to find the right extension process, | |
| 267 // which depends on whether the extension uses spanning or split mode. | |
| 268 MessagePort receiver(GetExtensionProcess(profile, source_extension_id), | |
|
Matt Perry
2012/08/09 02:13:00
The receiver is the target of the connect event -
eaugusti
2012/08/13 23:22:34
Done.
| |
| 269 MSG_ROUTING_CONTROL, | |
| 270 "native"); | |
| 271 WebContents* source_contents = tab_util::GetWebContentsByID( | |
| 272 source_process_id, source_routing_id); | |
| 273 | |
| 274 // Include info about the opener's tab (if it was a tab). | |
| 275 std::string tab_json = "null"; | |
| 276 if (source_contents) { | |
| 277 scoped_ptr<DictionaryValue> tab_value( | |
| 278 ExtensionTabUtil::CreateTabValue(source_contents)); | |
| 279 base::JSONWriter::Write(tab_value.get(), &tab_json); | |
| 280 } | |
| 281 | |
| 282 MessageChannel* channel(new MessageChannel); | |
| 283 channel->opener = MessagePort(source, MSG_ROUTING_CONTROL, | |
| 284 source_extension_id); | |
| 285 channel->receiver = receiver; | |
| 286 | |
| 287 content::BrowserThread::PostTask( | |
| 288 content::BrowserThread::FILE, | |
| 289 FROM_HERE, | |
| 290 base::Bind(&MessageService::OpenChannelToNativeAppOnFileThread, | |
| 291 base::Unretained(this), | |
| 292 receiver_port_id, | |
| 293 native_app_name, | |
| 294 channel_name, | |
| 295 connect_message, | |
| 296 channel, | |
| 297 tab_json)); | |
| 298 | |
| 299 // TODO(eriq): This should actually be called after the channel is opened | |
| 300 // successfully. | |
| 301 IncrementLazyKeepaliveCount(&channel->opener); | |
| 302 } | |
| 303 | |
| 304 void MessageService::OpenChannelToNativeAppOnFileThread( | |
|
Matt Perry
2012/08/09 02:13:00
This class is not threadsafe. Same goes for |chann
eaugusti
2012/08/13 23:22:34
Done.
| |
| 305 int receiver_port_id, | |
| 306 const std::string& native_app_name, | |
| 307 const std::string& channel_name, | |
| 308 const std::string& connect_message, | |
| 309 MessageChannel* channel, | |
| 310 const std::string& tab_json) { | |
| 311 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::FILE)); | |
| 312 | |
| 313 NativeMessageProcess::MessageType type = NativeMessageProcess::TYPE_CONNECT; | |
| 314 if (channel_name == "chrome.extension.sendNativeMessage") | |
| 315 type = NativeMessageProcess::TYPE_SEND_MESSAGE_REQUEST; | |
| 316 | |
| 317 NativeMessageProcess* native_process = NativeMessageProcess::Create( | |
| 318 native_app_name, connect_message, this, receiver_port_id, type); | |
|
Matt Perry
2012/08/09 02:13:00
What if an extension opens 2 channels to the same
Aaron Boodman
2012/08/09 18:36:12
I think we should just create two. The extension s
eaugusti
2012/08/13 23:22:34
I agree with spawning multiple processes, the nati
| |
| 319 if (!native_process) { | |
| 320 LOG(ERROR) << "Failed to create native process."; | |
| 321 return; | |
| 322 } | |
| 323 channel->receiver.is_native = true; | |
| 324 channel->receiver.native_process.reset(native_process); | |
| 325 | |
| 326 int channel_id = GET_CHANNEL_ID(receiver_port_id); | |
| 327 CHECK(channels_.find(channel_id) == channels_.end()); | |
| 328 channels_[channel_id] = channel; | |
| 329 pending_channels_.erase(channel_id); | |
| 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 DispatchOnConnect(channel->receiver, receiver_port_id, | |
|
Matt Perry
2012/08/09 02:13:00
I don't think this call makes sense. You're dispat
eaugusti
2012/08/13 23:22:34
You're right, it doesn't make sense.
| |
| 334 channel_name, tab_json, | |
| 335 channel->opener.extension_id, "native"); | |
| 336 } | |
| 337 | |
| 240 void MessageService::OpenChannelToTab( | 338 void MessageService::OpenChannelToTab( |
| 241 int source_process_id, int source_routing_id, int receiver_port_id, | 339 int source_process_id, int source_routing_id, int receiver_port_id, |
| 242 int tab_id, const std::string& extension_id, | 340 int tab_id, const std::string& extension_id, |
| 243 const std::string& channel_name) { | 341 const std::string& channel_name) { |
| 244 content::RenderProcessHost* source = | 342 content::RenderProcessHost* source = |
| 245 content::RenderProcessHost::FromID(source_process_id); | 343 content::RenderProcessHost::FromID(source_process_id); |
| 246 if (!source) | 344 if (!source) |
| 247 return; | 345 return; |
| 248 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext()); | 346 Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext()); |
| 249 | 347 |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 341 | 439 |
| 342 void MessageService::CloseChannelImpl( | 440 void MessageService::CloseChannelImpl( |
| 343 MessageChannelMap::iterator channel_iter, int closing_port_id, | 441 MessageChannelMap::iterator channel_iter, int closing_port_id, |
| 344 bool connection_error, bool notify_other_port) { | 442 bool connection_error, bool notify_other_port) { |
| 345 MessageChannel* channel = channel_iter->second; | 443 MessageChannel* channel = channel_iter->second; |
| 346 | 444 |
| 347 // Notify the other side. | 445 // Notify the other side. |
| 348 if (notify_other_port) { | 446 if (notify_other_port) { |
| 349 const MessagePort& port = IS_OPENER_PORT_ID(closing_port_id) ? | 447 const MessagePort& port = IS_OPENER_PORT_ID(closing_port_id) ? |
| 350 channel->receiver : channel->opener; | 448 channel->receiver : channel->opener; |
| 351 DispatchOnDisconnect(port, GET_OPPOSITE_PORT_ID(closing_port_id), | 449 |
| 352 connection_error); | 450 if (!port.is_native) { |
| 451 DispatchOnDisconnect(port, GET_OPPOSITE_PORT_ID(closing_port_id), | |
| 452 connection_error); | |
| 453 } | |
| 353 } | 454 } |
| 354 | 455 |
| 355 // Balance the addrefs in OpenChannelImpl. | 456 // Balance the addrefs in OpenChannelImpl. |
| 356 DecrementLazyKeepaliveCount(&channel->opener); | 457 DecrementLazyKeepaliveCount(&channel->opener); |
| 357 DecrementLazyKeepaliveCount(&channel->receiver); | 458 // The reciever may be native. |
| 459 if (!channel->receiver.is_native) { | |
| 460 DecrementLazyKeepaliveCount(&channel->receiver); | |
| 461 } | |
| 358 | 462 |
| 359 delete channel_iter->second; | 463 delete channel_iter->second; |
| 360 channels_.erase(channel_iter); | 464 channels_.erase(channel_iter); |
| 361 } | 465 } |
| 362 | 466 |
| 363 void MessageService::PostMessageFromRenderer( | 467 void MessageService::PostMessageFromRenderer( |
| 364 int source_port_id, const std::string& message) { | 468 int source_port_id, const std::string& message) { |
| 365 int channel_id = GET_CHANNEL_ID(source_port_id); | 469 int channel_id = GET_CHANNEL_ID(source_port_id); |
| 366 MessageChannelMap::iterator iter = channels_.find(channel_id); | 470 MessageChannelMap::iterator iter = channels_.find(channel_id); |
| 367 if (iter == channels_.end()) { | 471 if (iter == channels_.end()) { |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 462 if (!params.source) | 566 if (!params.source) |
| 463 return; | 567 return; |
| 464 | 568 |
| 465 params.receiver = MessagePort(host->render_process_host(), | 569 params.receiver = MessagePort(host->render_process_host(), |
| 466 MSG_ROUTING_CONTROL, | 570 MSG_ROUTING_CONTROL, |
| 467 params.target_extension_id); | 571 params.target_extension_id); |
| 468 OpenChannelImpl(params); | 572 OpenChannelImpl(params); |
| 469 } | 573 } |
| 470 | 574 |
| 471 } // namespace extensions | 575 } // namespace extensions |
| OLD | NEW |