OLD | NEW |
---|---|
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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/chromeos/accessibility/accessibility_extension_loader.h " | 5 #include "chrome/browser/chromeos/accessibility/accessibility_extension_loader.h " |
6 | 6 |
7 #include "base/callback.h" | 7 #include "base/callback.h" |
8 #include "base/callback_helpers.h" | |
9 #include "base/path_service.h" | |
10 #include "chrome/browser/chromeos/login/lock/screen_locker.h" | |
11 #include "chrome/browser/chromeos/login/lock/webui_screen_locker.h" | |
12 #include "chrome/browser/chromeos/login/ui/login_display_host.h" | |
13 #include "chrome/browser/chromeos/login/ui/webui_login_view.h" | |
14 #include "chrome/browser/chromeos/profiles/profile_helper.h" | 8 #include "chrome/browser/chromeos/profiles/profile_helper.h" |
15 #include "chrome/browser/extensions/component_loader.h" | 9 #include "chrome/browser/extensions/component_loader.h" |
16 #include "chrome/browser/extensions/extension_service.h" | 10 #include "chrome/browser/extensions/extension_service.h" |
17 #include "chrome/browser/extensions/tab_helper.h" | |
18 #include "chrome/browser/profiles/profile.h" | 11 #include "chrome/browser/profiles/profile.h" |
19 #include "chrome/common/extensions/extension_constants.h" | |
20 #include "chrome/common/extensions/manifest_handlers/content_scripts_handler.h" | |
21 #include "content/public/browser/render_process_host.h" | |
22 #include "content/public/browser/render_view_host.h" | |
23 #include "content/public/browser/web_contents.h" | |
24 #include "extensions/browser/extension_api_frame_id_map.h" | |
25 #include "extensions/browser/extension_registry.h" | |
26 #include "extensions/browser/extension_system.h" | 12 #include "extensions/browser/extension_system.h" |
27 #include "extensions/browser/file_reader.h" | |
28 #include "extensions/browser/script_executor.h" | |
29 #include "extensions/common/extension.h" | |
30 #include "extensions/common/extension_messages.h" | |
31 #include "extensions/common/extension_resource.h" | |
32 | 13 |
33 namespace chromeos { | 14 namespace chromeos { |
34 | 15 |
35 namespace { | |
36 | |
37 // Uses the ScriptExecutor associated with the given |render_view_host| to | |
38 // execute the given |code|. | |
39 void ExecuteScriptHelper(content::RenderViewHost* render_view_host, | |
40 const std::string& code, | |
41 const std::string& extension_id) { | |
42 content::WebContents* web_contents = | |
43 content::WebContents::FromRenderViewHost(render_view_host); | |
44 if (!web_contents) | |
45 return; | |
46 if (!extensions::TabHelper::FromWebContents(web_contents)) | |
47 extensions::TabHelper::CreateForWebContents(web_contents); | |
48 extensions::TabHelper::FromWebContents(web_contents) | |
49 ->script_executor() | |
50 ->ExecuteScript(HostID(HostID::EXTENSIONS, extension_id), | |
51 extensions::ScriptExecutor::JAVASCRIPT, code, | |
52 extensions::ScriptExecutor::INCLUDE_SUB_FRAMES, | |
53 extensions::ExtensionApiFrameIdMap::kTopFrameId, | |
54 extensions::ScriptExecutor::DONT_MATCH_ABOUT_BLANK, | |
55 extensions::UserScript::DOCUMENT_IDLE, | |
56 extensions::ScriptExecutor::ISOLATED_WORLD, | |
57 extensions::ScriptExecutor::DEFAULT_PROCESS, | |
58 GURL(), // No webview src. | |
59 GURL(), // No file url. | |
60 false, // Not user gesture. | |
61 extensions::ScriptExecutor::NO_RESULT, | |
62 extensions::ScriptExecutor::ExecuteScriptCallback()); | |
63 } | |
64 | |
65 // Helper class that directly loads an extension's content scripts into | |
66 // all of the frames corresponding to a given RenderViewHost. | |
67 class ContentScriptLoader { | |
68 public: | |
69 // Initialize the ContentScriptLoader with the ID of the extension | |
70 // and the RenderViewHost where the scripts should be loaded. | |
71 ContentScriptLoader(const std::string& extension_id, | |
72 int render_process_id, | |
73 int render_view_id) | |
74 : extension_id_(extension_id), | |
75 render_process_id_(render_process_id), | |
76 render_view_id_(render_view_id) {} | |
77 | |
78 // Call this once with the ExtensionResource corresponding to each | |
79 // content script to be loaded. | |
80 void AppendScript(extensions::ExtensionResource resource) { | |
81 resources_.push(resource); | |
82 } | |
83 | |
84 // Finally, call this method once to fetch all of the resources and | |
85 // load them. This method will delete this object when done. | |
86 void Run() { | |
87 if (resources_.empty()) { | |
88 delete this; | |
89 return; | |
90 } | |
91 | |
92 extensions::ExtensionResource resource = resources_.front(); | |
93 resources_.pop(); | |
94 scoped_refptr<FileReader> reader(new FileReader( | |
95 resource, | |
96 FileReader::OptionalFileThreadTaskCallback(), // null callback. | |
97 base::Bind(&ContentScriptLoader::OnFileLoaded, | |
98 base::Unretained(this)))); | |
99 reader->Start(); | |
100 } | |
101 | |
102 private: | |
103 void OnFileLoaded(bool success, std::unique_ptr<std::string> data) { | |
104 if (success) { | |
105 content::RenderViewHost* render_view_host = | |
106 content::RenderViewHost::FromID(render_process_id_, render_view_id_); | |
107 if (render_view_host) | |
108 ExecuteScriptHelper(render_view_host, *data, extension_id_); | |
109 } | |
110 Run(); | |
111 } | |
112 | |
113 std::string extension_id_; | |
114 int render_process_id_; | |
115 int render_view_id_; | |
116 std::queue<extensions::ExtensionResource> resources_; | |
117 }; | |
118 | |
119 } // namespace | |
120 | |
121 AccessibilityExtensionLoader::AccessibilityExtensionLoader( | 16 AccessibilityExtensionLoader::AccessibilityExtensionLoader( |
122 const std::string& extension_id, | 17 const std::string& extension_id, |
123 const base::FilePath& extension_path, | 18 const base::FilePath& extension_path, |
124 const base::Closure& unload_callback) | 19 const base::Closure& unload_callback) |
125 : profile_(nullptr), | 20 : profile_(nullptr), |
126 extension_id_(extension_id), | 21 extension_id_(extension_id), |
127 extension_path_(extension_path), | 22 extension_path_(extension_path), |
128 loaded_on_lock_screen_(false), | 23 loaded_(false), |
129 loaded_on_user_screen_(false), | |
130 unload_callback_(unload_callback), | 24 unload_callback_(unload_callback), |
131 weak_ptr_factory_(this) {} | 25 weak_ptr_factory_(this) {} |
132 | 26 |
133 AccessibilityExtensionLoader::~AccessibilityExtensionLoader() {} | 27 AccessibilityExtensionLoader::~AccessibilityExtensionLoader() {} |
134 | 28 |
135 void AccessibilityExtensionLoader::SetProfile( | 29 void AccessibilityExtensionLoader::SetProfile( |
136 Profile* profile, | 30 Profile* profile, |
137 const base::Closure& done_callback) { | 31 const base::Closure& done_callback) { |
138 profile_ = profile; | 32 profile_ = profile; |
139 | 33 |
140 if (!loaded_on_user_screen_ && !loaded_on_lock_screen_) | 34 if (!loaded_) |
141 return; | 35 return; |
142 | 36 |
143 // If the extension was already enabled, but not for this profile, add it | 37 // If the extension was already enabled, but not for this profile, add it |
144 // to this profile. | 38 // to this profile. |
145 auto* extension_service = | 39 auto* extension_service = |
146 extensions::ExtensionSystem::Get(profile_)->extension_service(); | 40 extensions::ExtensionSystem::Get(profile_)->extension_service(); |
147 auto* component_loader = extension_service->component_loader(); | 41 auto* component_loader = extension_service->component_loader(); |
148 if (!component_loader->Exists(extension_id_)) | 42 if (!component_loader->Exists(extension_id_)) |
149 LoadExtension(profile_, nullptr, done_callback); | 43 LoadExtension(profile_, done_callback); |
150 } | 44 } |
151 | 45 |
152 void AccessibilityExtensionLoader::Load(Profile* profile, | 46 void AccessibilityExtensionLoader::Load(Profile* profile, |
153 const std::string& init_script_str, | 47 const std::string& init_script_str, |
154 const base::Closure& done_cb) { | 48 const base::Closure& done_cb) { |
155 profile_ = profile; | 49 profile_ = profile; |
156 init_script_str_ = init_script_str; | 50 init_script_str_ = init_script_str; |
157 ScreenLocker* screen_locker = ScreenLocker::default_screen_locker(); | 51 |
158 if (screen_locker && screen_locker->locked()) { | 52 if (loaded_) |
159 // If on the lock screen, loads only to the lock screen as for | 53 return; |
160 // now. On unlock, it will be loaded to the user screen. | 54 |
161 // (see. AccessibilityExtensionLoader::Observe()) | 55 loaded_ = true; |
162 LoadToLockScreen(done_cb); | 56 LoadExtension(profile_, done_cb); |
163 } else { | |
164 LoadToUserScreen(done_cb); | |
165 } | |
166 } | 57 } |
167 | 58 |
168 void AccessibilityExtensionLoader::Unload() { | 59 void AccessibilityExtensionLoader::Unload() { |
169 if (loaded_on_lock_screen_) | 60 if (loaded_) { |
170 UnloadFromLockScreen(); | |
171 | |
172 if (loaded_on_user_screen_) { | |
173 UnloadExtensionFromProfile(profile_); | 61 UnloadExtensionFromProfile(profile_); |
174 loaded_on_user_screen_ = false; | 62 UnloadExtensionFromProfile(ProfileHelper::GetSigninProfile()); |
63 loaded_ = false; | |
175 } | 64 } |
176 | 65 |
177 profile_ = nullptr; | 66 profile_ = nullptr; |
178 | 67 |
179 if (unload_callback_) | 68 if (unload_callback_) |
180 unload_callback_.Run(); | 69 unload_callback_.Run(); |
181 } | 70 } |
182 | 71 |
183 void AccessibilityExtensionLoader::LoadToUserScreen( | |
184 const base::Closure& done_cb) { | |
185 if (loaded_on_user_screen_) | |
186 return; | |
187 | |
188 // Determine whether an OOBE screen is currently being shown. If so, | |
189 // the extension will be injected directly into that screen. | |
190 content::WebUI* login_web_ui = nullptr; | |
191 | |
192 if (ProfileHelper::IsSigninProfile(profile_)) { | |
193 LoginDisplayHost* login_display_host = LoginDisplayHost::default_host(); | |
194 if (login_display_host) { | |
195 WebUILoginView* web_ui_login_view = | |
196 login_display_host->GetWebUILoginView(); | |
197 if (web_ui_login_view) | |
198 login_web_ui = web_ui_login_view->GetWebUI(); | |
199 } | |
200 | |
201 // Lock screen uses the signin progile. | |
202 loaded_on_lock_screen_ = true; | |
203 } | |
204 | |
205 loaded_on_user_screen_ = true; | |
206 LoadExtension(profile_, | |
207 login_web_ui | |
208 ? login_web_ui->GetWebContents()->GetRenderViewHost() | |
209 : nullptr, | |
210 done_cb); | |
211 } | |
212 | |
213 void AccessibilityExtensionLoader::LoadToLockScreen( | |
214 const base::Closure& done_cb) { | |
215 if (loaded_on_lock_screen_) | |
216 return; | |
217 | |
218 ScreenLocker* screen_locker = ScreenLocker::default_screen_locker(); | |
219 if (screen_locker && screen_locker->locked()) { | |
220 content::WebUI* lock_web_ui = screen_locker->web_ui()->GetWebUI(); | |
221 if (lock_web_ui) { | |
222 Profile* profile = Profile::FromWebUI(lock_web_ui); | |
223 loaded_on_lock_screen_ = true; | |
224 LoadExtension(profile, lock_web_ui->GetWebContents()->GetRenderViewHost(), | |
225 done_cb); | |
226 } | |
227 } | |
228 } | |
229 | |
230 // | 72 // |
231 // private | 73 // private |
232 // | 74 // |
233 | 75 |
234 void AccessibilityExtensionLoader::UnloadExtensionFromProfile( | 76 void AccessibilityExtensionLoader::UnloadExtensionFromProfile( |
235 Profile* profile) { | 77 Profile* profile) { |
236 ExtensionService* extension_service = | 78 ExtensionService* extension_service = |
237 extensions::ExtensionSystem::Get(profile)->extension_service(); | 79 extensions::ExtensionSystem::Get(profile)->extension_service(); |
238 extension_service->component_loader()->Remove(extension_path_); | 80 extension_service->component_loader()->Remove(extension_path_); |
239 } | 81 } |
240 | 82 |
241 void AccessibilityExtensionLoader::UnloadFromLockScreen() { | |
242 // Lock screen uses the signin progile. | |
243 Profile* signin_profile = ProfileHelper::GetSigninProfile(); | |
244 UnloadExtensionFromProfile(signin_profile); | |
245 loaded_on_lock_screen_ = false; | |
246 } | |
247 | |
248 void AccessibilityExtensionLoader::InjectContentScriptAndCallback( | |
249 ExtensionService* extension_service, | |
250 int render_process_id, | |
251 int render_view_id, | |
252 const base::Closure& done_cb) { | |
253 // Make sure to always run |done_cb|. The extension was loaded even | |
254 // if we end up not injecting into this particular render view. | |
255 base::ScopedClosureRunner done_runner(done_cb); | |
256 content::RenderViewHost* render_view_host = | |
257 content::RenderViewHost::FromID(render_process_id, render_view_id); | |
258 if (!render_view_host) | |
259 return; | |
260 const content::WebContents* web_contents = | |
261 content::WebContents::FromRenderViewHost(render_view_host); | |
262 GURL content_url; | |
263 if (web_contents) | |
264 content_url = web_contents->GetLastCommittedURL(); | |
265 const extensions::Extension* extension = | |
266 extensions::ExtensionRegistry::Get(extension_service->profile()) | |
267 ->enabled_extensions() | |
268 .GetByID(extension_id_); | |
269 | |
270 if (!init_script_str_.empty()) { | |
dmazzoni
2017/01/09 19:17:19
init_script_str is unused, now. If it's really not
| |
271 ExecuteScriptHelper(render_view_host, init_script_str_, extension->id()); | |
272 } | |
273 | |
274 // Inject the content scripts. | |
275 ContentScriptLoader* loader = new ContentScriptLoader( | |
276 extension->id(), render_view_host->GetProcess()->GetID(), | |
277 render_view_host->GetRoutingID()); | |
278 | |
279 const extensions::UserScriptList& content_scripts = | |
280 extensions::ContentScriptsInfo::GetContentScripts(extension); | |
281 for (const std::unique_ptr<extensions::UserScript>& script : | |
282 content_scripts) { | |
283 if (web_contents && !script->MatchesURL(content_url)) | |
284 continue; | |
285 for (const std::unique_ptr<extensions::UserScript::File>& file : | |
286 script->js_scripts()) { | |
287 extensions::ExtensionResource resource = | |
288 extension->GetResource(file->relative_path()); | |
289 loader->AppendScript(resource); | |
290 } | |
291 } | |
292 loader->Run(); // It cleans itself up when done. | |
293 } | |
294 | |
295 void AccessibilityExtensionLoader::LoadExtension( | 83 void AccessibilityExtensionLoader::LoadExtension( |
296 Profile* profile, | 84 Profile* profile, |
297 content::RenderViewHost* render_view_host, | |
298 base::Closure done_cb) { | 85 base::Closure done_cb) { |
299 ExtensionService* extension_service = | 86 ExtensionService* extension_service = |
300 extensions::ExtensionSystem::Get(profile)->extension_service(); | 87 extensions::ExtensionSystem::Get(profile)->extension_service(); |
301 if (render_view_host) { | |
302 // Wrap the passed in callback to inject the content script. | |
303 done_cb = base::Bind( | |
304 &AccessibilityExtensionLoader::InjectContentScriptAndCallback, | |
305 weak_ptr_factory_.GetWeakPtr(), extension_service, | |
306 render_view_host->GetProcess()->GetID(), | |
307 render_view_host->GetRoutingID(), done_cb); | |
308 } | |
309 | 88 |
310 extension_service->component_loader()->AddComponentFromDir( | 89 extension_service->component_loader()->AddComponentFromDir( |
311 extension_path_, extension_id_.c_str(), done_cb); | 90 extension_path_, extension_id_.c_str(), done_cb); |
312 } | 91 } |
313 | 92 |
314 } // namespace chromeos | 93 } // namespace chromeos |
OLD | NEW |