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/render_frame_host.h" | |
8 #include "content/public/browser/render_process_host.h" | 9 #include "content/public/browser/render_process_host.h" |
10 #include "content/public/browser/web_contents.h" | |
11 #include "content/public/browser/web_contents_observer.h" | |
9 #include "extensions/browser/extension_host.h" | 12 #include "extensions/browser/extension_host.h" |
10 #include "extensions/browser/process_manager.h" | 13 #include "extensions/browser/process_manager.h" |
14 #include "extensions/browser/process_manager_observer.h" | |
11 #include "extensions/common/extension_messages.h" | 15 #include "extensions/common/extension_messages.h" |
12 #include "extensions/common/manifest_handlers/background_info.h" | 16 #include "extensions/common/manifest_handlers/background_info.h" |
13 | 17 |
14 namespace extensions { | 18 namespace extensions { |
15 | 19 |
16 ExtensionMessagePort::ExtensionMessagePort(content::RenderProcessHost* process, | 20 const char kReceivingEndDoesntExistError[] = |
17 int routing_id, | 21 "Could not establish connection. Receiving end does not exist."; |
18 const std::string& extension_id) | 22 |
19 : process_(process), | 23 // Helper class to detect when frames are destroyed. |
20 routing_id_(routing_id), | 24 class ExtensionMessagePort::FrameTracker : public content::WebContentsObserver, |
21 extension_id_(extension_id), | 25 public ProcessManagerObserver { |
22 background_host_ptr_(NULL) { | 26 public: |
27 // Watch all frames in an extension process. | |
28 explicit FrameTracker(ExtensionMessagePort* port) : port_(port) { | |
29 ProcessManager::Get(port_->browser_context_)->AddObserver(this); | |
Devlin
2015/10/30 01:49:39
nit: prefer scoped observer for usage like this.
robwu
2015/11/02 19:08:33
Done.
| |
30 } | |
31 // Watch all frames in a tab. | |
32 // TODO(robwu): Check whether this includes background pages and <webview>s. | |
33 FrameTracker(ExtensionMessagePort* port, content::WebContents* tab) | |
34 : content::WebContentsObserver(tab), port_(port) { | |
Devlin
2015/10/30 01:49:38
This doesn't observe the process manager. The com
robwu
2015/11/02 19:08:33
Done.
| |
35 } | |
36 ~FrameTracker() override { | |
37 ProcessManager::Get(port_->browser_context_)->RemoveObserver(this); | |
38 } | |
39 private: | |
40 // content::WebContentsObserver overrides: | |
41 void RenderFrameHostChanged(content::RenderFrameHost* old_host, | |
42 content::RenderFrameHost* new_host) override { | |
43 port_->UnregisterFrame(old_host); | |
44 } | |
45 void FrameDeleted(content::RenderFrameHost* render_frame_host) override { | |
46 port_->UnregisterFrame(render_frame_host); | |
47 } | |
48 | |
49 // extensions::ProcessManagerObserver overrides: | |
50 void OnExtensionFrameUnregistered( | |
51 const std::string& extension_id, | |
52 content::RenderFrameHost* render_frame_host) override { | |
53 if (extension_id == port_->extension_id_) | |
54 port_->UnregisterFrame(render_frame_host); | |
55 } | |
56 | |
57 ExtensionMessagePort* port_; | |
58 DISALLOW_COPY_AND_ASSIGN(FrameTracker); | |
59 }; | |
60 | |
61 ExtensionMessagePort::ExtensionMessagePort( | |
62 base::WeakPtr<MessageService> message_service, | |
63 int port_id, | |
64 const std::string& extension_id, | |
65 content::RenderProcessHost* extension_process) | |
66 : weak_message_service_(message_service), | |
67 port_id_(port_id), | |
68 extension_id_(extension_id), | |
69 did_create_port_(false), | |
70 browser_context_(extension_process->GetBrowserContext()), | |
71 frames_(ProcessManager::Get(browser_context_)-> | |
72 GetRenderFrameHostsForExtension(extension_id)), | |
73 extension_process_(extension_process), | |
74 background_host_ptr_(nullptr), | |
75 frame_tracker_(new FrameTracker(this)) { | |
76 } | |
77 | |
78 ExtensionMessagePort::ExtensionMessagePort( | |
79 base::WeakPtr<MessageService> message_service, | |
80 int port_id, | |
81 const std::string& extension_id, | |
82 content::RenderFrameHost* rfh, | |
83 bool include_child_frames) | |
84 : weak_message_service_(message_service), | |
85 port_id_(port_id), | |
86 extension_id_(extension_id), | |
87 did_create_port_(false), | |
88 browser_context_(rfh->GetProcess()->GetBrowserContext()), | |
89 frames_(), | |
90 extension_process_(nullptr), | |
91 background_host_ptr_(nullptr), | |
92 frame_tracker_() { | |
Devlin
2015/10/30 01:49:39
This will default-initialize itself; no need for t
robwu
2015/11/02 19:08:33
Acknowledged.
| |
93 content::WebContents* tab = content::WebContents::FromRenderFrameHost(rfh); | |
94 DCHECK(tab); | |
95 frame_tracker_.reset(new FrameTracker(this, tab)); | |
96 if (include_child_frames) { | |
97 tab->ForEachFrame(base::Bind(&ExtensionMessagePort::RegisterFrame, | |
98 base::Unretained(this))); | |
99 } else { | |
100 RegisterFrame(rfh); | |
101 } | |
102 } | |
103 | |
104 ExtensionMessagePort::~ExtensionMessagePort() { | |
105 frame_tracker_.reset(); | |
Devlin
2015/10/30 01:49:38
Why is the explicit destruction needed?
robwu
2015/11/02 19:08:33
It's not needed - removed.
| |
23 } | 106 } |
24 | 107 |
25 void ExtensionMessagePort::DispatchOnConnect( | 108 void ExtensionMessagePort::DispatchOnConnect( |
26 int dest_port_id, | |
27 const std::string& channel_name, | 109 const std::string& channel_name, |
28 scoped_ptr<base::DictionaryValue> source_tab, | 110 scoped_ptr<base::DictionaryValue> source_tab, |
29 int source_frame_id, | 111 int source_frame_id, |
30 int target_tab_id, | |
31 int target_frame_id, | |
32 int guest_process_id, | 112 int guest_process_id, |
33 int guest_render_frame_routing_id, | 113 int guest_render_frame_routing_id, |
34 const std::string& source_extension_id, | 114 const std::string& source_extension_id, |
35 const std::string& target_extension_id, | 115 const std::string& target_extension_id, |
36 const GURL& source_url, | 116 const GURL& source_url, |
37 const std::string& tls_channel_id) { | 117 const std::string& tls_channel_id) { |
38 ExtensionMsg_TabConnectionInfo source; | 118 ExtensionMsg_TabConnectionInfo source; |
39 if (source_tab) | 119 if (source_tab) |
40 source.tab.Swap(source_tab.get()); | 120 source.tab.Swap(source_tab.get()); |
41 source.frame_id = source_frame_id; | 121 source.frame_id = source_frame_id; |
42 | 122 |
43 ExtensionMsg_ExternalConnectionInfo info; | 123 ExtensionMsg_ExternalConnectionInfo info; |
44 info.target_id = target_extension_id; | 124 info.target_id = target_extension_id; |
45 info.source_id = source_extension_id; | 125 info.source_id = source_extension_id; |
46 info.source_url = source_url; | 126 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; | 127 info.guest_process_id = guest_process_id; |
50 info.guest_render_frame_routing_id = guest_render_frame_routing_id; | 128 info.guest_render_frame_routing_id = guest_render_frame_routing_id; |
51 | 129 |
52 process_->Send(new ExtensionMsg_DispatchOnConnect( | 130 SendToPort(new ExtensionMsg_DispatchOnConnect( |
53 routing_id_, dest_port_id, channel_name, source, info, tls_channel_id)); | 131 MSG_ROUTING_NONE, port_id_, channel_name, source, info, tls_channel_id)); |
54 } | 132 } |
55 | 133 |
56 void ExtensionMessagePort::DispatchOnDisconnect( | 134 void ExtensionMessagePort::DispatchOnDisconnect( |
57 int source_port_id, | |
58 const std::string& error_message) { | 135 const std::string& error_message) { |
59 process_->Send(new ExtensionMsg_DispatchOnDisconnect( | 136 SendToPort(new ExtensionMsg_DispatchOnDisconnect( |
60 routing_id_, source_port_id, error_message)); | 137 MSG_ROUTING_NONE, port_id_, error_message)); |
61 } | 138 } |
62 | 139 |
63 void ExtensionMessagePort::DispatchOnMessage(const Message& message, | 140 void ExtensionMessagePort::DispatchOnMessage(const Message& message) { |
64 int target_port_id) { | 141 SendToPort(new ExtensionMsg_DeliverMessage( |
65 process_->Send(new ExtensionMsg_DeliverMessage( | 142 MSG_ROUTING_NONE, port_id_, message)); |
66 routing_id_, target_port_id, message)); | |
67 } | 143 } |
68 | 144 |
69 void ExtensionMessagePort::IncrementLazyKeepaliveCount() { | 145 void ExtensionMessagePort::IncrementLazyKeepaliveCount() { |
70 Profile* profile = | 146 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_); | 147 ExtensionHost* host = pm->GetBackgroundHostForExtension(extension_id_); |
74 if (host && BackgroundInfo::HasLazyBackgroundPage(host->extension())) | 148 if (host && BackgroundInfo::HasLazyBackgroundPage(host->extension())) |
75 pm->IncrementLazyKeepaliveCount(host->extension()); | 149 pm->IncrementLazyKeepaliveCount(host->extension()); |
76 | 150 |
77 // Keep track of the background host, so when we decrement, we only do so if | 151 // Keep track of the background host, so when we decrement, we only do so if |
78 // the host hasn't reloaded. | 152 // the host hasn't reloaded. |
79 background_host_ptr_ = host; | 153 background_host_ptr_ = host; |
80 } | 154 } |
81 | 155 |
82 void ExtensionMessagePort::DecrementLazyKeepaliveCount() { | 156 void ExtensionMessagePort::DecrementLazyKeepaliveCount() { |
83 Profile* profile = | 157 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_); | 158 ExtensionHost* host = pm->GetBackgroundHostForExtension(extension_id_); |
87 if (host && host == background_host_ptr_) | 159 if (host && host == background_host_ptr_) |
88 pm->DecrementLazyKeepaliveCount(host->extension()); | 160 pm->DecrementLazyKeepaliveCount(host->extension()); |
89 } | 161 } |
90 | 162 |
91 content::RenderProcessHost* ExtensionMessagePort::GetRenderProcessHost() { | 163 void ExtensionMessagePort::OpenPort(int process_id, int routing_id) { |
92 return process_; | 164 // Mark port as active, so we can distinguish abnormal port closure from |
165 // explicit port closure via disconnect(). | |
166 did_create_port_ = true; | |
167 } | |
168 | |
169 void ExtensionMessagePort::ClosePort(int process_id, int routing_id) { | |
170 if (routing_id == MSG_ROUTING_NONE) { | |
171 // The only non-frame-specific message is the response to an unhandled | |
172 // onConnect event in the extension process. | |
173 DCHECK(extension_process_); | |
174 frames_.clear(); | |
175 CloseChannel(); | |
176 return; | |
177 } | |
178 content::RenderFrameHost* rfh = | |
179 content::RenderFrameHost::FromID(process_id, routing_id); | |
180 if (rfh) | |
181 UnregisterFrame(rfh); | |
182 } | |
183 | |
184 void ExtensionMessagePort::CloseChannel() { | |
185 std::string error_message = did_create_port_ ? std::string() : | |
186 kReceivingEndDoesntExistError; | |
187 if (weak_message_service_) | |
188 weak_message_service_->CloseChannel(port_id_, error_message); | |
189 } | |
190 | |
191 void ExtensionMessagePort::RegisterFrame(content::RenderFrameHost* rfh) { | |
192 frames_.insert(rfh); | |
193 } | |
194 | |
195 void ExtensionMessagePort::UnregisterFrame(content::RenderFrameHost* rfh) { | |
196 if (frames_.erase(rfh) != 0 && frames_.empty()) | |
197 CloseChannel(); | |
198 } | |
199 | |
200 void ExtensionMessagePort::SendToPort(IPC::Message* msg) { | |
201 if (extension_process_) { | |
202 msg->set_routing_id(MSG_ROUTING_CONTROL); | |
203 extension_process_->Send(msg); | |
204 return; | |
205 } | |
206 for (content::RenderFrameHost* rfh : frames_) { | |
Devlin
2015/10/30 01:49:39
Hmm... This is a bit confusing, because of the way
robwu
2015/10/31 00:10:44
|frames_| is used to avoid unnecessary IPC, since
Devlin
2015/10/31 00:19:56
What about extension iframes in web pages without
robwu
2015/11/02 19:08:33
Extension iframes currently don't have any access
| |
207 IPC::Message* msg_copy = new IPC::Message(*msg); | |
208 msg_copy->set_routing_id(rfh->GetRoutingID()); | |
209 rfh->Send(msg_copy); | |
210 } | |
211 delete msg; | |
93 } | 212 } |
94 | 213 |
95 } // namespace extensions | 214 } // namespace extensions |
OLD | NEW |