OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "extensions/browser/guest_view/web_view/web_view_content_script_manager .h" | |
6 | |
7 #include "base/lazy_instance.h" | |
8 #include "base/memory/linked_ptr.h" | |
9 #include "content/public/browser/browser_context.h" | |
10 #include "content/public/browser/browser_thread.h" | |
11 #include "content/public/browser/navigation_details.h" | |
12 #include "content/public/browser/render_process_host.h" | |
13 #include "content/public/browser/web_contents.h" | |
14 #include "content/public/browser/web_contents_observer.h" | |
15 #include "extensions/browser/declarative_user_script_manager.h" | |
16 #include "extensions/browser/declarative_user_script_master.h" | |
17 #include "extensions/browser/extension_system.h" | |
18 #include "extensions/browser/guest_view/guest_view_manager.h" | |
19 #include "extensions/browser/guest_view/web_view/web_view_constants.h" | |
20 #include "extensions/browser/guest_view/web_view/web_view_guest.h" | |
21 #include "extensions/browser/guest_view/web_view/web_view_renderer_state.h" | |
22 | |
23 using content::BrowserThread; | |
24 | |
25 namespace extensions { | |
26 | |
27 // This observer ensures that the content scripts added by the guest are removed | |
28 // when its embedder goes away. | |
29 // The OwnerWebContentsObserver object will be destroyed when the embedder web | |
30 // contents it observed is gone. | |
31 class WebViewContentScriptManager::OwnerWebContentsObserver | |
32 : public content::WebContentsObserver { | |
33 public: | |
34 OwnerWebContentsObserver(content::WebContents* embedder_web_contents, | |
35 const HostID& host_id, | |
36 WebViewContentScriptManager* manager) | |
37 : WebContentsObserver(embedder_web_contents), | |
38 host_id_(host_id), | |
39 web_view_content_script_manager_(manager) {} | |
40 ~OwnerWebContentsObserver() override {} | |
41 | |
42 // WebContentsObserver: | |
43 void WebContentsDestroyed() override { | |
44 // If the embedder is destroyed then remove all the content scripts of the | |
45 // guest. | |
46 RemoveContentScripts(); | |
47 } | |
48 void DidNavigateMainFrame( | |
49 const content::LoadCommittedDetails& details, | |
50 const content::FrameNavigateParams& params) override { | |
51 // If the embedder navigates to a different page then destroy the guest. | |
52 if (details.is_navigation_to_different_page()) | |
53 RemoveContentScripts(); | |
54 } | |
55 void RenderProcessGone(base::TerminationStatus status) override { | |
56 // If the embedder crashes, then destroy the guest. | |
57 RemoveContentScripts(); | |
58 } | |
59 | |
60 void add_view_instance_id(int view_instance_id) { | |
61 view_instance_ids_.push_back(view_instance_id); | |
62 } | |
63 | |
64 private: | |
65 void RemoveContentScripts() { | |
66 DCHECK(web_view_content_script_manager_); | |
67 | |
68 // Step 1: removes content scripts of all the guests embedded. | |
69 for (int view_instance_id : view_instance_ids_) { | |
70 web_view_content_script_manager_->RemoveContentScripts( | |
71 web_contents(), view_instance_id, host_id_, | |
72 std::vector<std::string>()); | |
73 } | |
74 // Step 2: removes this observer. | |
75 // This object can be deleted after this line. | |
76 web_view_content_script_manager_->RemoveObserver(web_contents()); | |
77 } | |
78 | |
79 HostID host_id_; | |
80 std::vector<int> view_instance_ids_; | |
Devlin
2015/04/14 23:04:57
This should be a set.
Xi Han
2015/04/15 19:43:55
Done.
| |
81 WebViewContentScriptManager* web_view_content_script_manager_; | |
82 | |
83 DISALLOW_COPY_AND_ASSIGN(OwnerWebContentsObserver); | |
84 }; | |
85 | |
86 WebViewContentScriptManager::WebViewContentScriptManager( | |
87 content::BrowserContext* browser_context) | |
88 : browser_context_(browser_context) { | |
89 } | |
90 | |
91 WebViewContentScriptManager::~WebViewContentScriptManager() { | |
92 } | |
93 | |
94 WebViewContentScriptManager* WebViewContentScriptManager::Get( | |
95 content::BrowserContext* browser_context) { | |
96 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
97 WebViewContentScriptManager* manager = | |
98 static_cast<WebViewContentScriptManager*>(browser_context->GetUserData( | |
99 webview::kWebViewContentScriptManagerKeyName)); | |
100 if (!manager) { | |
101 manager = new WebViewContentScriptManager(browser_context); | |
102 browser_context->SetUserData(webview::kWebViewContentScriptManagerKeyName, | |
103 manager); | |
104 } | |
105 return manager; | |
106 } | |
107 | |
108 void WebViewContentScriptManager::AddContentScripts( | |
109 content::WebContents* embedder_web_contents, | |
110 int view_instance_id, | |
111 const HostID& host_id, | |
112 const std::set<UserScript>& scripts) { | |
113 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
114 DCHECK(embedder_web_contents); | |
115 | |
116 DeclarativeUserScriptMaster* master = | |
117 ExtensionSystem::Get(browser_context_) | |
118 ->declarative_user_script_manager() | |
119 ->GetDeclarativeUserScriptMasterByID(host_id); | |
120 DCHECK(master); | |
121 | |
122 // We need to update WebViewRenderState in the IO thread if the guest exists. | |
123 std::set<int> ids_to_add; | |
124 | |
125 int embedder_process_id = | |
126 embedder_web_contents->GetRenderProcessHost()->GetID(); | |
127 GuestMapKey key = std::pair<int, int>(embedder_process_id, view_instance_id); | |
128 GuestContentScriptMap::iterator iter = guest_content_script_map_.find(key); | |
129 | |
130 // Step 1: finds the entry in guest_content_script_map_ by the given |key|. | |
131 // If there isn't any content script added for the given guest yet, insert an | |
132 // empty map first. | |
133 if (iter == guest_content_script_map_.end()) { | |
134 iter = guest_content_script_map_.insert( | |
135 iter, | |
136 std::pair<GuestMapKey, ContentScriptMap>(key, ContentScriptMap())); | |
137 } | |
138 | |
139 // Step 2: updates the guest_content_script_map_. | |
140 ContentScriptMap& map = iter->second; | |
141 for (const UserScript& script : scripts) { | |
142 auto map_iter = map.find(script.name()); | |
143 // If a content script has the same name as the new one, removes the old | |
Devlin
2015/04/14 23:04:57
s/removes/remove
Xi Han
2015/04/15 19:43:55
Done.
| |
144 // script first, and insert the new one. | |
145 if (map_iter != map.end()) { | |
146 master->RemoveScript(map_iter->second); | |
147 map.erase(map_iter); | |
148 } | |
149 map.insert(std::pair<std::string, UserScript>(script.name(), script)); | |
150 ids_to_add.insert(script.id()); | |
151 } | |
152 | |
153 // Step 3: adds new scripts to the master. | |
154 master->AddScripts(scripts); | |
155 | |
156 // Step 4: creates owner web contents observer for the given | |
157 // |embedder_web_contents| if it doesn't exist. | |
158 if (owner_web_contents_observer_map_.find(embedder_web_contents) == | |
159 owner_web_contents_observer_map_.end()) { | |
160 linked_ptr<OwnerWebContentsObserver> observer( | |
161 new OwnerWebContentsObserver(embedder_web_contents, host_id, this)); | |
162 observer->add_view_instance_id(view_instance_id); | |
Devlin
2015/04/14 23:04:57
Your if guard on line 158 means each observer will
Xi Han
2015/04/15 19:43:55
Great catch, it is a bug. Fixed.
| |
163 owner_web_contents_observer_map_[embedder_web_contents] = observer; | |
164 } | |
165 | |
166 // Step 5: updates WebViewRenderState in the IO thread. | |
167 // It is safe to use base::Unretained(WebViewRendererState::GetInstance()) | |
168 // since WebViewRendererState::GetInstance() always returns a Singleton of | |
169 // WebViewRendererState. | |
170 if (!ids_to_add.empty()) { | |
171 content::BrowserThread::PostTask( | |
172 content::BrowserThread::IO, FROM_HERE, | |
173 base::Bind(&WebViewRendererState::AddContentScriptIDs, | |
174 base::Unretained(WebViewRendererState::GetInstance()), | |
175 embedder_process_id, view_instance_id, ids_to_add)); | |
176 } | |
177 } | |
178 | |
179 void WebViewContentScriptManager::RemoveContentScripts( | |
180 content::WebContents* embedder_web_contents, | |
181 int view_instance_id, | |
182 const HostID& host_id, | |
183 const std::vector<std::string>& script_name_list) { | |
184 DCHECK_CURRENTLY_ON(BrowserThread::UI); | |
185 | |
186 int embedder_process_id = | |
187 embedder_web_contents->GetRenderProcessHost()->GetID(); | |
188 GuestMapKey key = std::pair<int, int>(embedder_process_id, view_instance_id); | |
189 GuestContentScriptMap::iterator script_map_iter = | |
190 guest_content_script_map_.find(key); | |
191 if (script_map_iter == guest_content_script_map_.end()) | |
192 return; | |
193 | |
194 DeclarativeUserScriptMaster* master = | |
195 ExtensionSystem::Get(browser_context_) | |
196 ->declarative_user_script_manager() | |
197 ->GetDeclarativeUserScriptMasterByID(host_id); | |
198 CHECK(master); | |
199 | |
200 // We need to update WebViewRenderState in the IO thread if the guest exists. | |
201 std::set<int> ids_to_delete; | |
202 | |
203 std::vector<std::string> names_to_delete; | |
204 | |
205 // Step 1: removes content scripts from |master| and updates | |
206 // |guest_content_script_map_| | |
207 std::map<std::string, UserScript>& map = script_map_iter->second; | |
208 // If the |script_name_list| is empty, all the content scripts added by the | |
209 // guest will be removed; otherwise, removes the scripts in the | |
210 // |script_name_list|. | |
211 if (script_name_list.empty()) { | |
212 for (const std::pair<std::string, UserScript>& iter : map) | |
213 names_to_delete.push_back(iter.first); | |
214 } else { | |
215 names_to_delete = script_name_list; | |
216 } | |
217 | |
218 std::set<UserScript> scripts_to_delete; | |
219 for (const std::string& name : names_to_delete) { | |
220 ContentScriptMap::iterator iter = map.find(name); | |
221 if (iter == map.end()) | |
222 continue; | |
223 const UserScript& script = iter->second; | |
224 ids_to_delete.insert(script.id()); | |
225 scripts_to_delete.insert(script); | |
226 map.erase(iter); | |
227 } | |
228 | |
229 // Step 2: removes content scripts from master. | |
230 master->RemoveScripts(scripts_to_delete); | |
231 | |
232 // Step 3: updates WebViewRenderState in the IO thread. | |
233 if (!ids_to_delete.empty()) { | |
234 content::BrowserThread::PostTask( | |
235 content::BrowserThread::IO, FROM_HERE, | |
236 base::Bind(&WebViewRendererState::RemoveContentScriptIDs, | |
237 base::Unretained(WebViewRendererState::GetInstance()), | |
238 embedder_process_id, view_instance_id, ids_to_delete)); | |
239 } | |
240 } | |
241 | |
242 void WebViewContentScriptManager::RemoveObserver( | |
243 content::WebContents* embedder_web_contents) { | |
244 owner_web_contents_observer_map_.erase(embedder_web_contents); | |
245 } | |
246 | |
247 std::set<int> WebViewContentScriptManager::GetContentScriptIDSet( | |
248 int embedder_process_id, | |
249 int view_instance_id) { | |
250 std::set<int> ids; | |
251 | |
252 GuestMapKey key = std::pair<int, int>(embedder_process_id, view_instance_id); | |
253 GuestContentScriptMap::const_iterator iter = | |
254 guest_content_script_map_.find(key); | |
255 if (iter == guest_content_script_map_.end()) | |
256 return ids; | |
257 const ContentScriptMap& map = iter->second; | |
258 for (const auto& pair : map) | |
259 ids.insert(pair.second.id()); | |
260 | |
261 return ids; | |
262 } | |
263 | |
264 } // namespace extensions | |
OLD | NEW |