Don't show supervised user as "already on this device" while they're being imported.
[chromium-blink-merge.git] / extensions / browser / guest_view / web_view / web_view_content_script_manager.cc
blob24e4b7eba19dd26312287215818d688b3df19b89
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.
5 #include "extensions/browser/guest_view/web_view/web_view_content_script_manager.h"
7 #include "base/lazy_instance.h"
8 #include "base/memory/linked_ptr.h"
9 #include "components/guest_view/browser/guest_view_manager.h"
10 #include "content/public/browser/browser_context.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "content/public/browser/navigation_details.h"
13 #include "content/public/browser/render_process_host.h"
14 #include "content/public/browser/web_contents.h"
15 #include "content/public/browser/web_contents_observer.h"
16 #include "extensions/browser/declarative_user_script_manager.h"
17 #include "extensions/browser/declarative_user_script_master.h"
18 #include "extensions/browser/extension_system.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"
23 using content::BrowserThread;
25 namespace extensions {
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 {}
42 // WebContentsObserver:
43 void WebContentsDestroyed() override {
44 // If the embedder is destroyed then remove all the content scripts of the
45 // guest.
46 RemoveContentScripts();
48 void DidNavigateMainFrame(
49 const content::LoadCommittedDetails& details,
50 const content::FrameNavigateParams& params) override {
51 // If the embedder navigates to a different page then remove all the content
52 // scripts of the guest.
53 if (details.is_navigation_to_different_page())
54 RemoveContentScripts();
56 void RenderProcessGone(base::TerminationStatus status) override {
57 // If the embedder crashes, then remove all the content scripts of the
58 // guest.
59 RemoveContentScripts();
62 void add_view_instance_id(int view_instance_id) {
63 view_instance_ids_.insert(view_instance_id);
66 private:
67 void RemoveContentScripts() {
68 DCHECK(web_view_content_script_manager_);
70 // Step 1: removes content scripts of all the guests embedded.
71 for (int view_instance_id : view_instance_ids_) {
72 web_view_content_script_manager_->RemoveContentScripts(
73 web_contents(), view_instance_id, host_id_,
74 std::vector<std::string>());
76 // Step 2: removes this observer.
77 // This object can be deleted after this line.
78 web_view_content_script_manager_->RemoveObserver(web_contents());
81 HostID host_id_;
82 std::set<int> view_instance_ids_;
83 WebViewContentScriptManager* web_view_content_script_manager_;
85 DISALLOW_COPY_AND_ASSIGN(OwnerWebContentsObserver);
88 WebViewContentScriptManager::WebViewContentScriptManager(
89 content::BrowserContext* browser_context)
90 : user_script_loader_observer_(this), browser_context_(browser_context) {
93 WebViewContentScriptManager::~WebViewContentScriptManager() {
96 WebViewContentScriptManager* WebViewContentScriptManager::Get(
97 content::BrowserContext* browser_context) {
98 DCHECK_CURRENTLY_ON(BrowserThread::UI);
99 WebViewContentScriptManager* manager =
100 static_cast<WebViewContentScriptManager*>(browser_context->GetUserData(
101 webview::kWebViewContentScriptManagerKeyName));
102 if (!manager) {
103 manager = new WebViewContentScriptManager(browser_context);
104 browser_context->SetUserData(webview::kWebViewContentScriptManagerKeyName,
105 manager);
107 return manager;
110 void WebViewContentScriptManager::AddContentScripts(
111 content::WebContents* embedder_web_contents,
112 int embedder_routing_id,
113 int view_instance_id,
114 const HostID& host_id,
115 const std::set<UserScript>& scripts) {
116 DCHECK_CURRENTLY_ON(BrowserThread::UI);
117 DCHECK(embedder_web_contents);
119 DeclarativeUserScriptMaster* master =
120 DeclarativeUserScriptManager::Get(browser_context_)
121 ->GetDeclarativeUserScriptMasterByID(host_id);
122 DCHECK(master);
124 // We need to update WebViewRenderState in the IO thread if the guest exists.
125 std::set<int> ids_to_add;
127 int embedder_process_id =
128 embedder_web_contents->GetRenderProcessHost()->GetID();
129 GuestMapKey key = std::pair<int, int>(embedder_process_id, view_instance_id);
130 GuestContentScriptMap::iterator iter = guest_content_script_map_.find(key);
132 // Step 1: finds the entry in guest_content_script_map_ by the given |key|.
133 // If there isn't any content script added for the given guest yet, insert an
134 // empty map first.
135 if (iter == guest_content_script_map_.end()) {
136 iter = guest_content_script_map_.insert(
137 iter,
138 std::pair<GuestMapKey, ContentScriptMap>(key, ContentScriptMap()));
141 // Step 2: updates the guest_content_script_map_.
142 ContentScriptMap& map = iter->second;
143 std::set<UserScript> scripts_to_delete;
144 for (const UserScript& script : scripts) {
145 auto map_iter = map.find(script.name());
146 // If a content script has the same name as the new one, remove the old
147 // script first, and insert the new one.
148 if (map_iter != map.end()) {
149 scripts_to_delete.insert(map_iter->second);
150 map.erase(map_iter);
152 map.insert(std::pair<std::string, UserScript>(script.name(), script));
153 ids_to_add.insert(script.id());
156 if (!scripts_to_delete.empty()) {
157 master->RemoveScripts(scripts_to_delete);
160 // Step 3: makes WebViewContentScriptManager become an observer of the
161 // |loader| for scripts loaded event.
162 UserScriptLoader* loader = master->loader();
163 DCHECK(loader);
164 if (!user_script_loader_observer_.IsObserving(loader))
165 user_script_loader_observer_.Add(loader);
167 // Step 4: adds new scripts to the master.
168 master->AddScripts(scripts, embedder_process_id, embedder_routing_id);
170 // Step 5: creates owner web contents observer for the given
171 // |embedder_web_contents| if it doesn't exist.
172 auto observer_iter =
173 owner_web_contents_observer_map_.find(embedder_web_contents);
174 if (observer_iter == owner_web_contents_observer_map_.end()) {
175 linked_ptr<OwnerWebContentsObserver> observer(
176 new OwnerWebContentsObserver(embedder_web_contents, host_id, this));
177 observer->add_view_instance_id(view_instance_id);
178 owner_web_contents_observer_map_[embedder_web_contents] = observer;
179 } else {
180 observer_iter->second->add_view_instance_id(view_instance_id);
183 // Step 6: updates WebViewRenderState in the IO thread.
184 // It is safe to use base::Unretained(WebViewRendererState::GetInstance())
185 // since WebViewRendererState::GetInstance() always returns a Singleton of
186 // WebViewRendererState.
187 if (!ids_to_add.empty()) {
188 content::BrowserThread::PostTask(
189 content::BrowserThread::IO, FROM_HERE,
190 base::Bind(&WebViewRendererState::AddContentScriptIDs,
191 base::Unretained(WebViewRendererState::GetInstance()),
192 embedder_process_id, view_instance_id, ids_to_add));
196 void WebViewContentScriptManager::RemoveContentScripts(
197 content::WebContents* embedder_web_contents,
198 int view_instance_id,
199 const HostID& host_id,
200 const std::vector<std::string>& script_name_list) {
201 DCHECK_CURRENTLY_ON(BrowserThread::UI);
203 int embedder_process_id =
204 embedder_web_contents->GetRenderProcessHost()->GetID();
205 GuestMapKey key = std::pair<int, int>(embedder_process_id, view_instance_id);
206 GuestContentScriptMap::iterator script_map_iter =
207 guest_content_script_map_.find(key);
208 if (script_map_iter == guest_content_script_map_.end())
209 return;
211 DeclarativeUserScriptMaster* master =
212 DeclarativeUserScriptManager::Get(browser_context_)
213 ->GetDeclarativeUserScriptMasterByID(host_id);
214 CHECK(master);
216 // We need to update WebViewRenderState in the IO thread if the guest exists.
217 std::set<int> ids_to_delete;
218 std::set<UserScript> scripts_to_delete;
220 // Step 1: removes content scripts from |master| and updates
221 // |guest_content_script_map_|.
222 std::map<std::string, UserScript>& map = script_map_iter->second;
223 // If the |script_name_list| is empty, all the content scripts added by the
224 // guest will be removed; otherwise, removes the scripts in the
225 // |script_name_list|.
226 if (script_name_list.empty()) {
227 auto it = map.begin();
228 while (it != map.end()) {
229 scripts_to_delete.insert(it->second);
230 ids_to_delete.insert(it->second.id());
231 map.erase(it++);
233 } else {
234 for (const std::string& name : script_name_list) {
235 ContentScriptMap::iterator iter = map.find(name);
236 if (iter == map.end())
237 continue;
238 const UserScript& script = iter->second;
239 ids_to_delete.insert(script.id());
240 scripts_to_delete.insert(script);
241 map.erase(iter);
245 // Step 2: makes WebViewContentScriptManager become an observer of the
246 // |loader| for scripts loaded event.
247 UserScriptLoader* loader = master->loader();
248 DCHECK(loader);
249 if (!user_script_loader_observer_.IsObserving(loader))
250 user_script_loader_observer_.Add(loader);
252 // Step 3: removes content scripts from master.
253 master->RemoveScripts(scripts_to_delete);
255 // Step 4: updates WebViewRenderState in the IO thread.
256 if (!ids_to_delete.empty()) {
257 content::BrowserThread::PostTask(
258 content::BrowserThread::IO, FROM_HERE,
259 base::Bind(&WebViewRendererState::RemoveContentScriptIDs,
260 base::Unretained(WebViewRendererState::GetInstance()),
261 embedder_process_id, view_instance_id, ids_to_delete));
265 void WebViewContentScriptManager::RemoveObserver(
266 content::WebContents* embedder_web_contents) {
267 owner_web_contents_observer_map_.erase(embedder_web_contents);
270 std::set<int> WebViewContentScriptManager::GetContentScriptIDSet(
271 int embedder_process_id,
272 int view_instance_id) {
273 std::set<int> ids;
275 GuestMapKey key = std::pair<int, int>(embedder_process_id, view_instance_id);
276 GuestContentScriptMap::const_iterator iter =
277 guest_content_script_map_.find(key);
278 if (iter == guest_content_script_map_.end())
279 return ids;
280 const ContentScriptMap& map = iter->second;
281 for (const auto& pair : map)
282 ids.insert(pair.second.id());
284 return ids;
287 void WebViewContentScriptManager::SignalOnScriptsLoaded(
288 const base::Closure& callback) {
289 if (!user_script_loader_observer_.IsObservingSources()) {
290 callback.Run();
291 return;
293 pending_scripts_loading_callbacks_.push_back(callback);
296 void WebViewContentScriptManager::OnScriptsLoaded(UserScriptLoader* loader) {
297 user_script_loader_observer_.Remove(loader);
298 RunCallbacksIfReady();
301 void WebViewContentScriptManager::OnUserScriptLoaderDestroyed(
302 UserScriptLoader* loader) {
303 user_script_loader_observer_.Remove(loader);
304 RunCallbacksIfReady();
307 void WebViewContentScriptManager::RunCallbacksIfReady() {
308 if (user_script_loader_observer_.IsObservingSources())
309 return;
310 for (auto& callback : pending_scripts_loading_callbacks_)
311 callback.Run();
312 pending_scripts_loading_callbacks_.clear();
315 } // namespace extensions