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 "base/scoped_observer.h" |
7 #include "chrome/browser/profiles/profile.h" | 8 #include "chrome/browser/profiles/profile.h" |
| 9 #include "content/public/browser/navigation_details.h" |
| 10 #include "content/public/browser/render_frame_host.h" |
8 #include "content/public/browser/render_process_host.h" | 11 #include "content/public/browser/render_process_host.h" |
| 12 #include "content/public/browser/web_contents.h" |
| 13 #include "content/public/browser/web_contents_observer.h" |
9 #include "extensions/browser/extension_host.h" | 14 #include "extensions/browser/extension_host.h" |
10 #include "extensions/browser/process_manager.h" | 15 #include "extensions/browser/process_manager.h" |
| 16 #include "extensions/browser/process_manager_observer.h" |
11 #include "extensions/common/extension_messages.h" | 17 #include "extensions/common/extension_messages.h" |
12 #include "extensions/common/manifest_handlers/background_info.h" | 18 #include "extensions/common/manifest_handlers/background_info.h" |
13 | 19 |
14 namespace extensions { | 20 namespace extensions { |
15 | 21 |
16 ExtensionMessagePort::ExtensionMessagePort(content::RenderProcessHost* process, | 22 const char kReceivingEndDoesntExistError[] = |
17 int routing_id, | 23 "Could not establish connection. Receiving end does not exist."; |
18 const std::string& extension_id) | 24 |
19 : process_(process), | 25 // Helper class to detect when frames are destroyed. |
20 routing_id_(routing_id), | 26 class ExtensionMessagePort::FrameTracker : public content::WebContentsObserver, |
21 extension_id_(extension_id), | 27 public ProcessManagerObserver { |
22 background_host_ptr_(NULL) { | 28 public: |
| 29 explicit FrameTracker(ExtensionMessagePort* port) |
| 30 : pm_observer_(this), port_(port) {} |
| 31 ~FrameTracker() override {} |
| 32 |
| 33 void TrackExtensionProcessFrames() { |
| 34 pm_observer_.Add(ProcessManager::Get(port_->browser_context_)); |
| 35 } |
| 36 |
| 37 void TrackTabFrames(content::WebContents* tab) { |
| 38 Observe(tab); |
| 39 } |
| 40 |
| 41 private: |
| 42 // content::WebContentsObserver overrides: |
| 43 void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) |
| 44 override { |
| 45 port_->UnregisterFrame(render_frame_host); |
| 46 } |
| 47 |
| 48 void DidNavigateAnyFrame(content::RenderFrameHost* render_frame_host, |
| 49 const content::LoadCommittedDetails& details, |
| 50 const content::FrameNavigateParams&) override { |
| 51 if (!details.is_in_page) |
| 52 port_->UnregisterFrame(render_frame_host); |
| 53 } |
| 54 |
| 55 // extensions::ProcessManagerObserver overrides: |
| 56 void OnExtensionFrameUnregistered( |
| 57 const std::string& extension_id, |
| 58 content::RenderFrameHost* render_frame_host) override { |
| 59 if (extension_id == port_->extension_id_) |
| 60 port_->UnregisterFrame(render_frame_host); |
| 61 } |
| 62 |
| 63 ScopedObserver<ProcessManager, ProcessManagerObserver> pm_observer_; |
| 64 ExtensionMessagePort* port_; // Owns this FrameTracker. |
| 65 |
| 66 DISALLOW_COPY_AND_ASSIGN(FrameTracker); |
| 67 }; |
| 68 |
| 69 ExtensionMessagePort::ExtensionMessagePort( |
| 70 base::WeakPtr<MessageService> message_service, |
| 71 int port_id, |
| 72 const std::string& extension_id, |
| 73 content::RenderProcessHost* extension_process) |
| 74 : weak_message_service_(message_service), |
| 75 port_id_(port_id), |
| 76 extension_id_(extension_id), |
| 77 browser_context_(extension_process->GetBrowserContext()), |
| 78 extension_process_(extension_process), |
| 79 frames_(ProcessManager::Get(browser_context_)-> |
| 80 GetRenderFrameHostsForExtension(extension_id)), |
| 81 did_create_port_(false), |
| 82 background_host_ptr_(nullptr), |
| 83 frame_tracker_(new FrameTracker(this)) { |
| 84 frame_tracker_->TrackExtensionProcessFrames(); |
| 85 } |
| 86 |
| 87 ExtensionMessagePort::ExtensionMessagePort( |
| 88 base::WeakPtr<MessageService> message_service, |
| 89 int port_id, |
| 90 const std::string& extension_id, |
| 91 content::RenderFrameHost* rfh, |
| 92 bool include_child_frames) |
| 93 : weak_message_service_(message_service), |
| 94 port_id_(port_id), |
| 95 extension_id_(extension_id), |
| 96 browser_context_(rfh->GetProcess()->GetBrowserContext()), |
| 97 extension_process_(nullptr), |
| 98 did_create_port_(false), |
| 99 background_host_ptr_(nullptr), |
| 100 frame_tracker_(new FrameTracker(this)) { |
| 101 content::WebContents* tab = content::WebContents::FromRenderFrameHost(rfh); |
| 102 DCHECK(tab); |
| 103 frame_tracker_->TrackTabFrames(tab); |
| 104 if (include_child_frames) { |
| 105 tab->ForEachFrame(base::Bind(&ExtensionMessagePort::RegisterFrame, |
| 106 base::Unretained(this))); |
| 107 } else { |
| 108 RegisterFrame(rfh); |
| 109 } |
| 110 } |
| 111 |
| 112 ExtensionMessagePort::~ExtensionMessagePort() {} |
| 113 |
| 114 bool ExtensionMessagePort::IsValidPort() { |
| 115 return !frames_.empty(); |
23 } | 116 } |
24 | 117 |
25 void ExtensionMessagePort::DispatchOnConnect( | 118 void ExtensionMessagePort::DispatchOnConnect( |
26 int dest_port_id, | |
27 const std::string& channel_name, | 119 const std::string& channel_name, |
28 scoped_ptr<base::DictionaryValue> source_tab, | 120 scoped_ptr<base::DictionaryValue> source_tab, |
29 int source_frame_id, | 121 int source_frame_id, |
30 int target_tab_id, | |
31 int target_frame_id, | |
32 int guest_process_id, | 122 int guest_process_id, |
33 int guest_render_frame_routing_id, | 123 int guest_render_frame_routing_id, |
34 const std::string& source_extension_id, | 124 const std::string& source_extension_id, |
35 const std::string& target_extension_id, | 125 const std::string& target_extension_id, |
36 const GURL& source_url, | 126 const GURL& source_url, |
37 const std::string& tls_channel_id) { | 127 const std::string& tls_channel_id) { |
38 ExtensionMsg_TabConnectionInfo source; | 128 ExtensionMsg_TabConnectionInfo source; |
39 if (source_tab) | 129 if (source_tab) |
40 source.tab.Swap(source_tab.get()); | 130 source.tab.Swap(source_tab.get()); |
41 source.frame_id = source_frame_id; | 131 source.frame_id = source_frame_id; |
42 | 132 |
43 ExtensionMsg_ExternalConnectionInfo info; | 133 ExtensionMsg_ExternalConnectionInfo info; |
44 info.target_id = target_extension_id; | 134 info.target_id = target_extension_id; |
45 info.source_id = source_extension_id; | 135 info.source_id = source_extension_id; |
46 info.source_url = source_url; | 136 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; | 137 info.guest_process_id = guest_process_id; |
50 info.guest_render_frame_routing_id = guest_render_frame_routing_id; | 138 info.guest_render_frame_routing_id = guest_render_frame_routing_id; |
51 | 139 |
52 process_->Send(new ExtensionMsg_DispatchOnConnect( | 140 SendToPort(make_scoped_ptr(new ExtensionMsg_DispatchOnConnect( |
53 routing_id_, dest_port_id, channel_name, source, info, tls_channel_id)); | 141 MSG_ROUTING_NONE, port_id_, channel_name, source, info, tls_channel_id))); |
54 } | 142 } |
55 | 143 |
56 void ExtensionMessagePort::DispatchOnDisconnect( | 144 void ExtensionMessagePort::DispatchOnDisconnect( |
57 int source_port_id, | |
58 const std::string& error_message) { | 145 const std::string& error_message) { |
59 process_->Send(new ExtensionMsg_DispatchOnDisconnect( | 146 SendToPort(make_scoped_ptr(new ExtensionMsg_DispatchOnDisconnect( |
60 routing_id_, source_port_id, error_message)); | 147 MSG_ROUTING_NONE, port_id_, error_message))); |
61 } | 148 } |
62 | 149 |
63 void ExtensionMessagePort::DispatchOnMessage(const Message& message, | 150 void ExtensionMessagePort::DispatchOnMessage(const Message& message) { |
64 int target_port_id) { | 151 SendToPort(make_scoped_ptr(new ExtensionMsg_DeliverMessage( |
65 process_->Send(new ExtensionMsg_DeliverMessage( | 152 MSG_ROUTING_NONE, port_id_, message))); |
66 routing_id_, target_port_id, message)); | |
67 } | 153 } |
68 | 154 |
69 void ExtensionMessagePort::IncrementLazyKeepaliveCount() { | 155 void ExtensionMessagePort::IncrementLazyKeepaliveCount() { |
70 Profile* profile = | 156 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_); | 157 ExtensionHost* host = pm->GetBackgroundHostForExtension(extension_id_); |
74 if (host && BackgroundInfo::HasLazyBackgroundPage(host->extension())) | 158 if (host && BackgroundInfo::HasLazyBackgroundPage(host->extension())) |
75 pm->IncrementLazyKeepaliveCount(host->extension()); | 159 pm->IncrementLazyKeepaliveCount(host->extension()); |
76 | 160 |
77 // Keep track of the background host, so when we decrement, we only do so if | 161 // Keep track of the background host, so when we decrement, we only do so if |
78 // the host hasn't reloaded. | 162 // the host hasn't reloaded. |
79 background_host_ptr_ = host; | 163 background_host_ptr_ = host; |
80 } | 164 } |
81 | 165 |
82 void ExtensionMessagePort::DecrementLazyKeepaliveCount() { | 166 void ExtensionMessagePort::DecrementLazyKeepaliveCount() { |
83 Profile* profile = | 167 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_); | 168 ExtensionHost* host = pm->GetBackgroundHostForExtension(extension_id_); |
87 if (host && host == background_host_ptr_) | 169 if (host && host == background_host_ptr_) |
88 pm->DecrementLazyKeepaliveCount(host->extension()); | 170 pm->DecrementLazyKeepaliveCount(host->extension()); |
89 } | 171 } |
90 | 172 |
91 content::RenderProcessHost* ExtensionMessagePort::GetRenderProcessHost() { | 173 void ExtensionMessagePort::OpenPort(int process_id, int routing_id) { |
92 return process_; | 174 DCHECK(routing_id != MSG_ROUTING_NONE || extension_process_); |
| 175 |
| 176 did_create_port_ = true; |
| 177 } |
| 178 |
| 179 void ExtensionMessagePort::ClosePort(int process_id, int routing_id) { |
| 180 if (routing_id == MSG_ROUTING_NONE) { |
| 181 // The only non-frame-specific message is the response to an unhandled |
| 182 // onConnect event in the extension process. |
| 183 DCHECK(extension_process_); |
| 184 frames_.clear(); |
| 185 CloseChannel(); |
| 186 return; |
| 187 } |
| 188 |
| 189 content::RenderFrameHost* rfh = |
| 190 content::RenderFrameHost::FromID(process_id, routing_id); |
| 191 if (rfh) |
| 192 UnregisterFrame(rfh); |
| 193 } |
| 194 |
| 195 void ExtensionMessagePort::CloseChannel() { |
| 196 std::string error_message = did_create_port_ ? std::string() : |
| 197 kReceivingEndDoesntExistError; |
| 198 if (weak_message_service_) |
| 199 weak_message_service_->CloseChannel(port_id_, error_message); |
| 200 } |
| 201 |
| 202 void ExtensionMessagePort::RegisterFrame(content::RenderFrameHost* rfh) { |
| 203 frames_.insert(rfh); |
| 204 } |
| 205 |
| 206 void ExtensionMessagePort::UnregisterFrame(content::RenderFrameHost* rfh) { |
| 207 if (frames_.erase(rfh) != 0 && frames_.empty()) |
| 208 CloseChannel(); |
| 209 } |
| 210 |
| 211 void ExtensionMessagePort::SendToPort(scoped_ptr<IPC::Message> msg) { |
| 212 DCHECK_GT(frames_.size(), 0UL); |
| 213 if (extension_process_) { |
| 214 // All extension frames reside in the same process, so we can just send a |
| 215 // single IPC message to the extension process as an optimization. |
| 216 // The frame tracking is then only used to make sure that the port gets |
| 217 // closed when all frames have closed / reloaded. |
| 218 msg->set_routing_id(MSG_ROUTING_CONTROL); |
| 219 extension_process_->Send(msg.release()); |
| 220 return; |
| 221 } |
| 222 for (content::RenderFrameHost* rfh : frames_) { |
| 223 IPC::Message* msg_copy = new IPC::Message(*msg.get()); |
| 224 msg_copy->set_routing_id(rfh->GetRoutingID()); |
| 225 rfh->Send(msg_copy); |
| 226 } |
93 } | 227 } |
94 | 228 |
95 } // namespace extensions | 229 } // namespace extensions |
OLD | NEW |