| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/extension_service.h" | 5 #include "chrome/browser/extensions/extension_service.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <set> | 8 #include <set> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/basictypes.h" | 11 #include "base/basictypes.h" |
| 12 #include "base/callback.h" | 12 #include "base/callback.h" |
| 13 #include "base/command_line.h" | 13 #include "base/command_line.h" |
| 14 #include "base/file_util.h" | 14 #include "base/file_util.h" |
| 15 #include "base/json/json_value_serializer.h" | |
| 16 #include "base/logging.h" | 15 #include "base/logging.h" |
| 17 #include "base/metrics/field_trial.h" | 16 #include "base/metrics/field_trial.h" |
| 18 #include "base/metrics/histogram.h" | 17 #include "base/metrics/histogram.h" |
| 19 #include "base/path_service.h" | |
| 20 #include "base/stl_util.h" | 18 #include "base/stl_util.h" |
| 21 #include "base/string16.h" | 19 #include "base/string16.h" |
| 22 #include "base/string_number_conversions.h" | 20 #include "base/string_number_conversions.h" |
| 23 #include "base/string_util.h" | 21 #include "base/string_util.h" |
| 24 #include "base/stringprintf.h" | 22 #include "base/stringprintf.h" |
| 25 #include "base/threading/thread_restrictions.h" | 23 #include "base/threading/thread_restrictions.h" |
| 26 #include "base/time.h" | 24 #include "base/time.h" |
| 27 #include "base/utf_string_conversions.h" | 25 #include "base/utf_string_conversions.h" |
| 28 #include "base/values.h" | 26 #include "base/values.h" |
| 29 #include "base/version.h" | 27 #include "base/version.h" |
| 30 #include "chrome/browser/bookmarks/bookmark_extension_api.h" | 28 #include "chrome/browser/bookmarks/bookmark_extension_api.h" |
| 31 #include "chrome/browser/browser_process.h" | 29 #include "chrome/browser/browser_process.h" |
| 32 #include "chrome/browser/chrome_plugin_service_filter.h" | 30 #include "chrome/browser/chrome_plugin_service_filter.h" |
| 33 #include "chrome/browser/extensions/app_notification_manager.h" | 31 #include "chrome/browser/extensions/app_notification_manager.h" |
| 34 #include "chrome/browser/extensions/apps_promo.h" | 32 #include "chrome/browser/extensions/apps_promo.h" |
| 33 #include "chrome/browser/extensions/component_loader.h" |
| 35 #include "chrome/browser/extensions/crx_installer.h" | 34 #include "chrome/browser/extensions/crx_installer.h" |
| 36 #include "chrome/browser/extensions/default_apps_trial.h" | 35 #include "chrome/browser/extensions/default_apps_trial.h" |
| 37 #include "chrome/browser/extensions/extension_accessibility_api.h" | 36 #include "chrome/browser/extensions/extension_accessibility_api.h" |
| 38 #include "chrome/browser/extensions/extension_browser_event_router.h" | 37 #include "chrome/browser/extensions/extension_browser_event_router.h" |
| 39 #include "chrome/browser/extensions/extension_cookies_api.h" | 38 #include "chrome/browser/extensions/extension_cookies_api.h" |
| 40 #include "chrome/browser/extensions/extension_data_deleter.h" | 39 #include "chrome/browser/extensions/extension_data_deleter.h" |
| 41 #include "chrome/browser/extensions/extension_downloads_api.h" | 40 #include "chrome/browser/extensions/extension_downloads_api.h" |
| 42 #include "chrome/browser/extensions/extension_error_reporter.h" | 41 #include "chrome/browser/extensions/extension_error_reporter.h" |
| 43 #include "chrome/browser/extensions/extension_global_error.h" | 42 #include "chrome/browser/extensions/extension_global_error.h" |
| 44 #include "chrome/browser/extensions/extension_host.h" | 43 #include "chrome/browser/extensions/extension_host.h" |
| 45 #include "chrome/browser/extensions/extension_input_ime_api.h" | 44 #include "chrome/browser/extensions/extension_input_ime_api.h" |
| 46 #include "chrome/browser/extensions/extension_install_ui.h" | |
| 47 #include "chrome/browser/extensions/extension_management_api.h" | 45 #include "chrome/browser/extensions/extension_management_api.h" |
| 48 #include "chrome/browser/extensions/extension_preference_api.h" | 46 #include "chrome/browser/extensions/extension_preference_api.h" |
| 49 #include "chrome/browser/extensions/extension_process_manager.h" | 47 #include "chrome/browser/extensions/extension_process_manager.h" |
| 50 #include "chrome/browser/extensions/extension_processes_api.h" | 48 #include "chrome/browser/extensions/extension_processes_api.h" |
| 51 #include "chrome/browser/extensions/extension_special_storage_policy.h" | 49 #include "chrome/browser/extensions/extension_special_storage_policy.h" |
| 52 #include "chrome/browser/extensions/extension_sync_data.h" | 50 #include "chrome/browser/extensions/extension_sync_data.h" |
| 53 #include "chrome/browser/extensions/extension_updater.h" | 51 #include "chrome/browser/extensions/extension_updater.h" |
| 54 #include "chrome/browser/extensions/extension_web_ui.h" | 52 #include "chrome/browser/extensions/extension_web_ui.h" |
| 55 #include "chrome/browser/extensions/extension_webnavigation_api.h" | 53 #include "chrome/browser/extensions/extension_webnavigation_api.h" |
| 56 #include "chrome/browser/extensions/external_extension_provider_impl.h" | 54 #include "chrome/browser/extensions/external_extension_provider_impl.h" |
| 57 #include "chrome/browser/extensions/external_extension_provider_interface.h" | 55 #include "chrome/browser/extensions/external_extension_provider_interface.h" |
| 56 #include "chrome/browser/extensions/installed_extension_loader.h" |
| 58 #include "chrome/browser/extensions/pending_extension_manager.h" | 57 #include "chrome/browser/extensions/pending_extension_manager.h" |
| 58 #include "chrome/browser/extensions/unpacked_installer.h" |
| 59 #include "chrome/browser/history/history_extension_api.h" | 59 #include "chrome/browser/history/history_extension_api.h" |
| 60 #include "chrome/browser/net/chrome_url_request_context.h" | 60 #include "chrome/browser/net/chrome_url_request_context.h" |
| 61 #include "chrome/browser/prefs/pref_service.h" | 61 #include "chrome/browser/prefs/pref_service.h" |
| 62 #include "chrome/browser/profiles/profile.h" | 62 #include "chrome/browser/profiles/profile.h" |
| 63 #include "chrome/browser/search_engines/template_url_service.h" | 63 #include "chrome/browser/search_engines/template_url_service.h" |
| 64 #include "chrome/browser/search_engines/template_url_service_factory.h" | 64 #include "chrome/browser/search_engines/template_url_service_factory.h" |
| 65 #include "chrome/browser/sync/api/sync_change.h" | 65 #include "chrome/browser/sync/api/sync_change.h" |
| 66 #include "chrome/browser/themes/theme_service.h" | 66 #include "chrome/browser/themes/theme_service.h" |
| 67 #include "chrome/browser/themes/theme_service_factory.h" | 67 #include "chrome/browser/themes/theme_service_factory.h" |
| 68 #include "chrome/browser/ui/browser.h" | 68 #include "chrome/browser/ui/browser.h" |
| 69 #include "chrome/browser/ui/browser_list.h" | 69 #include "chrome/browser/ui/browser_list.h" |
| 70 #include "chrome/browser/ui/global_error_service.h" | 70 #include "chrome/browser/ui/global_error_service.h" |
| 71 #include "chrome/browser/ui/global_error_service_factory.h" | 71 #include "chrome/browser/ui/global_error_service_factory.h" |
| 72 #include "chrome/browser/ui/webui/chrome_url_data_manager.h" | 72 #include "chrome/browser/ui/webui/chrome_url_data_manager.h" |
| 73 #include "chrome/browser/ui/webui/favicon_source.h" | 73 #include "chrome/browser/ui/webui/favicon_source.h" |
| 74 #include "chrome/browser/ui/webui/ntp/shown_sections_handler.h" | 74 #include "chrome/browser/ui/webui/ntp/shown_sections_handler.h" |
| 75 #include "chrome/browser/ui/webui/ntp/thumbnail_source.h" | 75 #include "chrome/browser/ui/webui/ntp/thumbnail_source.h" |
| 76 #include "chrome/common/child_process_logging.h" | 76 #include "chrome/common/child_process_logging.h" |
| 77 #include "chrome/common/chrome_notification_types.h" | 77 #include "chrome/common/chrome_notification_types.h" |
| 78 #include "chrome/common/chrome_paths.h" | |
| 79 #include "chrome/common/chrome_switches.h" | 78 #include "chrome/common/chrome_switches.h" |
| 80 #include "chrome/common/extensions/extension.h" | 79 #include "chrome/common/extensions/extension.h" |
| 81 #include "chrome/common/extensions/extension_constants.h" | 80 #include "chrome/common/extensions/extension_constants.h" |
| 82 #include "chrome/common/extensions/extension_error_utils.h" | 81 #include "chrome/common/extensions/extension_error_utils.h" |
| 83 #include "chrome/common/extensions/extension_file_util.h" | 82 #include "chrome/common/extensions/extension_file_util.h" |
| 84 #include "chrome/common/extensions/extension_l10n_util.h" | |
| 85 #include "chrome/common/extensions/extension_messages.h" | 83 #include "chrome/common/extensions/extension_messages.h" |
| 86 #include "chrome/common/extensions/extension_resource.h" | 84 #include "chrome/common/extensions/extension_resource.h" |
| 87 #include "chrome/common/pref_names.h" | 85 #include "chrome/common/pref_names.h" |
| 88 #include "chrome/common/url_constants.h" | 86 #include "chrome/common/url_constants.h" |
| 89 #include "content/browser/browser_thread.h" | 87 #include "content/browser/browser_thread.h" |
| 90 #include "content/browser/debugger/devtools_manager.h" | 88 #include "content/browser/debugger/devtools_manager.h" |
| 91 #include "content/browser/plugin_process_host.h" | 89 #include "content/browser/plugin_process_host.h" |
| 92 #include "content/browser/plugin_service.h" | 90 #include "content/browser/plugin_service.h" |
| 93 #include "content/browser/renderer_host/render_process_host.h" | 91 #include "content/browser/renderer_host/render_process_host.h" |
| 94 #include "content/browser/user_metrics.h" | 92 #include "content/browser/user_metrics.h" |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 129 #elif defined(OS_MACOSX) | 127 #elif defined(OS_MACOSX) |
| 130 static const int kOmniboxIconPaddingLeft = 0; | 128 static const int kOmniboxIconPaddingLeft = 0; |
| 131 static const int kOmniboxIconPaddingRight = 2; | 129 static const int kOmniboxIconPaddingRight = 2; |
| 132 #else | 130 #else |
| 133 static const int kOmniboxIconPaddingLeft = 0; | 131 static const int kOmniboxIconPaddingLeft = 0; |
| 134 static const int kOmniboxIconPaddingRight = 0; | 132 static const int kOmniboxIconPaddingRight = 0; |
| 135 #endif | 133 #endif |
| 136 | 134 |
| 137 const char* kNaClPluginMimeType = "application/x-nacl"; | 135 const char* kNaClPluginMimeType = "application/x-nacl"; |
| 138 | 136 |
| 139 // The following enumeration is used in histograms matching | |
| 140 // Extensions.ManifestReload* . Values may be added, as long | |
| 141 // as existing values are not changed. | |
| 142 enum ManifestReloadReason { | |
| 143 NOT_NEEDED = 0, // Reload not needed. | |
| 144 UNPACKED_DIR, // Unpacked directory | |
| 145 NEEDS_RELOCALIZATION, // The local has changed since we read this extension. | |
| 146 NUM_MANIFEST_RELOAD_REASONS | |
| 147 }; | |
| 148 | |
| 149 ManifestReloadReason ShouldReloadExtensionManifest(const ExtensionInfo& info) { | |
| 150 // Always reload manifests of unpacked extensions, because they can change | |
| 151 // on disk independent of the manifest in our prefs. | |
| 152 if (info.extension_location == Extension::LOAD) | |
| 153 return UNPACKED_DIR; | |
| 154 | |
| 155 // Reload the manifest if it needs to be relocalized. | |
| 156 if (extension_l10n_util::ShouldRelocalizeManifest(info)) | |
| 157 return NEEDS_RELOCALIZATION; | |
| 158 | |
| 159 return NOT_NEEDED; | |
| 160 } | |
| 161 | |
| 162 static void ForceShutdownPlugin(const FilePath& plugin_path) { | 137 static void ForceShutdownPlugin(const FilePath& plugin_path) { |
| 163 PluginProcessHost* plugin = | 138 PluginProcessHost* plugin = |
| 164 PluginService::GetInstance()->FindNpapiPluginProcess(plugin_path); | 139 PluginService::GetInstance()->FindNpapiPluginProcess(plugin_path); |
| 165 if (plugin) | 140 if (plugin) |
| 166 plugin->ForceShutdown(); | 141 plugin->ForceShutdown(); |
| 167 } | 142 } |
| 168 | 143 |
| 169 static bool IsSyncableExtension(const Extension& extension) { | 144 static bool IsSyncableExtension(const Extension& extension) { |
| 170 return extension.GetSyncType() == Extension::SYNC_TYPE_EXTENSION; | 145 return extension.GetSyncType() == Extension::SYNC_TYPE_EXTENSION; |
| 171 } | 146 } |
| 172 | 147 |
| 173 static bool IsSyncableApp(const Extension& extension) { | 148 static bool IsSyncableApp(const Extension& extension) { |
| 174 return extension.GetSyncType() == Extension::SYNC_TYPE_APP; | 149 return extension.GetSyncType() == Extension::SYNC_TYPE_APP; |
| 175 } | 150 } |
| 176 | 151 |
| 177 // Manages an ExtensionInstallUI for a particular extension. | |
| 178 class SimpleExtensionLoadPrompt : public ExtensionInstallUI::Delegate { | |
| 179 public: | |
| 180 SimpleExtensionLoadPrompt(Profile* profile, | |
| 181 base::WeakPtr<ExtensionService> extension_service, | |
| 182 const Extension* extension); | |
| 183 ~SimpleExtensionLoadPrompt(); | |
| 184 | |
| 185 void ShowPrompt(); | |
| 186 | |
| 187 // ExtensionInstallUI::Delegate | |
| 188 virtual void InstallUIProceed(); | |
| 189 virtual void InstallUIAbort(bool user_initiated); | |
| 190 | |
| 191 private: | |
| 192 base::WeakPtr<ExtensionService> extension_service_; | |
| 193 scoped_ptr<ExtensionInstallUI> install_ui_; | |
| 194 scoped_refptr<const Extension> extension_; | |
| 195 }; | |
| 196 | |
| 197 SimpleExtensionLoadPrompt::SimpleExtensionLoadPrompt( | |
| 198 Profile* profile, | |
| 199 base::WeakPtr<ExtensionService> extension_service, | |
| 200 const Extension* extension) | |
| 201 : extension_service_(extension_service), | |
| 202 install_ui_(new ExtensionInstallUI(profile)), | |
| 203 extension_(extension) { | |
| 204 } | |
| 205 | |
| 206 SimpleExtensionLoadPrompt::~SimpleExtensionLoadPrompt() { | |
| 207 } | |
| 208 | |
| 209 void SimpleExtensionLoadPrompt::ShowPrompt() { | |
| 210 install_ui_->ConfirmInstall(this, extension_); | |
| 211 } | |
| 212 | |
| 213 void SimpleExtensionLoadPrompt::InstallUIProceed() { | |
| 214 if (extension_service_.get()) | |
| 215 extension_service_->OnExtensionInstalled( | |
| 216 extension_, false, -1); // Not from web store. | |
| 217 delete this; | |
| 218 } | |
| 219 | |
| 220 void SimpleExtensionLoadPrompt::InstallUIAbort(bool user_initiated) { | |
| 221 delete this; | |
| 222 } | |
| 223 | |
| 224 } // namespace | 152 } // namespace |
| 225 | 153 |
| 226 bool ExtensionService::ComponentExtensionInfo::Equals( | |
| 227 const ComponentExtensionInfo& other) const { | |
| 228 return other.manifest == manifest && other.root_directory == root_directory; | |
| 229 } | |
| 230 | |
| 231 ExtensionService::ExtensionRuntimeData::ExtensionRuntimeData() | 154 ExtensionService::ExtensionRuntimeData::ExtensionRuntimeData() |
| 232 : background_page_ready(false), | 155 : background_page_ready(false), |
| 233 being_upgraded(false), | 156 being_upgraded(false), |
| 234 has_used_webrequest(false) { | 157 has_used_webrequest(false) { |
| 235 } | 158 } |
| 236 | 159 |
| 237 ExtensionService::ExtensionRuntimeData::~ExtensionRuntimeData() { | 160 ExtensionService::ExtensionRuntimeData::~ExtensionRuntimeData() { |
| 238 } | 161 } |
| 239 | 162 |
| 240 ExtensionService::NaClModuleInfo::NaClModuleInfo() { | 163 ExtensionService::NaClModuleInfo::NaClModuleInfo() { |
| 241 } | 164 } |
| 242 | 165 |
| 243 ExtensionService::NaClModuleInfo::~NaClModuleInfo() { | 166 ExtensionService::NaClModuleInfo::~NaClModuleInfo() { |
| 244 } | 167 } |
| 245 | 168 |
| 246 // ExtensionService. | 169 // ExtensionService. |
| 247 | 170 |
| 248 const char* ExtensionService::kInstallDirectoryName = "Extensions"; | 171 const char* ExtensionService::kInstallDirectoryName = "Extensions"; |
| 249 const char* ExtensionService::kSettingsDirectoryName = "Extension Settings"; | 172 const char* ExtensionService::kSettingsDirectoryName = "Extension Settings"; |
| 250 | 173 |
| 251 // Implements IO for the ExtensionService. | |
| 252 | |
| 253 class ExtensionServiceBackend | |
| 254 : public base::RefCountedThreadSafe<ExtensionServiceBackend> { | |
| 255 public: | |
| 256 // |install_directory| is a path where to look for extensions to load. | |
| 257 ExtensionServiceBackend( | |
| 258 base::WeakPtr<ExtensionService> frontend, | |
| 259 const FilePath& install_directory); | |
| 260 | |
| 261 // Loads a single extension from |path| where |path| is the top directory of | |
| 262 // a specific extension where its manifest file lives. If |prompt_for_plugins| | |
| 263 // is true and the extension contains plugins, we prompt the user before | |
| 264 // loading. | |
| 265 // Errors are reported through ExtensionErrorReporter. On success, | |
| 266 // AddExtension() is called. | |
| 267 // TODO(erikkay): It might be useful to be able to load a packed extension | |
| 268 // (presumably into memory) without installing it. | |
| 269 void LoadSingleExtension(const FilePath &path, bool prompt_for_plugins); | |
| 270 | |
| 271 private: | |
| 272 friend class base::RefCountedThreadSafe<ExtensionServiceBackend>; | |
| 273 | |
| 274 virtual ~ExtensionServiceBackend(); | |
| 275 | |
| 276 // LoadSingleExtension needs to check the file access preference, which needs | |
| 277 // to happen back on the UI thread, so it posts CheckExtensionFileAccess on | |
| 278 // the UI thread. In turn, once that gets the pref, it goes back to the | |
| 279 // file thread with LoadSingleExtensionWithFileAccess. | |
| 280 void CheckExtensionFileAccess(const FilePath& extension_path, | |
| 281 bool prompt_for_plugins); | |
| 282 void LoadSingleExtensionWithFileAccess( | |
| 283 const FilePath &path, bool allow_file_access, bool prompt_for_plugins); | |
| 284 | |
| 285 // Notify the frontend that there was an error loading an extension. | |
| 286 void ReportExtensionLoadError(const FilePath& extension_path, | |
| 287 const std::string& error); | |
| 288 | |
| 289 // Notify the frontend that an extension was installed. | |
| 290 void OnLoadSingleExtension(const scoped_refptr<const Extension>& extension, | |
| 291 bool prompt_for_plugins); | |
| 292 | |
| 293 base::WeakPtr<ExtensionService> frontend_; | |
| 294 | |
| 295 // The top-level extensions directory being installed to. | |
| 296 FilePath install_directory_; | |
| 297 | |
| 298 DISALLOW_COPY_AND_ASSIGN(ExtensionServiceBackend); | |
| 299 }; | |
| 300 | |
| 301 ExtensionServiceBackend::ExtensionServiceBackend( | |
| 302 base::WeakPtr<ExtensionService> frontend, | |
| 303 const FilePath& install_directory) | |
| 304 : frontend_(frontend), | |
| 305 install_directory_(install_directory) { | |
| 306 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 307 } | |
| 308 | |
| 309 ExtensionServiceBackend::~ExtensionServiceBackend() { | |
| 310 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) || | |
| 311 BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 312 } | |
| 313 | |
| 314 void ExtensionServiceBackend::LoadSingleExtension(const FilePath& path_in, | |
| 315 bool prompt_for_plugins) { | |
| 316 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 317 | |
| 318 FilePath extension_path = path_in; | |
| 319 file_util::AbsolutePath(&extension_path); | |
| 320 | |
| 321 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
| 322 base::Bind(&ExtensionServiceBackend::CheckExtensionFileAccess, | |
| 323 this, extension_path, prompt_for_plugins)); | |
| 324 } | |
| 325 | |
| 326 void ExtensionServiceBackend::CheckExtensionFileAccess( | |
| 327 const FilePath& extension_path, bool prompt_for_plugins) { | |
| 328 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 329 std::string id = Extension::GenerateIdForPath(extension_path); | |
| 330 // Unpacked extensions default to allowing file access, but if that has been | |
| 331 // overridden, don't reset the value. | |
| 332 bool allow_file_access = | |
| 333 Extension::ShouldAlwaysAllowFileAccess(Extension::LOAD); | |
| 334 if (frontend_->extension_prefs()->HasAllowFileAccessSetting(id)) | |
| 335 allow_file_access = frontend_->extension_prefs()->AllowFileAccess(id); | |
| 336 | |
| 337 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, | |
| 338 base::Bind( | |
| 339 &ExtensionServiceBackend::LoadSingleExtensionWithFileAccess, | |
| 340 this, extension_path, allow_file_access, prompt_for_plugins)); | |
| 341 } | |
| 342 | |
| 343 void ExtensionServiceBackend::LoadSingleExtensionWithFileAccess( | |
| 344 const FilePath& extension_path, | |
| 345 bool allow_file_access, | |
| 346 bool prompt_for_plugins) { | |
| 347 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 348 int flags = allow_file_access ? | |
| 349 Extension::ALLOW_FILE_ACCESS : Extension::NO_FLAGS; | |
| 350 if (Extension::ShouldDoStrictErrorChecking(Extension::LOAD)) | |
| 351 flags |= Extension::STRICT_ERROR_CHECKS; | |
| 352 std::string error; | |
| 353 scoped_refptr<const Extension> extension(extension_file_util::LoadExtension( | |
| 354 extension_path, | |
| 355 Extension::LOAD, | |
| 356 flags, | |
| 357 &error)); | |
| 358 | |
| 359 if (!extension) { | |
| 360 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
| 361 base::Bind( | |
| 362 &ExtensionServiceBackend::ReportExtensionLoadError, | |
| 363 this, | |
| 364 extension_path, error)); | |
| 365 return; | |
| 366 } | |
| 367 | |
| 368 // Report this as an installed extension so that it gets remembered in the | |
| 369 // prefs. | |
| 370 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, | |
| 371 base::Bind( | |
| 372 &ExtensionServiceBackend::OnLoadSingleExtension, | |
| 373 this, extension, prompt_for_plugins)); | |
| 374 } | |
| 375 | |
| 376 void ExtensionServiceBackend::ReportExtensionLoadError( | |
| 377 const FilePath& extension_path, const std::string &error) { | |
| 378 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 379 if (frontend_.get()) | |
| 380 frontend_->ReportExtensionLoadError( | |
| 381 extension_path, error, true /* alert_on_error */); | |
| 382 } | |
| 383 | |
| 384 void ExtensionServiceBackend::OnLoadSingleExtension( | |
| 385 const scoped_refptr<const Extension>& extension, bool prompt_for_plugins) { | |
| 386 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 387 if (frontend_.get()) | |
| 388 frontend_->OnLoadSingleExtension(extension, prompt_for_plugins); | |
| 389 } | |
| 390 | |
| 391 void ExtensionService::CheckExternalUninstall(const std::string& id) { | 174 void ExtensionService::CheckExternalUninstall(const std::string& id) { |
| 392 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 175 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 393 | 176 |
| 394 // Check if the providers know about this extension. | 177 // Check if the providers know about this extension. |
| 395 ProviderCollection::const_iterator i; | 178 ProviderCollection::const_iterator i; |
| 396 for (i = external_extension_providers_.begin(); | 179 for (i = external_extension_providers_.begin(); |
| 397 i != external_extension_providers_.end(); ++i) { | 180 i != external_extension_providers_.end(); ++i) { |
| 398 DCHECK(i->get()->IsReady()); | 181 DCHECK(i->get()->IsReady()); |
| 399 if (i->get()->HasExtension(id)) | 182 if (i->get()->HasExtension(id)) |
| 400 return; // Yup, known extension, don't uninstall. | 183 return; // Yup, known extension, don't uninstall. |
| (...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 619 switches::kExtensionsUpdateFrequency), | 402 switches::kExtensionsUpdateFrequency), |
| 620 &update_frequency); | 403 &update_frequency); |
| 621 } | 404 } |
| 622 updater_.reset(new ExtensionUpdater(this, | 405 updater_.reset(new ExtensionUpdater(this, |
| 623 extension_prefs, | 406 extension_prefs, |
| 624 profile->GetPrefs(), | 407 profile->GetPrefs(), |
| 625 profile, | 408 profile, |
| 626 update_frequency)); | 409 update_frequency)); |
| 627 } | 410 } |
| 628 | 411 |
| 629 backend_ = | 412 component_loader_.reset(new ComponentLoader(this)); |
| 630 new ExtensionServiceBackend(weak_ptr_factory_.GetWeakPtr(), | |
| 631 install_directory_); | |
| 632 | 413 |
| 633 app_notification_manager_->Init(); | 414 app_notification_manager_->Init(); |
| 634 | 415 |
| 635 if (extensions_enabled_) { | 416 if (extensions_enabled_) { |
| 636 ExternalExtensionProviderImpl::CreateExternalProviders( | 417 ExternalExtensionProviderImpl::CreateExternalProviders( |
| 637 this, profile_, &external_extension_providers_); | 418 this, profile_, &external_extension_providers_); |
| 638 } | 419 } |
| 639 | 420 |
| 640 // Use monochrome icons for Omnibox icons. | 421 // Use monochrome icons for Omnibox icons. |
| 641 omnibox_popup_icon_manager_.set_monochrome(true); | 422 omnibox_popup_icon_manager_.set_monochrome(true); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 657 } | 438 } |
| 658 | 439 |
| 659 const ExtensionList* ExtensionService::terminated_extensions() const { | 440 const ExtensionList* ExtensionService::terminated_extensions() const { |
| 660 return &terminated_extensions_; | 441 return &terminated_extensions_; |
| 661 } | 442 } |
| 662 | 443 |
| 663 PendingExtensionManager* ExtensionService::pending_extension_manager() { | 444 PendingExtensionManager* ExtensionService::pending_extension_manager() { |
| 664 return &pending_extension_manager_; | 445 return &pending_extension_manager_; |
| 665 } | 446 } |
| 666 | 447 |
| 667 void ExtensionService::UnregisterComponentExtension( | |
| 668 const ComponentExtensionInfo& info) { | |
| 669 RegisteredComponentExtensions new_component_extension_manifests; | |
| 670 for (RegisteredComponentExtensions::iterator it = | |
| 671 component_extension_manifests_.begin(); | |
| 672 it != component_extension_manifests_.end(); ++it) { | |
| 673 if (!it->Equals(info)) | |
| 674 new_component_extension_manifests.push_back(*it); | |
| 675 } | |
| 676 component_extension_manifests_.swap(new_component_extension_manifests); | |
| 677 } | |
| 678 | |
| 679 ExtensionService::~ExtensionService() { | 448 ExtensionService::~ExtensionService() { |
| 680 // No need to unload extensions here because they are profile-scoped, and the | 449 // No need to unload extensions here because they are profile-scoped, and the |
| 681 // profile is in the process of being deleted. | 450 // profile is in the process of being deleted. |
| 682 | 451 |
| 683 ProviderCollection::const_iterator i; | 452 ProviderCollection::const_iterator i; |
| 684 for (i = external_extension_providers_.begin(); | 453 for (i = external_extension_providers_.begin(); |
| 685 i != external_extension_providers_.end(); ++i) { | 454 i != external_extension_providers_.end(); ++i) { |
| 686 ExternalExtensionProviderInterface* provider = i->get(); | 455 ExternalExtensionProviderInterface* provider = i->get(); |
| 687 provider->ServiceShutdown(); | 456 provider->ServiceShutdown(); |
| 688 } | 457 } |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 742 void ExtensionService::Init() { | 511 void ExtensionService::Init() { |
| 743 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 512 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 744 | 513 |
| 745 DCHECK(!ready_); // Can't redo init. | 514 DCHECK(!ready_); // Can't redo init. |
| 746 DCHECK_EQ(extensions_.size(), 0u); | 515 DCHECK_EQ(extensions_.size(), 0u); |
| 747 | 516 |
| 748 // Hack: we need to ensure the ResourceDispatcherHost is ready before we load | 517 // Hack: we need to ensure the ResourceDispatcherHost is ready before we load |
| 749 // the first extension, because its members listen for loaded notifications. | 518 // the first extension, because its members listen for loaded notifications. |
| 750 g_browser_process->resource_dispatcher_host(); | 519 g_browser_process->resource_dispatcher_host(); |
| 751 | 520 |
| 752 LoadAllExtensions(); | 521 component_loader_->LoadComponentExtensions(); |
| 522 MakeInstalledExtensionLoader()->LoadAllExtensions(); |
| 753 | 523 |
| 754 // TODO(erikkay) this should probably be deferred to a future point | 524 // TODO(erikkay) this should probably be deferred to a future point |
| 755 // rather than running immediately at startup. | 525 // rather than running immediately at startup. |
| 756 CheckForExternalUpdates(); | 526 CheckForExternalUpdates(); |
| 757 | 527 |
| 758 // TODO(erikkay) this should probably be deferred as well. | 528 // TODO(erikkay) this should probably be deferred as well. |
| 759 GarbageCollectExtensions(); | 529 GarbageCollectExtensions(); |
| 760 } | 530 } |
| 761 | 531 |
| 762 bool ExtensionService::UpdateExtension( | 532 bool ExtensionService::UpdateExtension( |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 839 } else { | 609 } else { |
| 840 path = unloaded_extension_paths_[extension_id]; | 610 path = unloaded_extension_paths_[extension_id]; |
| 841 } | 611 } |
| 842 | 612 |
| 843 // Check the installed extensions to see if what we're reloading was already | 613 // Check the installed extensions to see if what we're reloading was already |
| 844 // installed. | 614 // installed. |
| 845 scoped_ptr<ExtensionInfo> installed_extension( | 615 scoped_ptr<ExtensionInfo> installed_extension( |
| 846 extension_prefs_->GetInstalledExtensionInfo(extension_id)); | 616 extension_prefs_->GetInstalledExtensionInfo(extension_id)); |
| 847 if (installed_extension.get() && | 617 if (installed_extension.get() && |
| 848 installed_extension->extension_manifest.get()) { | 618 installed_extension->extension_manifest.get()) { |
| 849 LoadInstalledExtension(*installed_extension, false); | 619 MakeInstalledExtensionLoader()->Load(*installed_extension, false); |
| 850 } else { | 620 } else { |
| 621 // Otherwise, the extension is unpacked (location LOAD). |
| 851 // We should always be able to remember the extension's path. If it's not in | 622 // We should always be able to remember the extension's path. If it's not in |
| 852 // the map, someone failed to update |unloaded_extension_paths_|. | 623 // the map, someone failed to update |unloaded_extension_paths_|. |
| 853 CHECK(!path.empty()); | 624 CHECK(!path.empty()); |
| 854 LoadExtension(path); | 625 MakeUnpackedInstaller()->Load(path); |
| 855 } | 626 } |
| 856 } | 627 } |
| 857 | 628 |
| 858 bool ExtensionService::UninstallExtension( | 629 bool ExtensionService::UninstallExtension( |
| 859 const std::string& extension_id_unsafe, | 630 const std::string& extension_id_unsafe, |
| 860 bool external_uninstall, | 631 bool external_uninstall, |
| 861 std::string* error) { | 632 std::string* error) { |
| 862 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 633 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 863 | 634 |
| 864 // Copy the extension identifier since the reference might have been | 635 // Copy the extension identifier since the reference might have been |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1095 EnableExtension(extension->id()); | 866 EnableExtension(extension->id()); |
| 1096 } | 867 } |
| 1097 | 868 |
| 1098 void ExtensionService::UpdateActivePermissions( | 869 void ExtensionService::UpdateActivePermissions( |
| 1099 const Extension* extension, | 870 const Extension* extension, |
| 1100 const ExtensionPermissionSet* permissions) { | 871 const ExtensionPermissionSet* permissions) { |
| 1101 extension_prefs()->SetActivePermissions(extension->id(), permissions); | 872 extension_prefs()->SetActivePermissions(extension->id(), permissions); |
| 1102 extension->SetActivePermissions(permissions); | 873 extension->SetActivePermissions(permissions); |
| 1103 } | 874 } |
| 1104 | 875 |
| 1105 void ExtensionService::LoadExtension(const FilePath& extension_path) { | |
| 1106 LoadExtension(extension_path, true); | |
| 1107 } | |
| 1108 | |
| 1109 void ExtensionService::LoadExtension(const FilePath& extension_path, | |
| 1110 bool prompt_for_plugins) { | |
| 1111 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, | |
| 1112 base::Bind(&ExtensionServiceBackend::LoadSingleExtension, backend_.get(), | |
| 1113 extension_path, prompt_for_plugins)); | |
| 1114 } | |
| 1115 | |
| 1116 void ExtensionService::LoadExtensionFromCommandLine( | |
| 1117 const FilePath& path_in) { | |
| 1118 | |
| 1119 // Load extensions from the command line synchronously to avoid a race | |
| 1120 // between extension loading and loading an URL from the command line. | |
| 1121 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
| 1122 | |
| 1123 FilePath extension_path = path_in; | |
| 1124 file_util::AbsolutePath(&extension_path); | |
| 1125 | |
| 1126 std::string id = Extension::GenerateIdForPath(extension_path); | |
| 1127 bool allow_file_access = | |
| 1128 Extension::ShouldAlwaysAllowFileAccess(Extension::LOAD); | |
| 1129 if (extension_prefs()->HasAllowFileAccessSetting(id)) | |
| 1130 allow_file_access = extension_prefs()->AllowFileAccess(id); | |
| 1131 | |
| 1132 int flags = Extension::NO_FLAGS; | |
| 1133 if (allow_file_access) | |
| 1134 flags |= Extension::ALLOW_FILE_ACCESS; | |
| 1135 if (Extension::ShouldDoStrictErrorChecking(Extension::LOAD)) | |
| 1136 flags |= Extension::STRICT_ERROR_CHECKS; | |
| 1137 | |
| 1138 std::string error; | |
| 1139 scoped_refptr<const Extension> extension(extension_file_util::LoadExtension( | |
| 1140 extension_path, | |
| 1141 Extension::LOAD, | |
| 1142 flags, | |
| 1143 &error)); | |
| 1144 | |
| 1145 if (!extension) { | |
| 1146 ReportExtensionLoadError(extension_path, error, true); | |
| 1147 return; | |
| 1148 } | |
| 1149 | |
| 1150 OnLoadSingleExtension(extension, false); | |
| 1151 } | |
| 1152 | |
| 1153 void ExtensionService::LoadComponentExtensions() { | |
| 1154 for (RegisteredComponentExtensions::iterator it = | |
| 1155 component_extension_manifests_.begin(); | |
| 1156 it != component_extension_manifests_.end(); ++it) { | |
| 1157 LoadComponentExtension(*it); | |
| 1158 } | |
| 1159 } | |
| 1160 | |
| 1161 const Extension* ExtensionService::LoadComponentExtension( | |
| 1162 const ComponentExtensionInfo &info) { | |
| 1163 JSONStringValueSerializer serializer(info.manifest); | |
| 1164 scoped_ptr<Value> manifest(serializer.Deserialize(NULL, NULL)); | |
| 1165 if (!manifest.get()) { | |
| 1166 LOG(ERROR) << "Failed to parse manifest for extension"; | |
| 1167 return NULL; | |
| 1168 } | |
| 1169 | |
| 1170 int flags = Extension::REQUIRE_KEY; | |
| 1171 if (Extension::ShouldDoStrictErrorChecking(Extension::COMPONENT)) | |
| 1172 flags |= Extension::STRICT_ERROR_CHECKS; | |
| 1173 std::string error; | |
| 1174 scoped_refptr<const Extension> extension(Extension::Create( | |
| 1175 info.root_directory, | |
| 1176 Extension::COMPONENT, | |
| 1177 *static_cast<DictionaryValue*>(manifest.get()), | |
| 1178 flags, | |
| 1179 &error)); | |
| 1180 if (!extension.get()) { | |
| 1181 LOG(ERROR) << error; | |
| 1182 return NULL; | |
| 1183 } | |
| 1184 AddExtension(extension); | |
| 1185 return extension; | |
| 1186 } | |
| 1187 | |
| 1188 void ExtensionService::UnloadComponentExtension( | |
| 1189 const ComponentExtensionInfo& info) { | |
| 1190 JSONStringValueSerializer serializer(info.manifest); | |
| 1191 scoped_ptr<Value> manifest(serializer.Deserialize(NULL, NULL)); | |
| 1192 if (!manifest.get()) { | |
| 1193 LOG(ERROR) << "Failed to parse manifest for extension"; | |
| 1194 return; | |
| 1195 } | |
| 1196 std::string public_key; | |
| 1197 std::string public_key_bytes; | |
| 1198 std::string id; | |
| 1199 if (!static_cast<DictionaryValue*>(manifest.get())-> | |
| 1200 GetString(extension_manifest_keys::kPublicKey, &public_key) || | |
| 1201 !Extension::ParsePEMKeyBytes(public_key, &public_key_bytes) || | |
| 1202 !Extension::GenerateId(public_key_bytes, &id)) { | |
| 1203 LOG(ERROR) << "Failed to get extension id"; | |
| 1204 return; | |
| 1205 } | |
| 1206 UnloadExtension(id, extension_misc::UNLOAD_REASON_DISABLE); | |
| 1207 } | |
| 1208 | |
| 1209 void ExtensionService::LoadAllExtensions() { | |
| 1210 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
| 1211 | |
| 1212 base::TimeTicks start_time = base::TimeTicks::Now(); | |
| 1213 | |
| 1214 // Load any component extensions. | |
| 1215 LoadComponentExtensions(); | |
| 1216 | |
| 1217 // Load the previously installed extensions. | |
| 1218 scoped_ptr<ExtensionPrefs::ExtensionsInfo> extensions_info( | |
| 1219 extension_prefs_->GetInstalledExtensionsInfo()); | |
| 1220 | |
| 1221 std::vector<int> reload_reason_counts(NUM_MANIFEST_RELOAD_REASONS, 0); | |
| 1222 bool should_write_prefs = false; | |
| 1223 | |
| 1224 for (size_t i = 0; i < extensions_info->size(); ++i) { | |
| 1225 ExtensionInfo* info = extensions_info->at(i).get(); | |
| 1226 | |
| 1227 ManifestReloadReason reload_reason = ShouldReloadExtensionManifest(*info); | |
| 1228 ++reload_reason_counts[reload_reason]; | |
| 1229 UMA_HISTOGRAM_ENUMERATION("Extensions.ManifestReloadEnumValue", | |
| 1230 reload_reason, 100); | |
| 1231 | |
| 1232 if (reload_reason != NOT_NEEDED) { | |
| 1233 // Reloading and extension reads files from disk. We do this on the | |
| 1234 // UI thread because reloads should be very rare, and the complexity | |
| 1235 // added by delaying the time when the extensions service knows about | |
| 1236 // all extensions is significant. See crbug.com/37548 for details. | |
| 1237 // |allow_io| disables tests that file operations run on the file | |
| 1238 // thread. | |
| 1239 base::ThreadRestrictions::ScopedAllowIO allow_io; | |
| 1240 | |
| 1241 std::string error; | |
| 1242 scoped_refptr<const Extension> extension( | |
| 1243 extension_file_util::LoadExtension( | |
| 1244 info->extension_path, | |
| 1245 info->extension_location, | |
| 1246 GetExtensionCreateFlagsForInstalledExtension(info), | |
| 1247 &error)); | |
| 1248 | |
| 1249 if (extension.get()) { | |
| 1250 extensions_info->at(i)->extension_manifest.reset( | |
| 1251 static_cast<DictionaryValue*>( | |
| 1252 extension->manifest_value()->DeepCopy())); | |
| 1253 should_write_prefs = true; | |
| 1254 } | |
| 1255 } | |
| 1256 } | |
| 1257 | |
| 1258 for (size_t i = 0; i < extensions_info->size(); ++i) { | |
| 1259 LoadInstalledExtension(*extensions_info->at(i), should_write_prefs); | |
| 1260 } | |
| 1261 | |
| 1262 OnLoadedInstalledExtensions(); | |
| 1263 | |
| 1264 // The histograms Extensions.ManifestReload* allow us to validate | |
| 1265 // the assumption that reloading manifest is a rare event. | |
| 1266 UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadNotNeeded", | |
| 1267 reload_reason_counts[NOT_NEEDED]); | |
| 1268 UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadUnpackedDir", | |
| 1269 reload_reason_counts[UNPACKED_DIR]); | |
| 1270 UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadNeedsRelocalization", | |
| 1271 reload_reason_counts[NEEDS_RELOCALIZATION]); | |
| 1272 | |
| 1273 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAll", extensions_.size()); | |
| 1274 UMA_HISTOGRAM_COUNTS_100("Extensions.Disabled", disabled_extensions_.size()); | |
| 1275 | |
| 1276 UMA_HISTOGRAM_TIMES("Extensions.LoadAllTime", | |
| 1277 base::TimeTicks::Now() - start_time); | |
| 1278 | |
| 1279 int app_user_count = 0; | |
| 1280 int app_external_count = 0; | |
| 1281 int hosted_app_count = 0; | |
| 1282 int packaged_app_count = 0; | |
| 1283 int user_script_count = 0; | |
| 1284 int extension_user_count = 0; | |
| 1285 int extension_external_count = 0; | |
| 1286 int theme_count = 0; | |
| 1287 int page_action_count = 0; | |
| 1288 int browser_action_count = 0; | |
| 1289 ExtensionList::iterator ex; | |
| 1290 for (ex = extensions_.begin(); ex != extensions_.end(); ++ex) { | |
| 1291 Extension::Location location = (*ex)->location(); | |
| 1292 Extension::Type type = (*ex)->GetType(); | |
| 1293 if ((*ex)->is_app()) { | |
| 1294 UMA_HISTOGRAM_ENUMERATION("Extensions.AppLocation", | |
| 1295 location, 100); | |
| 1296 } else if (type == Extension::TYPE_EXTENSION) { | |
| 1297 UMA_HISTOGRAM_ENUMERATION("Extensions.ExtensionLocation", | |
| 1298 location, 100); | |
| 1299 } | |
| 1300 | |
| 1301 // Don't count component extensions, since they are only extensions as an | |
| 1302 // implementation detail. | |
| 1303 if (location == Extension::COMPONENT) | |
| 1304 continue; | |
| 1305 | |
| 1306 // Don't count unpacked extensions, since they're a developer-specific | |
| 1307 // feature. | |
| 1308 if (location == Extension::LOAD) | |
| 1309 continue; | |
| 1310 | |
| 1311 // Using an enumeration shows us the total installed ratio across all users. | |
| 1312 // Using the totals per user at each startup tells us the distribution of | |
| 1313 // usage for each user (e.g. 40% of users have at least one app installed). | |
| 1314 UMA_HISTOGRAM_ENUMERATION("Extensions.LoadType", type, 100); | |
| 1315 switch (type) { | |
| 1316 case Extension::TYPE_THEME: | |
| 1317 ++theme_count; | |
| 1318 break; | |
| 1319 case Extension::TYPE_USER_SCRIPT: | |
| 1320 ++user_script_count; | |
| 1321 break; | |
| 1322 case Extension::TYPE_HOSTED_APP: | |
| 1323 ++hosted_app_count; | |
| 1324 if (Extension::IsExternalLocation(location)) { | |
| 1325 ++app_external_count; | |
| 1326 } else { | |
| 1327 ++app_user_count; | |
| 1328 } | |
| 1329 break; | |
| 1330 case Extension::TYPE_PACKAGED_APP: | |
| 1331 ++packaged_app_count; | |
| 1332 if (Extension::IsExternalLocation(location)) { | |
| 1333 ++app_external_count; | |
| 1334 } else { | |
| 1335 ++app_user_count; | |
| 1336 } | |
| 1337 break; | |
| 1338 case Extension::TYPE_EXTENSION: | |
| 1339 default: | |
| 1340 if (Extension::IsExternalLocation(location)) { | |
| 1341 ++extension_external_count; | |
| 1342 } else { | |
| 1343 ++extension_user_count; | |
| 1344 } | |
| 1345 break; | |
| 1346 } | |
| 1347 if ((*ex)->page_action() != NULL) | |
| 1348 ++page_action_count; | |
| 1349 if ((*ex)->browser_action() != NULL) | |
| 1350 ++browser_action_count; | |
| 1351 | |
| 1352 RecordPermissionMessagesHistogram( | |
| 1353 ex->get(), "Extensions.Permissions_Load"); | |
| 1354 } | |
| 1355 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadApp", | |
| 1356 app_user_count + app_external_count); | |
| 1357 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAppUser", app_user_count); | |
| 1358 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAppExternal", app_external_count); | |
| 1359 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadHostedApp", hosted_app_count); | |
| 1360 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPackagedApp", packaged_app_count); | |
| 1361 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtension", | |
| 1362 extension_user_count + extension_external_count); | |
| 1363 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtensionUser", | |
| 1364 extension_user_count); | |
| 1365 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtensionExternal", | |
| 1366 extension_external_count); | |
| 1367 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadUserScript", user_script_count); | |
| 1368 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadTheme", theme_count); | |
| 1369 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPageAction", page_action_count); | |
| 1370 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadBrowserAction", | |
| 1371 browser_action_count); | |
| 1372 } | |
| 1373 | |
| 1374 // static | 876 // static |
| 1375 void ExtensionService::RecordPermissionMessagesHistogram( | 877 void ExtensionService::RecordPermissionMessagesHistogram( |
| 1376 const Extension* e, const char* histogram) { | 878 const Extension* e, const char* histogram) { |
| 1377 // Since this is called from multiple sources, and since the Histogram macros | 879 // Since this is called from multiple sources, and since the Histogram macros |
| 1378 // use statics, we need to manually lookup the Histogram ourselves. | 880 // use statics, we need to manually lookup the Histogram ourselves. |
| 1379 base::Histogram* counter = base::LinearHistogram::FactoryGet( | 881 base::Histogram* counter = base::LinearHistogram::FactoryGet( |
| 1380 histogram, | 882 histogram, |
| 1381 1, | 883 1, |
| 1382 ExtensionPermissionMessage::kEnumBoundary, | 884 ExtensionPermissionMessage::kEnumBoundary, |
| 1383 ExtensionPermissionMessage::kEnumBoundary + 1, | 885 ExtensionPermissionMessage::kEnumBoundary + 1, |
| 1384 base::Histogram::kUmaTargetedHistogramFlag); | 886 base::Histogram::kUmaTargetedHistogramFlag); |
| 1385 | 887 |
| 1386 ExtensionPermissionMessages permissions = e->GetPermissionMessages(); | 888 ExtensionPermissionMessages permissions = e->GetPermissionMessages(); |
| 1387 if (permissions.empty()) { | 889 if (permissions.empty()) { |
| 1388 counter->Add(ExtensionPermissionMessage::kNone); | 890 counter->Add(ExtensionPermissionMessage::kNone); |
| 1389 } else { | 891 } else { |
| 1390 for (ExtensionPermissionMessages::iterator it = permissions.begin(); | 892 for (ExtensionPermissionMessages::iterator it = permissions.begin(); |
| 1391 it != permissions.end(); ++it) | 893 it != permissions.end(); ++it) |
| 1392 counter->Add(it->id()); | 894 counter->Add(it->id()); |
| 1393 } | 895 } |
| 1394 } | 896 } |
| 1395 | 897 |
| 1396 void ExtensionService::LoadInstalledExtension(const ExtensionInfo& info, | |
| 1397 bool write_to_prefs) { | |
| 1398 std::string error; | |
| 1399 scoped_refptr<const Extension> extension(NULL); | |
| 1400 if (!extension_prefs_->IsExtensionAllowedByPolicy(info.extension_id)) { | |
| 1401 error = errors::kDisabledByPolicy; | |
| 1402 } else if (info.extension_manifest.get()) { | |
| 1403 extension = Extension::Create( | |
| 1404 info.extension_path, | |
| 1405 info.extension_location, | |
| 1406 *info.extension_manifest, | |
| 1407 GetExtensionCreateFlagsForInstalledExtension(&info), | |
| 1408 &error); | |
| 1409 } else { | |
| 1410 error = errors::kManifestUnreadable; | |
| 1411 } | |
| 1412 | |
| 1413 // Once installed, non-unpacked extensions cannot change their IDs (e.g., by | |
| 1414 // updating the 'key' field in their manifest). | |
| 1415 if (extension && | |
| 1416 extension->location() != Extension::LOAD && | |
| 1417 info.extension_id != extension->id()) { | |
| 1418 error = errors::kCannotChangeExtensionID; | |
| 1419 extension = NULL; | |
| 1420 UserMetrics::RecordAction(UserMetricsAction("Extensions.IDChangedError")); | |
| 1421 } | |
| 1422 | |
| 1423 if (!extension) { | |
| 1424 ReportExtensionLoadError(info.extension_path, error, false); | |
| 1425 return; | |
| 1426 } | |
| 1427 | |
| 1428 if (write_to_prefs) | |
| 1429 extension_prefs_->UpdateManifest(extension); | |
| 1430 | |
| 1431 AddExtension(extension); | |
| 1432 } | |
| 1433 | |
| 1434 int ExtensionService::GetExtensionCreateFlagsForInstalledExtension( | |
| 1435 const ExtensionInfo* info) { | |
| 1436 int flags = Extension::NO_FLAGS; | |
| 1437 if (info->extension_location != Extension::LOAD) | |
| 1438 flags |= Extension::REQUIRE_KEY; | |
| 1439 if (Extension::ShouldDoStrictErrorChecking(info->extension_location)) | |
| 1440 flags |= Extension::STRICT_ERROR_CHECKS; | |
| 1441 if (extension_prefs_->AllowFileAccess(info->extension_id)) | |
| 1442 flags |= Extension::ALLOW_FILE_ACCESS; | |
| 1443 if (extension_prefs_->IsFromWebStore(info->extension_id)) | |
| 1444 flags |= Extension::FROM_WEBSTORE; | |
| 1445 if (extension_prefs_->IsFromBookmark(info->extension_id)) | |
| 1446 flags |= Extension::FROM_BOOKMARK; | |
| 1447 return flags; | |
| 1448 } | |
| 1449 | |
| 1450 void ExtensionService::NotifyExtensionLoaded(const Extension* extension) { | 898 void ExtensionService::NotifyExtensionLoaded(const Extension* extension) { |
| 1451 // The ChromeURLRequestContexts need to be first to know that the extension | 899 // The ChromeURLRequestContexts need to be first to know that the extension |
| 1452 // was loaded, otherwise a race can arise where a renderer that is created | 900 // was loaded, otherwise a race can arise where a renderer that is created |
| 1453 // for the extension may try to load an extension URL with an extension id | 901 // for the extension may try to load an extension URL with an extension id |
| 1454 // that the request context doesn't yet know about. The profile is responsible | 902 // that the request context doesn't yet know about. The profile is responsible |
| 1455 // for ensuring its URLRequestContexts appropriately discover the loaded | 903 // for ensuring its URLRequestContexts appropriately discover the loaded |
| 1456 // extension. | 904 // extension. |
| 1457 profile_->RegisterExtensionWithRequestContexts(extension); | 905 profile_->RegisterExtensionWithRequestContexts(extension); |
| 1458 | 906 |
| 1459 // Tell subsystems that use the EXTENSION_LOADED notification about the new | 907 // Tell subsystems that use the EXTENSION_LOADED notification about the new |
| (...skipping 842 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2302 terminated_extensions_.clear(); | 1750 terminated_extensions_.clear(); |
| 2303 extension_runtime_data_.clear(); | 1751 extension_runtime_data_.clear(); |
| 2304 | 1752 |
| 2305 // TODO(erikkay) should there be a notification for this? We can't use | 1753 // TODO(erikkay) should there be a notification for this? We can't use |
| 2306 // EXTENSION_UNLOADED since that implies that the extension has been disabled | 1754 // EXTENSION_UNLOADED since that implies that the extension has been disabled |
| 2307 // or uninstalled, and UnloadAll is just part of shutdown. | 1755 // or uninstalled, and UnloadAll is just part of shutdown. |
| 2308 } | 1756 } |
| 2309 | 1757 |
| 2310 void ExtensionService::ReloadExtensions() { | 1758 void ExtensionService::ReloadExtensions() { |
| 2311 UnloadAllExtensions(); | 1759 UnloadAllExtensions(); |
| 2312 LoadAllExtensions(); | 1760 component_loader_->LoadComponentExtensions(); |
| 1761 MakeInstalledExtensionLoader()->LoadAllExtensions(); |
| 2313 } | 1762 } |
| 2314 | 1763 |
| 2315 void ExtensionService::GarbageCollectExtensions() { | 1764 void ExtensionService::GarbageCollectExtensions() { |
| 2316 if (extension_prefs_->pref_service()->ReadOnly()) | 1765 if (extension_prefs_->pref_service()->ReadOnly()) |
| 2317 return; | 1766 return; |
| 2318 | 1767 |
| 2319 scoped_ptr<ExtensionPrefs::ExtensionsInfo> info( | 1768 scoped_ptr<ExtensionPrefs::ExtensionsInfo> info( |
| 2320 extension_prefs_->GetInstalledExtensionsInfo()); | 1769 extension_prefs_->GetInstalledExtensionsInfo()); |
| 2321 | 1770 |
| 2322 std::map<std::string, FilePath> extension_paths; | 1771 std::map<std::string, FilePath> extension_paths; |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2508 std::set<std::string> extension_ids; | 1957 std::set<std::string> extension_ids; |
| 2509 for (size_t i = 0; i < extensions_.size(); ++i) { | 1958 for (size_t i = 0; i < extensions_.size(); ++i) { |
| 2510 if (!extensions_[i]->is_theme() && | 1959 if (!extensions_[i]->is_theme() && |
| 2511 extensions_[i]->location() != Extension::COMPONENT) | 1960 extensions_[i]->location() != Extension::COMPONENT) |
| 2512 extension_ids.insert(extensions_[i]->id()); | 1961 extension_ids.insert(extensions_[i]->id()); |
| 2513 } | 1962 } |
| 2514 | 1963 |
| 2515 child_process_logging::SetActiveExtensions(extension_ids); | 1964 child_process_logging::SetActiveExtensions(extension_ids); |
| 2516 } | 1965 } |
| 2517 | 1966 |
| 2518 void ExtensionService::OnLoadSingleExtension(const Extension* extension, | |
| 2519 bool prompt_for_plugins) { | |
| 2520 // If this is a new install of an extension with plugins, prompt the user | |
| 2521 // first. | |
| 2522 if (show_extensions_prompts_ && prompt_for_plugins && | |
| 2523 !extension->plugins().empty() && | |
| 2524 disabled_extension_paths_.find(extension->id()) == | |
| 2525 disabled_extension_paths_.end()) { | |
| 2526 SimpleExtensionLoadPrompt* prompt = new SimpleExtensionLoadPrompt( | |
| 2527 profile_, weak_ptr_factory_.GetWeakPtr(), extension); | |
| 2528 prompt->ShowPrompt(); | |
| 2529 return; // continues in SimpleExtensionLoadPrompt::InstallUI* | |
| 2530 } | |
| 2531 OnExtensionInstalled(extension, false, -1); // Not from web store. | |
| 2532 } | |
| 2533 | |
| 2534 void ExtensionService::OnExtensionInstalled( | 1967 void ExtensionService::OnExtensionInstalled( |
| 2535 const Extension* extension, bool from_webstore, int page_index) { | 1968 const Extension* extension, bool from_webstore, int page_index) { |
| 2536 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1969 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 2537 | 1970 |
| 2538 // Ensure extension is deleted unless we transfer ownership. | 1971 // Ensure extension is deleted unless we transfer ownership. |
| 2539 scoped_refptr<const Extension> scoped_extension(extension); | 1972 scoped_refptr<const Extension> scoped_extension(extension); |
| 2540 const std::string& id = extension->id(); | 1973 const std::string& id = extension->id(); |
| 2541 // Extensions installed by policy can't be disabled. So even if a previous | 1974 // Extensions installed by policy can't be disabled. So even if a previous |
| 2542 // installation disabled the extension, make sure it is now enabled. | 1975 // installation disabled the extension, make sure it is now enabled. |
| 2543 bool initial_enable = | 1976 bool initial_enable = |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2774 installer->set_expected_version(*version); | 2207 installer->set_expected_version(*version); |
| 2775 installer->set_install_cause(extension_misc::INSTALL_CAUSE_EXTERNAL_FILE); | 2208 installer->set_install_cause(extension_misc::INSTALL_CAUSE_EXTERNAL_FILE); |
| 2776 installer->set_creation_flags(creation_flags); | 2209 installer->set_creation_flags(creation_flags); |
| 2777 installer->InstallCrx(path); | 2210 installer->InstallCrx(path); |
| 2778 } | 2211 } |
| 2779 | 2212 |
| 2780 void ExtensionService::ReportExtensionLoadError( | 2213 void ExtensionService::ReportExtensionLoadError( |
| 2781 const FilePath& extension_path, | 2214 const FilePath& extension_path, |
| 2782 const std::string &error, | 2215 const std::string &error, |
| 2783 bool be_noisy) { | 2216 bool be_noisy) { |
| 2784 content::NotificationService* service = | 2217 content::NotificationService::current()->Notify( |
| 2785 content::NotificationService::current(); | 2218 chrome::NOTIFICATION_EXTENSION_LOAD_ERROR, |
| 2786 service->Notify(chrome::NOTIFICATION_EXTENSION_LOAD_ERROR, | 2219 content::Source<Profile>(profile_), |
| 2787 content::Source<Profile>(profile_), | 2220 content::Details<const std::string>(&error)); |
| 2788 content::Details<const std::string>(&error)); | |
| 2789 | 2221 |
| 2790 std::string path_str = UTF16ToUTF8(extension_path.LossyDisplayName()); | 2222 std::string path_str = UTF16ToUTF8(extension_path.LossyDisplayName()); |
| 2791 std::string message = base::StringPrintf( | 2223 std::string message = base::StringPrintf( |
| 2792 "Could not load extension from '%s'. %s", | 2224 "Could not load extension from '%s'. %s", |
| 2793 path_str.c_str(), error.c_str()); | 2225 path_str.c_str(), error.c_str()); |
| 2794 ExtensionErrorReporter::GetInstance()->ReportError(message, be_noisy); | 2226 ExtensionErrorReporter::GetInstance()->ReportError(message, be_noisy); |
| 2795 } | 2227 } |
| 2796 | 2228 |
| 2797 void ExtensionService::DidCreateRenderViewForBackgroundPage( | 2229 void ExtensionService::DidCreateRenderViewForBackgroundPage( |
| 2798 ExtensionHost* host) { | 2230 ExtensionHost* host) { |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2902 } | 2334 } |
| 2903 | 2335 |
| 2904 return result; | 2336 return result; |
| 2905 } | 2337 } |
| 2906 | 2338 |
| 2907 scoped_refptr<CrxInstaller> ExtensionService::MakeCrxInstaller( | 2339 scoped_refptr<CrxInstaller> ExtensionService::MakeCrxInstaller( |
| 2908 ExtensionInstallUI* client) { | 2340 ExtensionInstallUI* client) { |
| 2909 return new CrxInstaller(weak_ptr_factory_.GetWeakPtr(), client); | 2341 return new CrxInstaller(weak_ptr_factory_.GetWeakPtr(), client); |
| 2910 } | 2342 } |
| 2911 | 2343 |
| 2344 scoped_refptr<UnpackedInstaller> ExtensionService::MakeUnpackedInstaller() { |
| 2345 return new UnpackedInstaller(weak_ptr_factory_.GetWeakPtr()); |
| 2346 } |
| 2347 |
| 2348 scoped_refptr<InstalledExtensionLoader> |
| 2349 ExtensionService::MakeInstalledExtensionLoader() { |
| 2350 return new InstalledExtensionLoader(this, extension_prefs_); |
| 2351 } |
| 2352 |
| 2912 bool ExtensionService::IsBackgroundPageReady(const Extension* extension) { | 2353 bool ExtensionService::IsBackgroundPageReady(const Extension* extension) { |
| 2913 return (extension->background_url().is_empty() || | 2354 return (extension->background_url().is_empty() || |
| 2914 extension_runtime_data_[extension->id()].background_page_ready); | 2355 extension_runtime_data_[extension->id()].background_page_ready); |
| 2915 } | 2356 } |
| 2916 | 2357 |
| 2917 void ExtensionService::SetBackgroundPageReady(const Extension* extension) { | 2358 void ExtensionService::SetBackgroundPageReady(const Extension* extension) { |
| 2918 DCHECK(!extension->background_url().is_empty()); | 2359 DCHECK(!extension->background_url().is_empty()); |
| 2919 extension_runtime_data_[extension->id()].background_page_ready = true; | 2360 extension_runtime_data_[extension->id()].background_page_ready = true; |
| 2920 content::NotificationService::current()->Notify( | 2361 content::NotificationService::current()->Notify( |
| 2921 chrome::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY, | 2362 chrome::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY, |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3014 | 2455 |
| 3015 ExtensionService::NaClModuleInfoList::iterator | 2456 ExtensionService::NaClModuleInfoList::iterator |
| 3016 ExtensionService::FindNaClModule(const GURL& url) { | 2457 ExtensionService::FindNaClModule(const GURL& url) { |
| 3017 for (NaClModuleInfoList::iterator iter = nacl_module_list_.begin(); | 2458 for (NaClModuleInfoList::iterator iter = nacl_module_list_.begin(); |
| 3018 iter != nacl_module_list_.end(); ++iter) { | 2459 iter != nacl_module_list_.end(); ++iter) { |
| 3019 if (iter->url == url) | 2460 if (iter->url == url) |
| 3020 return iter; | 2461 return iter; |
| 3021 } | 2462 } |
| 3022 return nacl_module_list_.end(); | 2463 return nacl_module_list_.end(); |
| 3023 } | 2464 } |
| OLD | NEW |