| 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, | |
| 154 const base::Closure& done_cb) { | 47 const base::Closure& done_cb) { |
| 155 profile_ = profile; | 48 profile_ = profile; |
| 156 init_script_str_ = init_script_str; | 49 |
| 157 ScreenLocker* screen_locker = ScreenLocker::default_screen_locker(); | 50 if (loaded_) |
| 158 if (screen_locker && screen_locker->locked()) { | 51 return; |
| 159 // If on the lock screen, loads only to the lock screen as for | 52 |
| 160 // now. On unlock, it will be loaded to the user screen. | 53 loaded_ = true; |
| 161 // (see. AccessibilityExtensionLoader::Observe()) | 54 LoadExtension(profile_, done_cb); |
| 162 LoadToLockScreen(done_cb); | |
| 163 } else { | |
| 164 LoadToUserScreen(done_cb); | |
| 165 } | |
| 166 } | 55 } |
| 167 | 56 |
| 168 void AccessibilityExtensionLoader::Unload() { | 57 void AccessibilityExtensionLoader::Unload() { |
| 169 if (loaded_on_lock_screen_) | 58 if (loaded_) { |
| 170 UnloadFromLockScreen(); | |
| 171 | |
| 172 if (loaded_on_user_screen_) { | |
| 173 UnloadExtensionFromProfile(profile_); | 59 UnloadExtensionFromProfile(profile_); |
| 174 loaded_on_user_screen_ = false; | 60 UnloadExtensionFromProfile(ProfileHelper::GetSigninProfile()); |
| 61 loaded_ = false; |
| 175 } | 62 } |
| 176 | 63 |
| 177 profile_ = nullptr; | 64 profile_ = nullptr; |
| 178 | 65 |
| 179 if (unload_callback_) | 66 if (unload_callback_) |
| 180 unload_callback_.Run(); | 67 unload_callback_.Run(); |
| 181 } | 68 } |
| 182 | 69 |
| 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 // | 70 // |
| 231 // private | 71 // private |
| 232 // | 72 // |
| 233 | 73 |
| 234 void AccessibilityExtensionLoader::UnloadExtensionFromProfile( | 74 void AccessibilityExtensionLoader::UnloadExtensionFromProfile( |
| 235 Profile* profile) { | 75 Profile* profile) { |
| 236 ExtensionService* extension_service = | 76 ExtensionService* extension_service = |
| 237 extensions::ExtensionSystem::Get(profile)->extension_service(); | 77 extensions::ExtensionSystem::Get(profile)->extension_service(); |
| 238 extension_service->component_loader()->Remove(extension_path_); | 78 extension_service->component_loader()->Remove(extension_path_); |
| 239 } | 79 } |
| 240 | 80 |
| 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()) { | |
| 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( | 81 void AccessibilityExtensionLoader::LoadExtension( |
| 296 Profile* profile, | 82 Profile* profile, |
| 297 content::RenderViewHost* render_view_host, | |
| 298 base::Closure done_cb) { | 83 base::Closure done_cb) { |
| 299 ExtensionService* extension_service = | 84 ExtensionService* extension_service = |
| 300 extensions::ExtensionSystem::Get(profile)->extension_service(); | 85 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 | 86 |
| 310 extension_service->component_loader()->AddComponentFromDir( | 87 extension_service->component_loader()->AddComponentFromDir( |
| 311 extension_path_, extension_id_.c_str(), done_cb); | 88 extension_path_, extension_id_.c_str(), done_cb); |
| 312 } | 89 } |
| 313 | 90 |
| 314 } // namespace chromeos | 91 } // namespace chromeos |
| OLD | NEW |