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

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

Issue 1413543005: Use FrameTreeNode ID as frameId in extension APIs (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Improve port lifetime management, add tests Created 5 years, 1 month 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/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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698