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/api/messaging/extension_message_port.h" | 5 #include "chrome/browser/extensions/api/messaging/extension_message_port.h" |
| 6 | 6 |
| 7 #include "chrome/browser/profiles/profile.h" | 7 #include "chrome/browser/profiles/profile.h" |
| 8 #include "content/public/browser/navigation_details.h" | |
| 9 #include "content/public/browser/render_frame_host.h" | |
| 8 #include "content/public/browser/render_process_host.h" | 10 #include "content/public/browser/render_process_host.h" |
| 11 #include "content/public/browser/web_contents.h" | |
| 12 #include "content/public/browser/web_contents_observer.h" | |
| 9 #include "extensions/browser/extension_host.h" | 13 #include "extensions/browser/extension_host.h" |
| 10 #include "extensions/browser/process_manager.h" | 14 #include "extensions/browser/process_manager.h" |
| 15 #include "extensions/browser/process_manager_observer.h" | |
| 11 #include "extensions/common/extension_messages.h" | 16 #include "extensions/common/extension_messages.h" |
| 12 #include "extensions/common/manifest_handlers/background_info.h" | 17 #include "extensions/common/manifest_handlers/background_info.h" |
| 13 | 18 |
| 14 namespace extensions { | 19 namespace extensions { |
| 15 | 20 |
| 16 ExtensionMessagePort::ExtensionMessagePort(content::RenderProcessHost* process, | 21 const char kReceivingEndDoesntExistError[] = |
| 17 int routing_id, | 22 "Could not establish connection. Receiving end does not exist."; |
| 18 const std::string& extension_id) | 23 |
| 19 : process_(process), | 24 // Helper class to detect when frames are destroyed. |
| 20 routing_id_(routing_id), | 25 class ExtensionMessagePort::FrameTracker : public content::WebContentsObserver, |
| 21 extension_id_(extension_id), | 26 public ProcessManagerObserver { |
| 22 background_host_ptr_(NULL) { | 27 public: |
| 28 // Watch all frames in an extension process. | |
| 29 explicit FrameTracker(ExtensionMessagePort* port) : port_(port) { | |
| 30 ProcessManager::Get(port_->browser_context_)->AddObserver(this); | |
| 31 } | |
| 32 // Watch all frames in a tab. | |
| 33 // TODO(robwu): Check whether this includes background pages and <webview>s. | |
| 34 FrameTracker(ExtensionMessagePort* port, content::WebContents* tab) | |
| 35 : content::WebContentsObserver(tab), port_(port) { | |
| 36 } | |
| 37 ~FrameTracker() override { | |
| 38 ProcessManager::Get(port_->browser_context_)->RemoveObserver(this); | |
| 39 } | |
|
Devlin
2015/10/30 01:49:39
nit: newline
robwu
2015/11/02 19:08:34
Done.
| |
| 40 private: | |
| 41 // content::WebContentsObserver overrides: | |
| 42 void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) | |
|
Devlin
2015/10/30 01:49:39
I would have thought FrameDeleted here - are you s
robwu
2015/10/31 00:10:45
I initially used FrameDeleted (as you can see in p
Devlin
2015/10/31 00:19:56
Interesting. I defer to Charlie's judgment for wh
Charlie Reis
2015/11/03 00:23:49
RenderFrameDeleted is for cases where you care whe
| |
| 43 override { | |
| 44 port_->UnregisterFrame(render_frame_host); | |
| 45 } | |
| 46 void DidNavigateAnyFrame(content::RenderFrameHost* render_frame_host, | |
| 47 const content::LoadCommittedDetails& details, | |
| 48 const content::FrameNavigateParams&) override { | |
| 49 if (!details.is_in_page) | |
| 50 port_->UnregisterFrame(render_frame_host); | |
| 51 } | |
| 52 | |
| 53 // extensions::ProcessManagerObserver overrides: | |
| 54 void OnExtensionFrameUnregistered( | |
| 55 const std::string& extension_id, | |
| 56 content::RenderFrameHost* render_frame_host) override { | |
| 57 if (extension_id == port_->extension_id_) | |
| 58 { | |
|
Devlin
2015/10/30 01:49:39
bracket
robwu
2015/11/02 19:08:33
Done.
| |
| 59 DVLOG(2) << "OnExtensionFrameUnregistered " << port_->port_id_ << " for " | |
|
Devlin
2015/10/30 01:49:39
We don't usually like to commit logs (even [D]VLOG
robwu
2015/10/31 00:10:45
Oops, I did not intend to commit this one. I usual
Devlin
2015/10/31 00:19:56
Probably all of them, but if there's one or two yo
robwu
2015/11/02 19:08:34
Done.
| |
| 60 << "frame " << render_frame_host << " " << " in extension " | |
| 61 << extension_id; | |
| 62 port_->UnregisterFrame(render_frame_host); | |
| 63 } | |
| 64 } | |
| 65 | |
| 66 ExtensionMessagePort* port_; | |
| 67 DISALLOW_COPY_AND_ASSIGN(FrameTracker); | |
| 68 }; | |
| 69 | |
| 70 ExtensionMessagePort::ExtensionMessagePort( | |
| 71 base::WeakPtr<MessageService> message_service, | |
| 72 int port_id, | |
| 73 const std::string& extension_id, | |
| 74 content::RenderProcessHost* extension_process) | |
| 75 : weak_message_service_(message_service), | |
| 76 port_id_(port_id), | |
| 77 extension_id_(extension_id), | |
| 78 did_create_port_(false), | |
| 79 browser_context_(extension_process->GetBrowserContext()), | |
| 80 frames_(ProcessManager::Get(browser_context_)-> | |
| 81 GetRenderFrameHostsForExtension(extension_id)), | |
| 82 extension_process_(extension_process), | |
| 83 background_host_ptr_(nullptr), | |
| 84 frame_tracker_(new FrameTracker(this)) { | |
| 85 DVLOG(2) << "Created ExtensionMessagePort " << port_id_ << " for extension " | |
| 86 << extension_id_ << " with " << frames_.size() << " frame(s)."; | |
| 87 } | |
| 88 | |
| 89 bool ExtensionMessagePort::IsValidPort() { | |
| 90 return !frames_.empty(); | |
| 91 } | |
| 92 | |
| 93 ExtensionMessagePort::ExtensionMessagePort( | |
| 94 base::WeakPtr<MessageService> message_service, | |
| 95 int port_id, | |
| 96 const std::string& extension_id, | |
| 97 content::RenderFrameHost* rfh, | |
| 98 bool include_child_frames) | |
| 99 : weak_message_service_(message_service), | |
| 100 port_id_(port_id), | |
| 101 extension_id_(extension_id), | |
| 102 did_create_port_(false), | |
| 103 browser_context_(rfh->GetProcess()->GetBrowserContext()), | |
| 104 frames_(), | |
| 105 extension_process_(nullptr), | |
| 106 background_host_ptr_(nullptr), | |
| 107 frame_tracker_() { | |
| 108 content::WebContents* tab = content::WebContents::FromRenderFrameHost(rfh); | |
| 109 DCHECK(tab); | |
| 110 frame_tracker_.reset(new FrameTracker(this, tab)); | |
| 111 if (include_child_frames) { | |
| 112 tab->ForEachFrame(base::Bind(&ExtensionMessagePort::RegisterFrame, | |
| 113 base::Unretained(this))); | |
| 114 } else { | |
| 115 RegisterFrame(rfh); | |
| 116 } | |
| 117 DVLOG(2) << "Created ExtensionMessagePort " << port_id_ << " for " | |
| 118 << frames_.size() << " frame(s)."; | |
| 119 } | |
| 120 | |
| 121 ExtensionMessagePort::~ExtensionMessagePort() { | |
| 122 frame_tracker_.reset(); | |
| 123 DVLOG(2) << "Destroyed ExtensionMessagePort " << port_id_; | |
| 23 } | 124 } |
| 24 | 125 |
| 25 void ExtensionMessagePort::DispatchOnConnect( | 126 void ExtensionMessagePort::DispatchOnConnect( |
| 26 int dest_port_id, | |
| 27 const std::string& channel_name, | 127 const std::string& channel_name, |
| 28 scoped_ptr<base::DictionaryValue> source_tab, | 128 scoped_ptr<base::DictionaryValue> source_tab, |
| 29 int source_frame_id, | 129 int source_frame_id, |
| 30 int target_tab_id, | |
| 31 int target_frame_id, | |
| 32 int guest_process_id, | 130 int guest_process_id, |
| 33 int guest_render_frame_routing_id, | 131 int guest_render_frame_routing_id, |
| 34 const std::string& source_extension_id, | 132 const std::string& source_extension_id, |
| 35 const std::string& target_extension_id, | 133 const std::string& target_extension_id, |
| 36 const GURL& source_url, | 134 const GURL& source_url, |
| 37 const std::string& tls_channel_id) { | 135 const std::string& tls_channel_id) { |
| 136 DVLOG(2) << "ExtensionMessagePort::DispatchOnConnect " << port_id_; | |
| 137 | |
| 38 ExtensionMsg_TabConnectionInfo source; | 138 ExtensionMsg_TabConnectionInfo source; |
| 39 if (source_tab) | 139 if (source_tab) |
| 40 source.tab.Swap(source_tab.get()); | 140 source.tab.Swap(source_tab.get()); |
| 41 source.frame_id = source_frame_id; | 141 source.frame_id = source_frame_id; |
| 42 | 142 |
| 43 ExtensionMsg_ExternalConnectionInfo info; | 143 ExtensionMsg_ExternalConnectionInfo info; |
| 44 info.target_id = target_extension_id; | 144 info.target_id = target_extension_id; |
| 45 info.source_id = source_extension_id; | 145 info.source_id = source_extension_id; |
| 46 info.source_url = source_url; | 146 info.source_url = source_url; |
| 47 info.target_tab_id = target_tab_id; | |
| 48 info.target_frame_id = target_frame_id; | |
| 49 info.guest_process_id = guest_process_id; | 147 info.guest_process_id = guest_process_id; |
| 50 info.guest_render_frame_routing_id = guest_render_frame_routing_id; | 148 info.guest_render_frame_routing_id = guest_render_frame_routing_id; |
| 51 | 149 |
| 52 process_->Send(new ExtensionMsg_DispatchOnConnect( | 150 SendToPort(new ExtensionMsg_DispatchOnConnect( |
| 53 routing_id_, dest_port_id, channel_name, source, info, tls_channel_id)); | 151 MSG_ROUTING_NONE, port_id_, channel_name, source, info, tls_channel_id)); |
| 54 } | 152 } |
| 55 | 153 |
| 56 void ExtensionMessagePort::DispatchOnDisconnect( | 154 void ExtensionMessagePort::DispatchOnDisconnect( |
| 57 int source_port_id, | |
| 58 const std::string& error_message) { | 155 const std::string& error_message) { |
| 59 process_->Send(new ExtensionMsg_DispatchOnDisconnect( | 156 DVLOG(2) << "ExtensionMessagePort::DispatchOnDisconnect " << port_id_; |
| 60 routing_id_, source_port_id, error_message)); | 157 |
| 158 SendToPort(new ExtensionMsg_DispatchOnDisconnect( | |
| 159 MSG_ROUTING_NONE, port_id_, error_message)); | |
| 61 } | 160 } |
| 62 | 161 |
| 63 void ExtensionMessagePort::DispatchOnMessage(const Message& message, | 162 void ExtensionMessagePort::DispatchOnMessage(const Message& message) { |
| 64 int target_port_id) { | 163 DVLOG(2) << "ExtensionMessagePort::DispatchOnMessage " << port_id_; |
| 65 process_->Send(new ExtensionMsg_DeliverMessage( | 164 |
| 66 routing_id_, target_port_id, message)); | 165 SendToPort(new ExtensionMsg_DeliverMessage( |
| 166 MSG_ROUTING_NONE, port_id_, message)); | |
| 67 } | 167 } |
| 68 | 168 |
| 69 void ExtensionMessagePort::IncrementLazyKeepaliveCount() { | 169 void ExtensionMessagePort::IncrementLazyKeepaliveCount() { |
| 70 Profile* profile = | 170 ProcessManager* pm = ProcessManager::Get(browser_context_); |
| 71 Profile::FromBrowserContext(process_->GetBrowserContext()); | |
| 72 extensions::ProcessManager* pm = ProcessManager::Get(profile); | |
| 73 ExtensionHost* host = pm->GetBackgroundHostForExtension(extension_id_); | 171 ExtensionHost* host = pm->GetBackgroundHostForExtension(extension_id_); |
| 74 if (host && BackgroundInfo::HasLazyBackgroundPage(host->extension())) | 172 if (host && BackgroundInfo::HasLazyBackgroundPage(host->extension())) |
| 75 pm->IncrementLazyKeepaliveCount(host->extension()); | 173 pm->IncrementLazyKeepaliveCount(host->extension()); |
| 76 | 174 |
| 77 // Keep track of the background host, so when we decrement, we only do so if | 175 // Keep track of the background host, so when we decrement, we only do so if |
| 78 // the host hasn't reloaded. | 176 // the host hasn't reloaded. |
| 79 background_host_ptr_ = host; | 177 background_host_ptr_ = host; |
| 80 } | 178 } |
| 81 | 179 |
| 82 void ExtensionMessagePort::DecrementLazyKeepaliveCount() { | 180 void ExtensionMessagePort::DecrementLazyKeepaliveCount() { |
| 83 Profile* profile = | 181 ProcessManager* pm = ProcessManager::Get(browser_context_); |
| 84 Profile::FromBrowserContext(process_->GetBrowserContext()); | |
| 85 extensions::ProcessManager* pm = ProcessManager::Get(profile); | |
| 86 ExtensionHost* host = pm->GetBackgroundHostForExtension(extension_id_); | 182 ExtensionHost* host = pm->GetBackgroundHostForExtension(extension_id_); |
| 87 if (host && host == background_host_ptr_) | 183 if (host && host == background_host_ptr_) |
| 88 pm->DecrementLazyKeepaliveCount(host->extension()); | 184 pm->DecrementLazyKeepaliveCount(host->extension()); |
| 89 } | 185 } |
| 90 | 186 |
| 91 content::RenderProcessHost* ExtensionMessagePort::GetRenderProcessHost() { | 187 void ExtensionMessagePort::OpenPort(int process_id, int routing_id) { |
| 92 return process_; | 188 DCHECK(routing_id != MSG_ROUTING_NONE || extension_process_); |
| 189 DVLOG_IF(2, !extension_process_) << "ExtensionMessagePort::OpenPort " | |
| 190 << port_id_ << " from frame " | |
| 191 << content::RenderFrameHost::FromID(process_id, routing_id); | |
| 192 DVLOG_IF(2, extension_process_) << "ExtensionMessagePort::OpenPort " | |
| 193 << port_id_ << " from extension " << extension_id_; | |
| 194 | |
| 195 // Mark port as active, so we can distinguish abnormal port closure from | |
| 196 // explicit port closure via disconnect(). | |
| 197 did_create_port_ = true; | |
| 198 } | |
| 199 | |
| 200 void ExtensionMessagePort::ClosePort(int process_id, int routing_id) { | |
| 201 if (routing_id == MSG_ROUTING_NONE) { | |
| 202 // The only non-frame-specific message is the response to an unhandled | |
| 203 // onConnect event in the extension process. | |
| 204 DCHECK(extension_process_); | |
| 205 DVLOG(2) << "ExtensionMessagePort::ClosePort " << port_id_ << " from " | |
| 206 << "extension " << extension_id_; | |
| 207 | |
| 208 frames_.clear(); | |
| 209 CloseChannel(); | |
| 210 return; | |
| 211 } | |
| 212 | |
| 213 content::RenderFrameHost* rfh = | |
| 214 content::RenderFrameHost::FromID(process_id, routing_id); | |
| 215 DVLOG(2) << "ExtensionMessagePort::ClosePort " << port_id_ << " for frame " | |
| 216 << rfh; | |
| 217 if (rfh) | |
| 218 UnregisterFrame(rfh); | |
| 219 } | |
| 220 | |
| 221 void ExtensionMessagePort::CloseChannel() { | |
| 222 DVLOG(2) << "ExtensionMessagePort::CloseChannel " << port_id_; | |
| 223 | |
| 224 std::string error_message = did_create_port_ ? std::string() : | |
| 225 kReceivingEndDoesntExistError; | |
| 226 if (weak_message_service_) | |
| 227 weak_message_service_->CloseChannel(port_id_, error_message); | |
| 228 } | |
| 229 | |
| 230 void ExtensionMessagePort::RegisterFrame(content::RenderFrameHost* rfh) { | |
| 231 frames_.insert(rfh); | |
| 232 } | |
| 233 | |
| 234 void ExtensionMessagePort::UnregisterFrame(content::RenderFrameHost* rfh) { | |
| 235 if (frames_.erase(rfh) != 0 && frames_.empty()) | |
| 236 CloseChannel(); | |
| 237 } | |
| 238 | |
| 239 void ExtensionMessagePort::SendToPort(IPC::Message* msg) { | |
| 240 DCHECK_GT(frames_.size(), 0UL); | |
| 241 if (extension_process_) { | |
| 242 msg->set_routing_id(MSG_ROUTING_CONTROL); | |
| 243 extension_process_->Send(msg); | |
| 244 return; | |
| 245 } | |
| 246 for (content::RenderFrameHost* rfh : frames_) { | |
| 247 IPC::Message* msg_copy = new IPC::Message(*msg); | |
| 248 msg_copy->set_routing_id(rfh->GetRoutingID()); | |
| 249 rfh->Send(msg_copy); | |
| 250 } | |
| 251 delete msg; | |
| 93 } | 252 } |
| 94 | 253 |
| 95 } // namespace extensions | 254 } // namespace extensions |
| OLD | NEW |