blob: 9f0d5caed556161e3a87d17ed9333ee2d78621a1 [file] [log] [blame]
[email protected]16d900042012-01-04 21:24:321// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]6014d672008-12-05 00:38:252// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]eaa7dd182010-12-14 11:09:005#include "chrome/browser/extensions/extension_service.h"
[email protected]6014d672008-12-05 00:38:256
[email protected]654512b2010-09-01 02:09:427#include <algorithm>
[email protected]695b5712012-12-06 23:55:288#include <iterator>
[email protected]97d2f1d2011-01-15 00:41:089#include <set>
[email protected]654512b2010-09-01 02:09:4210
[email protected]24b538a2010-02-27 01:22:4411#include "base/basictypes.h"
[email protected]05aad2da2011-10-28 10:12:3712#include "base/bind.h"
[email protected]e5af875f2011-10-10 21:09:1413#include "base/callback.h"
[email protected]62433d32011-10-12 22:33:1214#include "base/command_line.h"
[email protected]6014d672008-12-05 00:38:2515#include "base/file_util.h"
[email protected]14908b72011-04-20 06:54:3616#include "base/logging.h"
[email protected]835d7c82010-10-14 04:38:3817#include "base/metrics/histogram.h"
[email protected]1e127022011-11-29 21:11:4718#include "base/path_service.h"
[email protected]7286e3fc2011-07-19 22:13:2419#include "base/stl_util.h"
[email protected]e83326f2010-07-31 17:29:2520#include "base/string_number_conversions.h"
[email protected]6014d672008-12-05 00:38:2521#include "base/string_util.h"
[email protected]18d4b6c2010-09-21 03:21:0422#include "base/stringprintf.h"
[email protected]7f8f24f2012-11-15 19:40:1423#include "base/threading/sequenced_worker_pool.h"
[email protected]34b99632011-01-01 01:01:0624#include "base/threading/thread_restrictions.h"
[email protected]cc2c3432009-11-06 17:24:3625#include "base/time.h"
[email protected]ce7f62e32010-08-10 23:43:5926#include "base/utf_string_conversions.h"
[email protected]cc655912009-01-29 23:19:1927#include "base/values.h"
[email protected]aa142702010-03-26 01:26:3328#include "base/version.h"
[email protected]a692a952011-11-28 08:23:5429#include "chrome/browser/accessibility/accessibility_extension_api.h"
[email protected]23d5f172011-10-25 05:49:5330#include "chrome/browser/bookmarks/bookmark_extension_api.h"
[email protected]e07f2da2012-08-01 22:46:1231#include "chrome/browser/bookmarks/bookmark_model_factory.h"
[email protected]15730c42009-09-03 00:03:2032#include "chrome/browser/browser_process.h"
[email protected]dfba8762011-09-02 12:49:5433#include "chrome/browser/chrome_plugin_service_filter.h"
[email protected]65992d52012-09-19 23:05:3134#include "chrome/browser/debugger/devtools_window.h"
[email protected]32b36c62012-10-24 05:37:4135#include "chrome/browser/extensions/api/app_runtime/app_runtime_api.h"
[email protected]895a1e52012-05-15 02:50:1236#include "chrome/browser/extensions/api/declarative/rules_registry_service.h"
[email protected]c77f2352012-08-08 22:07:5837#include "chrome/browser/extensions/api/extension_action/extension_actions_api.h"
[email protected]9ef82fda2012-11-30 01:55:0338#include "chrome/browser/extensions/api/font_settings/font_settings_api.h"
[email protected]31bb5ee62012-09-12 22:58:4039#include "chrome/browser/extensions/api/media_galleries_private/media_galleries_private_event_router.h"
[email protected]135e4782012-09-19 20:36:5240#include "chrome/browser/extensions/api/preference/preference_api.h"
[email protected]5ebd6a62012-08-01 23:54:3941#include "chrome/browser/extensions/api/push_messaging/push_messaging_api.h"
[email protected]e9f541a2012-11-19 21:52:3142#include "chrome/browser/extensions/api/runtime/runtime_api.h"
[email protected]af9db5f2011-10-05 05:13:1543#include "chrome/browser/extensions/app_notification_manager.h"
[email protected]5db9ada2012-04-11 13:48:2044#include "chrome/browser/extensions/app_sync_data.h"
[email protected]5a38dfd2012-07-23 23:22:1045#include "chrome/browser/extensions/browser_event_router.h"
[email protected]d8c8f25f2011-11-02 18:18:0146#include "chrome/browser/extensions/component_loader.h"
[email protected]e0785902011-05-19 23:34:1747#include "chrome/browser/extensions/crx_installer.h"
[email protected]d9ede582012-08-14 19:21:3848#include "chrome/browser/extensions/data_deleter.h"
[email protected]62f051c2012-03-29 17:04:4449#include "chrome/browser/extensions/extension_disabled_ui.h"
[email protected]14a000d2010-04-29 21:44:2450#include "chrome/browser/extensions/extension_error_reporter.h"
[email protected]89226982012-07-16 20:09:1851#include "chrome/browser/extensions/extension_error_ui.h"
[email protected]b1748b1d82009-11-30 20:32:5652#include "chrome/browser/extensions/extension_host.h"
[email protected]00b38242012-07-18 18:43:2253#include "chrome/browser/extensions/extension_install_ui.h"
[email protected]4814b512009-11-07 00:12:2954#include "chrome/browser/extensions/extension_process_manager.h"
[email protected]3569b502012-01-12 20:08:2355#include "chrome/browser/extensions/extension_sorting.h"
[email protected]19eb80152011-02-26 00:28:4356#include "chrome/browser/extensions/extension_special_storage_policy.h"
[email protected]90310d92011-04-17 07:35:0457#include "chrome/browser/extensions/extension_sync_data.h"
[email protected]31d8f5f22012-04-02 15:22:0858#include "chrome/browser/extensions/extension_system.h"
[email protected]8f9d4eb2011-02-05 01:39:1059#include "chrome/browser/extensions/extension_web_ui.h"
[email protected]612a1cb12012-10-17 13:18:0360#include "chrome/browser/extensions/external_install_ui.h"
[email protected]5df038b2012-07-16 19:03:2761#include "chrome/browser/extensions/external_provider_impl.h"
62#include "chrome/browser/extensions/external_provider_interface.h"
[email protected]d8c8f25f2011-11-02 18:18:0163#include "chrome/browser/extensions/installed_loader.h"
[email protected]6cafe35a2012-08-27 22:40:5064#include "chrome/browser/extensions/lazy_background_task_queue.h"
[email protected]fdd679b2012-11-15 20:49:3965#include "chrome/browser/extensions/management_policy.h"
[email protected]b2907fd2011-03-25 16:43:3766#include "chrome/browser/extensions/pending_extension_manager.h"
[email protected]c333e792012-01-06 16:57:3967#include "chrome/browser/extensions/permissions_updater.h"
[email protected]6cafe35a2012-08-27 22:40:5068#include "chrome/browser/extensions/platform_app_launcher.h"
[email protected]cccdf0aa2011-11-11 03:43:3869#include "chrome/browser/extensions/settings/settings_frontend.h"
[email protected]6cafe35a2012-08-27 22:40:5070#include "chrome/browser/extensions/shell_window_registry.h"
[email protected]d8c8f25f2011-11-02 18:18:0171#include "chrome/browser/extensions/unpacked_installer.h"
[email protected]42a08162012-03-16 18:09:1172#include "chrome/browser/extensions/updater/extension_updater.h"
[email protected]163ed192012-07-24 19:31:0773#include "chrome/browser/extensions/window_event_router.h"
[email protected]d2e6bd62011-10-24 20:29:0774#include "chrome/browser/history/history_extension_api.h"
[email protected]56ad3792010-05-28 17:45:3375#include "chrome/browser/net/chrome_url_request_context.h"
[email protected]37858e52010-08-26 00:22:0276#include "chrome/browser/prefs/pref_service.h"
[email protected]8ecad5e2010-12-02 21:18:3377#include "chrome/browser/profiles/profile.h"
[email protected]cf593af2011-12-30 05:44:3978#include "chrome/browser/profiles/profile_manager.h"
[email protected]8e5c89a2011-06-07 18:13:3379#include "chrome/browser/search_engines/template_url_service.h"
80#include "chrome/browser/search_engines/template_url_service_factory.h"
[email protected]d5949312012-12-03 22:13:3081#include "chrome/browser/themes/theme_service.h"
82#include "chrome/browser/themes/theme_service_factory.h"
[email protected]c8d407e2011-04-28 21:27:1783#include "chrome/browser/ui/webui/chrome_url_data_manager.h"
84#include "chrome/browser/ui/webui/favicon_source.h"
[email protected]5eddc3e2011-10-26 04:33:3185#include "chrome/browser/ui/webui/ntp/thumbnail_source.h"
[email protected]b07e606e2012-09-15 20:16:1586#include "chrome/browser/ui/webui/theme_source.h"
[email protected]aab98a52009-12-02 03:22:3587#include "chrome/common/child_process_logging.h"
[email protected]432115822011-07-10 15:52:2788#include "chrome/common/chrome_notification_types.h"
[email protected]1e127022011-11-29 21:11:4789#include "chrome/common/chrome_paths.h"
[email protected]e2eb43112009-05-29 21:19:5490#include "chrome/common/chrome_switches.h"
[email protected]15397b42012-05-16 23:56:0691#include "chrome/common/chrome_version_info.h"
[email protected]5b1a0e22009-05-26 19:00:5892#include "chrome/common/extensions/extension.h"
[email protected]7c927b62010-02-24 09:54:1393#include "chrome/common/extensions/extension_file_util.h"
[email protected]895a1e52012-05-15 02:50:1294#include "chrome/common/extensions/extension_manifest_constants.h"
[email protected]77a6970c2011-04-23 16:58:5695#include "chrome/common/extensions/extension_messages.h"
[email protected]a315ba92010-11-16 14:12:2196#include "chrome/common/extensions/extension_resource.h"
[email protected]612a1cb12012-10-17 13:18:0397#include "chrome/common/extensions/feature_switch.h"
[email protected]e9f541a2012-11-19 21:52:3198#include "chrome/common/extensions/features/feature.h"
[email protected]0db124b02012-11-07 04:55:0599#include "chrome/common/extensions/manifest.h"
[email protected]25b34332009-06-05 21:53:19100#include "chrome/common/pref_names.h"
[email protected]a57209872009-05-04 22:53:14101#include "chrome/common/url_constants.h"
[email protected]c38831a12011-10-28 12:44:49102#include "content/public/browser/browser_thread.h"
[email protected]0e12d7d2011-12-01 16:21:44103#include "content/public/browser/devtools_agent_host_registry.h"
104#include "content/public/browser/devtools_manager.h"
[email protected]05aad2da2011-10-28 10:12:37105#include "content/public/browser/notification_service.h"
[email protected]0d6e9bd2011-10-18 04:29:16106#include "content/public/browser/notification_types.h"
[email protected]3a5180ae2011-12-21 02:39:38107#include "content/public/browser/plugin_service.h"
[email protected]f3b1a082011-11-18 00:34:30108#include "content/public/browser/render_process_host.h"
[email protected]1e127022011-11-29 21:11:47109#include "content/public/common/pepper_plugin_info.h"
[email protected]e9f541a2012-11-19 21:52:31110#include "extensions/common/error_utils.h"
[email protected]c10da4b02010-03-25 14:38:32111#include "googleurl/src/gurl.h"
[email protected]65187152012-06-02 13:14:14112#include "grit/generated_resources.h"
[email protected]be28b5f42012-07-20 11:31:25113#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
[email protected]895a1e52012-05-15 02:50:12114#include "sync/api/sync_change.h"
115#include "sync/api/sync_error_factory.h"
[email protected]24b538a2010-02-27 01:22:44116#include "webkit/database/database_tracker.h"
117#include "webkit/database/database_util.h"
[email protected]79a60642012-10-20 21:03:18118
[email protected]eed367e2011-04-12 03:43:31119#if defined(OS_CHROMEOS)
[email protected]14da67b02011-08-02 05:49:13120#include "chrome/browser/chromeos/cros/cros_library.h"
[email protected]eed367e2011-04-12 03:43:31121#include "chrome/browser/chromeos/extensions/file_browser_event_router.h"
[email protected]be5bd5742011-07-14 07:21:01122#include "chrome/browser/chromeos/extensions/input_method_event_router.h"
[email protected]ce9802042011-05-27 10:11:40123#include "chrome/browser/chromeos/extensions/media_player_event_router.h"
[email protected]14da67b02011-08-02 05:49:13124#include "chrome/browser/chromeos/input_method/input_method_manager.h"
[email protected]1364c6d2012-07-24 11:57:19125#include "chrome/browser/extensions/api/input_ime/input_ime_api.h"
[email protected]10eb28162012-09-18 03:04:09126#include "content/public/browser/storage_partition.h"
[email protected]b777b332011-04-16 04:01:08127#include "webkit/fileapi/file_system_context.h"
128#include "webkit/fileapi/file_system_mount_point_provider.h"
[email protected]eed367e2011-04-12 03:43:31129#endif
130
[email protected]55eb70e762012-02-20 17:38:39131using content::BrowserContext;
[email protected]631bb742011-11-02 11:29:39132using content::BrowserThread;
[email protected]0e12d7d2011-12-01 16:21:44133using content::DevToolsAgentHost;
134using content::DevToolsAgentHostRegistry;
[email protected]3a5180ae2011-12-21 02:39:38135using content::PluginService;
[email protected]bf3d9df2012-07-24 23:20:27136using extensions::CrxInstaller;
[email protected]1c321ee52012-05-21 03:02:34137using extensions::Extension;
138using extensions::ExtensionIdSet;
139using extensions::ExtensionInfo;
[email protected]215a7be2012-10-22 19:53:42140using extensions::FeatureSwitch;
[email protected]1c321ee52012-05-21 03:02:34141using extensions::UnloadedExtensionInfo;
[email protected]c2e66e12012-06-27 06:27:06142using extensions::PermissionMessage;
143using extensions::PermissionMessages;
144using extensions::PermissionSet;
[email protected]5ef47ec2010-01-28 05:58:05145
[email protected]c6d474f82009-12-16 21:11:06146namespace errors = extension_manifest_errors;
147
[email protected]b6ab96d2009-08-20 18:58:19148namespace {
149
[email protected]d96eb512012-11-01 23:44:08150// Histogram values for logging events related to externally installed
151// extensions.
152enum ExternalExtensionEvent {
153 EXTERNAL_EXTENSION_INSTALLED = 0,
154 EXTERNAL_EXTENSION_IGNORED,
155 EXTERNAL_EXTENSION_REENABLED,
156 EXTERNAL_EXTENSION_UNINSTALLED,
157 EXTERNAL_EXTENSION_BUCKET_BOUNDARY,
158};
159
[email protected]29d0d4ac2010-09-08 21:10:31160#if defined(OS_LINUX)
161static const int kOmniboxIconPaddingLeft = 2;
162static const int kOmniboxIconPaddingRight = 2;
163#elif defined(OS_MACOSX)
164static const int kOmniboxIconPaddingLeft = 0;
165static const int kOmniboxIconPaddingRight = 2;
166#else
167static const int kOmniboxIconPaddingLeft = 0;
168static const int kOmniboxIconPaddingRight = 0;
169#endif
170
[email protected]612a1cb12012-10-17 13:18:03171// Prompt the user this many times before considering an extension acknowledged.
172static const int kMaxExtensionAcknowledgePromptCount = 3;
173
[email protected]0db124b02012-11-07 04:55:05174// Wait this many seconds after an extensions becomes idle before updating it.
175static const int kUpdateIdleDelay = 5;
176
[email protected]9bd9a6862012-11-29 09:24:22177// Wait this many seconds before trying to garbage collect extensions again.
178static const int kGarbageCollectRetryDelay = 30;
179
[email protected]300c0ea2011-07-15 23:04:33180const char* kNaClPluginMimeType = "application/x-nacl";
181
[email protected]3bdba0d2011-08-23 07:17:30182static bool IsSyncableExtension(const Extension& extension) {
183 return extension.GetSyncType() == Extension::SYNC_TYPE_EXTENSION;
184}
185
186static bool IsSyncableApp(const Extension& extension) {
187 return extension.GetSyncType() == Extension::SYNC_TYPE_APP;
188}
189
[email protected]c6d474f82009-12-16 21:11:06190} // namespace
[email protected]b6ab96d2009-08-20 18:58:19191
[email protected]eaa7dd182010-12-14 11:09:00192ExtensionService::ExtensionRuntimeData::ExtensionRuntimeData()
[email protected]d7e9a862010-11-03 21:57:49193 : background_page_ready(false),
[email protected]f8bf5992011-10-24 22:38:57194 being_upgraded(false),
195 has_used_webrequest(false) {
[email protected]d7e9a862010-11-03 21:57:49196}
197
[email protected]eaa7dd182010-12-14 11:09:00198ExtensionService::ExtensionRuntimeData::~ExtensionRuntimeData() {
[email protected]d7e9a862010-11-03 21:57:49199}
200
[email protected]cebc3dc2011-04-18 17:15:00201ExtensionService::NaClModuleInfo::NaClModuleInfo() {
202}
203
204ExtensionService::NaClModuleInfo::~NaClModuleInfo() {
205}
206
[email protected]eaa7dd182010-12-14 11:09:00207// ExtensionService.
[email protected]6014d672008-12-05 00:38:25208
[email protected]31bb5ee62012-09-12 22:58:40209const char ExtensionService::kInstallDirectoryName[] = "Extensions";
[email protected]15d5b472011-11-24 04:17:24210
[email protected]31bb5ee62012-09-12 22:58:40211const char ExtensionService::kLocalAppSettingsDirectoryName[] =
[email protected]15d5b472011-11-24 04:17:24212 "Local App Settings";
[email protected]31bb5ee62012-09-12 22:58:40213const char ExtensionService::kLocalExtensionSettingsDirectoryName[] =
[email protected]15d5b472011-11-24 04:17:24214 "Local Extension Settings";
[email protected]31bb5ee62012-09-12 22:58:40215const char ExtensionService::kSyncAppSettingsDirectoryName[] =
[email protected]15d5b472011-11-24 04:17:24216 "Sync App Settings";
[email protected]31bb5ee62012-09-12 22:58:40217const char ExtensionService::kSyncExtensionSettingsDirectoryName[] =
[email protected]15d5b472011-11-24 04:17:24218 "Sync Extension Settings";
[email protected]31bb5ee62012-09-12 22:58:40219const char ExtensionService::kStateStoreName[] = "Extension State";
[email protected]494c06e2009-07-25 01:06:42220
[email protected]8e4560b62011-01-14 10:09:14221void ExtensionService::CheckExternalUninstall(const std::string& id) {
[email protected]a29a517a2011-01-21 21:11:12222 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]a8af9fdb2010-10-28 21:52:20223
[email protected]7a4c6852010-09-16 03:44:22224 // Check if the providers know about this extension.
[email protected]5df038b2012-07-16 19:03:27225 extensions::ProviderCollection::const_iterator i;
[email protected]0a60a2e2010-10-25 16:15:21226 for (i = external_extension_providers_.begin();
227 i != external_extension_providers_.end(); ++i) {
[email protected]8e4560b62011-01-14 10:09:14228 DCHECK(i->get()->IsReady());
[email protected]0a60a2e2010-10-25 16:15:21229 if (i->get()->HasExtension(id))
230 return; // Yup, known extension, don't uninstall.
[email protected]7a4c6852010-09-16 03:44:22231 }
232
[email protected]0f48fca2011-05-19 18:46:35233 // We get the list of external extensions to check from preferences.
234 // It is possible that an extension has preferences but is not loaded.
235 // For example, an extension that requires experimental permissions
236 // will not be loaded if the experimental command line flag is not used.
237 // In this case, do not uninstall.
[email protected]31bb5ee62012-09-12 22:58:40238 if (!GetInstalledExtension(id)) {
[email protected]0f48fca2011-05-19 18:46:35239 // We can't call UninstallExtension with an unloaded/invalid
240 // extension ID.
241 LOG(WARNING) << "Attempted uninstallation of unloaded/invalid extension "
242 << "with id: " << id;
243 return;
244 }
[email protected]d6ebc9792011-04-07 18:18:33245 UninstallExtension(id, true, NULL);
[email protected]7a4c6852010-09-16 03:44:22246}
247
[email protected]7f8f24f2012-11-15 19:40:14248void ExtensionService::SetFileTaskRunnerForTesting(
249 base::SequencedTaskRunner* task_runner) {
250 file_task_runner_ = task_runner;
251}
252
[email protected]8e4560b62011-01-14 10:09:14253void ExtensionService::ClearProvidersForTesting() {
[email protected]7a4c6852010-09-16 03:44:22254 external_extension_providers_.clear();
255}
256
[email protected]8e4560b62011-01-14 10:09:14257void ExtensionService::AddProviderForTesting(
[email protected]5df038b2012-07-16 19:03:27258 extensions::ExternalProviderInterface* test_provider) {
[email protected]a29a517a2011-01-21 21:11:12259 CHECK(test_provider);
[email protected]0a60a2e2010-10-25 16:15:21260 external_extension_providers_.push_back(
[email protected]5df038b2012-07-16 19:03:27261 linked_ptr<extensions::ExternalProviderInterface>(test_provider));
[email protected]7a4c6852010-09-16 03:44:22262}
263
[email protected]9060d8b02012-01-13 02:14:30264bool ExtensionService::OnExternalExtensionUpdateUrlFound(
[email protected]7a4c6852010-09-16 03:44:22265 const std::string& id,
[email protected]21a5a672010-11-04 10:47:42266 const GURL& update_url,
267 Extension::Location location) {
[email protected]ab22ba42011-01-14 16:36:38268 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
269 CHECK(Extension::IdIsValid(id));
[email protected]a8af9fdb2010-10-28 21:52:20270
[email protected]8a87a5332011-08-11 17:54:59271 const Extension* extension = GetExtensionById(id, true);
272 if (extension) {
273 // Already installed. Skip this install if the current location has
274 // higher priority than |location|.
275 Extension::Location current = extension->location();
276 if (current == Extension::GetHigherPriorityLocation(current, location))
[email protected]9060d8b02012-01-13 02:14:30277 return false;
[email protected]8a87a5332011-08-11 17:54:59278 // Otherwise, overwrite the current installation.
[email protected]7a4c6852010-09-16 03:44:22279 }
[email protected]9060d8b02012-01-13 02:14:30280
281 // Add |id| to the set of pending extensions. If it can not be added,
282 // then there is already a pending record from a higher-priority install
283 // source. In this case, signal that this extension will not be
284 // installed by returning false.
285 if (!pending_extension_manager()->AddFromExternalUpdateUrl(
[email protected]31bb5ee62012-09-12 22:58:40286 id, update_url, location)) {
[email protected]9060d8b02012-01-13 02:14:30287 return false;
[email protected]31bb5ee62012-09-12 22:58:40288 }
[email protected]9060d8b02012-01-13 02:14:30289
[email protected]94fde232012-04-27 10:22:30290 update_once_all_providers_are_ready_ = true;
[email protected]9060d8b02012-01-13 02:14:30291 return true;
[email protected]7a4c6852010-09-16 03:44:22292}
293
[email protected]dc9a74f72012-08-17 18:07:21294const Extension* ExtensionService::GetInstalledApp(const GURL& url) const {
[email protected]615d88f2011-12-13 01:47:44295 const Extension* extension = extensions_.GetExtensionOrAppByURL(
296 ExtensionURLInfo(url));
[email protected]dc9a74f72012-08-17 18:07:21297 return (extension && extension->is_app()) ? extension : NULL;
[email protected]d9696672011-03-15 22:45:09298}
299
[email protected]dc9a74f72012-08-17 18:07:21300bool ExtensionService::IsInstalledApp(const GURL& url) const {
[email protected]d9696672011-03-15 22:45:09301 return !!GetInstalledApp(url);
[email protected]ffb204f22010-12-05 23:20:27302}
303
[email protected]404fb002012-10-02 21:06:17304const Extension* ExtensionService::GetIsolatedAppForRenderer(
[email protected]dc9a74f72012-08-17 18:07:21305 int renderer_child_id) const {
[email protected]404fb002012-10-02 21:06:17306 std::set<std::string> extension_ids =
307 process_map_.GetExtensionsInProcess(renderer_child_id);
308 // All apps in one process share the same partition.
309 // It is only possible for the app to have isolated storage
310 // if there is only 1 app in the process.
311 if (extension_ids.size() != 1)
312 return NULL;
313
314 const extensions::Extension* extension =
315 extensions_.GetByID(*(extension_ids.begin()));
316 // We still need to check is_storage_isolated(),
317 // because it's common for there to be one extension in a process
318 // with is_storage_isolated() == false.
319 if (extension && extension->is_storage_isolated())
320 return extension;
321
322 return NULL;
[email protected]da5683db2011-04-23 17:12:21323}
324
[email protected]6aeac8342010-10-01 20:21:18325// static
[email protected]d6ebc9792011-04-07 18:18:33326// This function is used to implement the command-line switch
[email protected]3bdba0d2011-08-23 07:17:30327// --uninstall-extension, and to uninstall an extension via sync. The LOG
328// statements within this function are used to inform the user if the uninstall
329// cannot be done.
[email protected]eaa7dd182010-12-14 11:09:00330bool ExtensionService::UninstallExtensionHelper(
331 ExtensionService* extensions_service,
[email protected]6aeac8342010-10-01 20:21:18332 const std::string& extension_id) {
[email protected]d6ebc9792011-04-07 18:18:33333 // We can't call UninstallExtension with an invalid extension ID.
[email protected]31bb5ee62012-09-12 22:58:40334 if (!extensions_service->GetInstalledExtension(extension_id)) {
[email protected]6aeac8342010-10-01 20:21:18335 LOG(WARNING) << "Attempted uninstallation of non-existent extension with "
[email protected]95da88c42011-03-31 10:07:33336 << "id: " << extension_id;
337 return false;
[email protected]6aeac8342010-10-01 20:21:18338 }
339
[email protected]d6ebc9792011-04-07 18:18:33340 // The following call to UninstallExtension will not allow an uninstall of a
341 // policy-controlled extension.
[email protected]65187152012-06-02 13:14:14342 string16 error;
[email protected]d6ebc9792011-04-07 18:18:33343 if (!extensions_service->UninstallExtension(extension_id, false, &error)) {
344 LOG(WARNING) << "Cannot uninstall extension with id " << extension_id
345 << ": " << error;
346 return false;
347 }
[email protected]95da88c42011-03-31 10:07:33348
[email protected]6aeac8342010-10-01 20:21:18349 return true;
350}
351
[email protected]eaa7dd182010-12-14 11:09:00352ExtensionService::ExtensionService(Profile* profile,
[email protected]f0841cd2011-01-19 15:07:24353 const CommandLine* command_line,
354 const FilePath& install_directory,
[email protected]45759612012-07-10 17:21:23355 extensions::ExtensionPrefs* extension_prefs,
[email protected]fdd679b2012-11-15 20:49:39356 extensions::Blacklist* blacklist,
[email protected]0436b102011-04-15 18:30:03357 bool autoupdate_enabled,
358 bool extensions_enabled)
[email protected]fdd679b2012-11-15 20:49:39359 : extensions::Blacklist::Observer(blacklist),
360 profile_(profile),
[email protected]bd306722012-07-11 20:43:59361 system_(extensions::ExtensionSystem::Get(profile)),
[email protected]73c47932010-12-06 18:13:43362 extension_prefs_(extension_prefs),
[email protected]695b5712012-12-06 23:55:28363 blacklist_(blacklist),
[email protected]cccdf0aa2011-11-11 03:43:38364 settings_frontend_(extensions::SettingsFrontend::Create(profile)),
[email protected]14908b72011-04-20 06:54:36365 pending_extension_manager_(*ALLOW_THIS_IN_INITIALIZER_LIST(this)),
[email protected]a9b00ac2009-06-25 21:03:23366 install_directory_(install_directory),
[email protected]0436b102011-04-15 18:30:03367 extensions_enabled_(extensions_enabled),
[email protected]e81dba32009-06-19 20:19:13368 show_extensions_prompts_(true),
[email protected]fc332ae2012-11-14 20:17:33369 install_updates_when_idle_(true),
[email protected]3ecda252010-11-18 19:50:55370 ready_(false),
[email protected]14908b72011-04-20 06:54:36371 toolbar_model_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
[email protected]8b280302011-10-13 22:22:23372 menu_manager_(profile),
[email protected]8d92e0382012-08-01 18:06:52373 app_notification_manager_(
374 new extensions::AppNotificationManager(profile)),
[email protected]7c1490da2011-10-11 18:53:25375 event_routers_initialized_(false),
[email protected]dff1e042012-04-27 10:59:18376 update_once_all_providers_are_ready_(false),
[email protected]3c4abc82012-10-22 22:25:54377 browser_terminating_(false),
[email protected]1ff4d282012-12-08 00:39:21378 wipeout_is_active_(false),
[email protected]5db9ada2012-04-11 13:48:20379 app_sync_bundle_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
380 extension_sync_bundle_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
[email protected]178f8512012-02-09 01:49:36381 app_shortcut_manager_(profile) {
[email protected]a29a517a2011-01-21 21:11:12382 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]a8af9fdb2010-10-28 21:52:20383
[email protected]36a784c2009-06-23 06:21:08384 // Figure out if extension installation should be enabled.
[email protected]31bb5ee62012-09-12 22:58:40385 if (command_line->HasSwitch(switches::kDisableExtensions) ||
386 profile->GetPrefs()->GetBoolean(prefs::kDisableExtensions)) {
[email protected]6d60703b2009-08-29 01:29:23387 extensions_enabled_ = false;
[email protected]6b75ec32009-08-14 06:37:18388 }
[email protected]36a784c2009-06-23 06:21:08389
[email protected]3c4abc82012-10-22 22:25:54390 registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
391 content::NotificationService::AllBrowserContextsAndSources());
[email protected]432115822011-07-10 15:52:27392 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED,
[email protected]ad50def52011-10-19 23:17:07393 content::NotificationService::AllBrowserContextsAndSources());
[email protected]432115822011-07-10 15:52:27394 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CREATED,
[email protected]ad50def52011-10-19 23:17:07395 content::NotificationService::AllBrowserContextsAndSources());
[email protected]432115822011-07-10 15:52:27396 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
[email protected]ad50def52011-10-19 23:17:07397 content::NotificationService::AllBrowserContextsAndSources());
[email protected]0db124b02012-11-07 04:55:05398 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED,
399 content::NotificationService::AllBrowserContextsAndSources());
[email protected]2fb7dc982010-09-29 12:24:28400 pref_change_registrar_.Init(profile->GetPrefs());
[email protected]90bb38d2012-11-14 18:36:03401 base::Closure callback =
402 base::Bind(&ExtensionService::OnExtensionInstallPrefChanged,
403 base::Unretained(this));
404 pref_change_registrar_.Add(prefs::kExtensionInstallAllowList, callback);
405 pref_change_registrar_.Add(prefs::kExtensionInstallDenyList, callback);
[email protected]4814b512009-11-07 00:12:29406
[email protected]93fd78f42009-07-10 16:43:17407 // Set up the ExtensionUpdater
408 if (autoupdate_enabled) {
409 int update_frequency = kDefaultUpdateFrequencySeconds;
410 if (command_line->HasSwitch(switches::kExtensionsUpdateFrequency)) {
[email protected]e83326f2010-07-31 17:29:25411 base::StringToInt(command_line->GetSwitchValueASCII(
412 switches::kExtensionsUpdateFrequency),
413 &update_frequency);
[email protected]93fd78f42009-07-10 16:43:17414 }
[email protected]42a08162012-03-16 18:09:11415 updater_.reset(new extensions::ExtensionUpdater(this,
416 extension_prefs,
417 profile->GetPrefs(),
418 profile,
[email protected]fdd679b2012-11-15 20:49:39419 blacklist,
[email protected]42a08162012-03-16 18:09:11420 update_frequency));
[email protected]93fd78f42009-07-10 16:43:17421 }
422
[email protected]25ae0152011-11-18 14:40:02423 component_loader_.reset(
424 new extensions::ComponentLoader(this,
425 profile->GetPrefs(),
426 g_browser_process->local_state()));
[email protected]8e4560b62011-01-14 10:09:14427
[email protected]af9db5f2011-10-05 05:13:15428 app_notification_manager_->Init();
429
[email protected]0436b102011-04-15 18:30:03430 if (extensions_enabled_) {
[email protected]1f2f3002011-12-28 00:40:21431 if (!command_line->HasSwitch(switches::kImport) &&
432 !command_line->HasSwitch(switches::kImportFromFile)) {
[email protected]5df038b2012-07-16 19:03:27433 extensions::ExternalProviderImpl::CreateExternalProviders(
[email protected]1f2f3002011-12-28 00:40:21434 this, profile_, &external_extension_providers_);
435 }
[email protected]873531342011-03-09 12:16:05436 }
[email protected]b671760b2010-07-15 21:13:47437
[email protected]aa96d3a2010-08-21 08:45:25438 // Use monochrome icons for Omnibox icons.
[email protected]29d0d4ac2010-09-08 21:10:31439 omnibox_popup_icon_manager_.set_monochrome(true);
[email protected]b671760b2010-07-15 21:13:47440 omnibox_icon_manager_.set_monochrome(true);
[email protected]29d0d4ac2010-09-08 21:10:31441 omnibox_icon_manager_.set_padding(gfx::Insets(0, kOmniboxIconPaddingLeft,
442 0, kOmniboxIconPaddingRight));
[email protected]cb0e50312011-05-09 15:03:07443
[email protected]fb82dcd2012-03-21 14:15:46444 // Set this as the ExtensionService for extension sorting to ensure it
445 // cause syncs if required.
446 extension_prefs_->extension_sorting()->SetExtensionService(this);
447
[email protected]9ce11d22012-08-08 23:20:13448#if defined(ENABLE_EXTENSIONS)
[email protected]c77f2352012-08-08 22:07:58449 extension_action_storage_manager_.reset(
450 new extensions::ExtensionActionStorageManager(profile_));
[email protected]9ce11d22012-08-08 23:20:13451#endif
[email protected]c77f2352012-08-08 22:07:58452
[email protected]1ff4d282012-12-08 00:39:21453 // Before loading any extensions, determine whether Sideload Wipeout is on.
454 wipeout_is_active_ = FeatureSwitch::sideload_wipeout()->IsEnabled() &&
455 !extension_prefs_->GetSideloadWipeoutDone();
456
[email protected]cb0e50312011-05-09 15:03:07457 // How long is the path to the Extensions directory?
458 UMA_HISTOGRAM_CUSTOM_COUNTS("Extensions.ExtensionRootPathLength",
459 install_directory_.value().length(), 0, 500, 100);
[email protected]6014d672008-12-05 00:38:25460}
461
[email protected]84df8332011-12-06 18:22:46462const ExtensionSet* ExtensionService::extensions() const {
[email protected]ddb1e5a2010-12-13 20:10:45463 return &extensions_;
464}
465
[email protected]84df8332011-12-06 18:22:46466const ExtensionSet* ExtensionService::disabled_extensions() const {
[email protected]ddb1e5a2010-12-13 20:10:45467 return &disabled_extensions_;
468}
469
[email protected]84df8332011-12-06 18:22:46470const ExtensionSet* ExtensionService::terminated_extensions() const {
[email protected]bb7f40952011-01-13 00:21:20471 return &terminated_extensions_;
472}
473
[email protected]695b5712012-12-06 23:55:28474const ExtensionSet* ExtensionService::blacklisted_extensions() const {
475 return &blacklisted_extensions_;
476}
477
478scoped_ptr<const ExtensionSet>
479 ExtensionService::GenerateInstalledExtensionsSet() const {
480 scoped_ptr<ExtensionSet> installed_extensions(new ExtensionSet());
[email protected]7f4308d2012-01-18 07:43:01481 installed_extensions->InsertAll(extensions_);
482 installed_extensions->InsertAll(disabled_extensions_);
483 installed_extensions->InsertAll(terminated_extensions_);
[email protected]695b5712012-12-06 23:55:28484 installed_extensions->InsertAll(blacklisted_extensions_);
485 return installed_extensions.PassAs<const ExtensionSet>();
[email protected]7f4308d2012-01-18 07:43:01486}
487
[email protected]695b5712012-12-06 23:55:28488scoped_ptr<const ExtensionSet> ExtensionService::GetWipedOutExtensions() const {
489 scoped_ptr<ExtensionSet> extension_set(new ExtensionSet());
[email protected]215a7be2012-10-22 19:53:42490 for (ExtensionSet::const_iterator iter = disabled_extensions_.begin();
491 iter != disabled_extensions_.end(); ++iter) {
492 int disabled_reason = extension_prefs_->GetDisableReasons((*iter)->id());
493 if ((disabled_reason & Extension::DISABLE_SIDELOAD_WIPEOUT) != 0)
494 extension_set->Insert(*iter);
495 }
[email protected]695b5712012-12-06 23:55:28496 return extension_set.PassAs<const ExtensionSet>();
[email protected]215a7be2012-10-22 19:53:42497}
498
[email protected]3f213ad2012-07-26 23:39:41499extensions::PendingExtensionManager*
500 ExtensionService::pending_extension_manager() {
[email protected]b2907fd2011-03-25 16:43:37501 return &pending_extension_manager_;
[email protected]ddb1e5a2010-12-13 20:10:45502}
503
[email protected]eaa7dd182010-12-14 11:09:00504ExtensionService::~ExtensionService() {
[email protected]c8d407e2011-04-28 21:27:17505 // No need to unload extensions here because they are profile-scoped, and the
506 // profile is in the process of being deleted.
[email protected]94b4ffc2011-02-04 05:55:17507
[email protected]5df038b2012-07-16 19:03:27508 extensions::ProviderCollection::const_iterator i;
[email protected]8e4560b62011-01-14 10:09:14509 for (i = external_extension_providers_.begin();
510 i != external_extension_providers_.end(); ++i) {
[email protected]5df038b2012-07-16 19:03:27511 extensions::ExternalProviderInterface* provider = i->get();
[email protected]8e4560b62011-01-14 10:09:14512 provider->ServiceShutdown();
513 }
[email protected]6014d672008-12-05 00:38:25514}
515
[email protected]d91268022011-08-26 13:17:37516void ExtensionService::InitEventRoutersAfterImport() {
[email protected]cf593af2011-12-30 05:44:39517 RegisterForImportFinished();
518}
519
520void ExtensionService::RegisterForImportFinished() {
521 if (!registrar_.IsRegistered(this, chrome::NOTIFICATION_IMPORT_FINISHED,
522 content::Source<Profile>(profile_))) {
523 registrar_.Add(this, chrome::NOTIFICATION_IMPORT_FINISHED,
524 content::Source<Profile>(profile_));
525 }
526}
527
528void ExtensionService::InitAfterImport() {
529 CheckForExternalUpdates();
530
531 GarbageCollectExtensions();
532
533 // Idempotent, so although there is a possible race if the import
534 // process finished sometime in the middle of ProfileImpl::InitExtensions,
535 // it cannot happen twice.
536 InitEventRouters();
[email protected]d91268022011-08-26 13:17:37537}
538
[email protected]eaa7dd182010-12-14 11:09:00539void ExtensionService::InitEventRouters() {
[email protected]b3d62312b12010-10-14 21:10:18540 if (event_routers_initialized_)
541 return;
542
[email protected]6a3cd37e2012-04-17 17:13:34543#if defined(ENABLE_EXTENSIONS)
[email protected]79a60642012-10-20 21:03:18544 history_event_router_.reset(new HistoryExtensionEventRouter(profile_));
[email protected]5a38dfd2012-07-23 23:22:10545 browser_event_router_.reset(new extensions::BrowserEventRouter(profile_));
[email protected]163ed192012-07-24 19:31:07546 window_event_router_.reset(new extensions::WindowEventRouter(profile_));
[email protected]135e4782012-09-19 20:36:52547 preference_event_router_.reset(
548 new extensions::PreferenceEventRouter(profile_));
[email protected]23d5f172011-10-25 05:49:53549 bookmark_event_router_.reset(new BookmarkExtensionEventRouter(
[email protected]e07f2da2012-08-01 22:46:12550 BookmarkModelFactory::GetForProfile(profile_)));
[email protected]9ef82fda2012-11-30 01:55:03551 font_settings_event_router_.reset(
552 new extensions::FontSettingsEventRouter(profile_));
[email protected]5ebd6a62012-08-01 23:54:39553 push_messaging_event_router_.reset(
554 new extensions::PushMessagingEventRouter(profile_));
[email protected]31bb5ee62012-09-12 22:58:40555 media_galleries_private_event_router_.reset(
556 new extensions::MediaGalleriesPrivateEventRouter(profile_));
[email protected]27072cad2011-05-09 19:46:40557
[email protected]eed367e2011-04-12 03:43:31558#if defined(OS_CHROMEOS)
[email protected]2a72c9f2012-03-17 15:10:30559 FileBrowserEventRouterFactory::GetForProfile(
560 profile_)->ObserveFileSystemEvents();
[email protected]771a6182011-10-05 16:32:52561
562 input_method_event_router_.reset(
563 new chromeos::ExtensionInputMethodEventRouter);
[email protected]be5bd5742011-07-14 07:21:01564
[email protected]c8bf09be2011-06-25 03:22:27565 ExtensionMediaPlayerEventRouter::GetInstance()->Init(profile_);
[email protected]1364c6d2012-07-24 11:57:19566 extensions::InputImeEventRouter::GetInstance()->Init();
[email protected]31bb5ee62012-09-12 22:58:40567#endif // defined(OS_CHROMEOS)
[email protected]6a3cd37e2012-04-17 17:13:34568#endif // defined(ENABLE_EXTENSIONS)
[email protected]b3d62312b12010-10-14 21:10:18569 event_routers_initialized_ = true;
[email protected]c5ae74ab2010-04-15 18:14:37570}
571
[email protected]037228a2012-10-05 01:36:16572void ExtensionService::OnProfileSyncServiceShutdown() {
573 // TODO(akalin): Move this block to Shutdown() once
574 // http://crbug.com/153827 is fixed.
[email protected]b5f12622012-08-23 20:59:33575 if (push_messaging_event_router_.get())
576 push_messaging_event_router_->Shutdown();
[email protected]47b896562012-08-22 23:55:15577}
578
[email protected]037228a2012-10-05 01:36:16579void ExtensionService::Shutdown() {
580 // Do nothing for now.
581}
582
[email protected]b2907fd2011-03-25 16:43:37583const Extension* ExtensionService::GetExtensionById(
584 const std::string& id, bool include_disabled) const {
[email protected]81f0d162012-08-15 04:21:47585 int include_mask = INCLUDE_ENABLED;
[email protected]695b5712012-12-06 23:55:28586 if (include_disabled) {
587 // Include blacklisted extensions here because there are hundreds of
588 // callers of this function, and many might assume that this includes those
589 // that have been disabled due to blacklisting.
590 include_mask |= INCLUDE_DISABLED | INCLUDE_BLACKLISTED;
591 }
592 return GetExtensionById(id, include_mask);
593}
594
595const Extension* ExtensionService::GetExtensionById(
596 const std::string& id, int include_mask) const {
597 std::string lowercase_id = StringToLowerASCII(id);
598 if (include_mask & INCLUDE_ENABLED) {
599 const Extension* extension = extensions_.GetByID(lowercase_id);
600 if (extension)
601 return extension;
602 }
603 if (include_mask & INCLUDE_DISABLED) {
604 const Extension* extension = disabled_extensions_.GetByID(lowercase_id);
605 if (extension)
606 return extension;
607 }
608 if (include_mask & INCLUDE_TERMINATED) {
609 const Extension* extension = terminated_extensions_.GetByID(lowercase_id);
610 if (extension)
611 return extension;
612 }
613 if (include_mask & INCLUDE_BLACKLISTED) {
614 const Extension* extension = blacklisted_extensions_.GetByID(lowercase_id);
615 if (extension)
616 return extension;
617 }
618 return NULL;
[email protected]78994ab02010-12-08 18:06:44619}
620
[email protected]eaa7dd182010-12-14 11:09:00621void ExtensionService::Init() {
[email protected]a29a517a2011-01-21 21:11:12622 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]a8af9fdb2010-10-28 21:52:20623
[email protected]fa6a9102010-11-22 15:38:50624 DCHECK(!ready_); // Can't redo init.
[email protected]93fd78f42009-07-10 16:43:17625 DCHECK_EQ(extensions_.size(), 0u);
[email protected]9f1087e2009-06-15 17:29:32626
[email protected]0db124b02012-11-07 04:55:05627 // TODO(mek): It might be cleaner to do the FinishIdleInstallInfo stuff here
628 // instead of in installedloader
[email protected]d8c8f25f2011-11-02 18:18:01629 component_loader_->LoadAll();
630 extensions::InstalledLoader(this).LoadAllExtensions();
[email protected]894bb502009-05-21 22:39:57631
[email protected]215a7be2012-10-22 19:53:42632 // The Sideload Wipeout effort takes place during load (see above), so once
633 // that is done the flag can be set so that we don't have to check again.
[email protected]1ff4d282012-12-08 00:39:21634 if (wipeout_is_active_) {
[email protected]215a7be2012-10-22 19:53:42635 extension_prefs_->SetSideloadWipeoutDone();
[email protected]1ff4d282012-12-08 00:39:21636 wipeout_is_active_ = false; // Wipeout is only on during load.
637 }
[email protected]215a7be2012-10-22 19:53:42638
[email protected]7a161db2011-12-15 20:45:51639 // If we are running in the import process, don't bother initializing the
640 // extension service since this can interfere with the main browser process
641 // that is already running an extension service for this profile.
642 // TODO(aa): can we start up even less of ExtensionService?
643 // http://crbug.com/107636
[email protected]1f2f3002011-12-28 00:40:21644 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kImport) &&
645 !CommandLine::ForCurrentProcess()->HasSwitch(switches::kImportFromFile)) {
[email protected]cf593af2011-12-30 05:44:39646 if (g_browser_process->profile_manager() &&
647 g_browser_process->profile_manager()->will_import()) {
648 RegisterForImportFinished();
649 } else {
[email protected]1f4728f2012-12-05 20:40:05650 // TODO(erikkay) this should probably be deferred to a future point
651 // rather than running immediately at startup.
652 CheckForExternalUpdates();
[email protected]894bb502009-05-21 22:39:57653
[email protected]1f4728f2012-12-05 20:40:05654 // TODO(erikkay) this should probably be deferred as well.
655 GarbageCollectExtensions();
[email protected]cf593af2011-12-30 05:44:39656 }
[email protected]7a161db2011-12-15 20:45:51657 }
[email protected]6014d672008-12-05 00:38:25658}
659
[email protected]31bb5ee62012-09-12 22:58:40660bool ExtensionService::UpdateExtension(const std::string& id,
661 const FilePath& extension_path,
662 const GURL& download_url,
663 CrxInstaller** out_crx_installer) {
[email protected]a29a517a2011-01-21 21:11:12664 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]3c4abc82012-10-22 22:25:54665 if (browser_terminating_) {
666 LOG(WARNING) << "Skipping UpdateExtension due to browser shutdown";
667 // Leak the temp file at extension_path. We don't want to add to the disk
668 // I/O burden at shutdown, we can't rely on the I/O completing anyway, and
669 // the file is in the OS temp directory which should be cleaned up for us.
670 return false;
671 }
[email protected]a8af9fdb2010-10-28 21:52:20672
[email protected]3f213ad2012-07-26 23:39:41673 const extensions::PendingExtensionInfo* pending_extension_info =
[email protected]51a3bf8b2012-06-08 22:53:06674 pending_extension_manager()->GetById(id);
[email protected]8ef78fd2010-08-19 17:14:32675
[email protected]695b5712012-12-06 23:55:28676 const Extension* extension = GetInstalledExtension(id);
[email protected]51a3bf8b2012-06-08 22:53:06677 if (!pending_extension_info && !extension) {
[email protected]aa142702010-03-26 01:26:33678 LOG(WARNING) << "Will not update extension " << id
679 << " because it is not installed or pending";
680 // Delete extension_path since we're not creating a CrxInstaller
681 // that would do it for us.
[email protected]7f8f24f2012-11-15 19:40:14682 if (!GetFileTaskRunner()->PostTask(
683 FROM_HERE,
[email protected]53612e82011-10-18 18:00:36684 base::Bind(
[email protected]7296f2762011-11-21 19:23:44685 &extension_file_util::DeleteFile, extension_path, false)))
[email protected]14908b72011-04-20 06:54:36686 NOTREACHED();
[email protected]420a0ec2011-06-01 01:07:03687
688 return false;
[email protected]e957fe52009-06-23 16:51:05689 }
690
[email protected]aa142702010-03-26 01:26:33691 // We want a silent install only for non-pending extensions and
692 // pending extensions that have install_silently set.
[email protected]91e51d612012-10-21 23:03:05693 ExtensionInstallPrompt* client = NULL;
694 if (pending_extension_info && !pending_extension_info->install_silently())
695 client = ExtensionInstallUI::CreateInstallPromptWithProfile(profile_);
[email protected]aa142702010-03-26 01:26:33696
[email protected]d8c8f25f2011-11-02 18:18:01697 scoped_refptr<CrxInstaller> installer(CrxInstaller::Create(this, client));
[email protected]6dfbbf82010-03-12 23:09:16698 installer->set_expected_id(id);
[email protected]51a3bf8b2012-06-08 22:53:06699 if (pending_extension_info) {
700 installer->set_install_source(pending_extension_info->install_source());
701 if (pending_extension_info->install_silently())
702 installer->set_allow_silent_install(true);
703 } else if (extension) {
[email protected]5eb375e92010-11-26 07:50:41704 installer->set_install_source(extension->location());
[email protected]51a3bf8b2012-06-08 22:53:06705 }
[email protected]7d8b7072012-04-07 01:07:46706 // If the extension was installed from or has migrated to the webstore, or
[email protected]fcb2c2c2012-10-17 21:08:45707 // its auto-update URL is from the webstore, treat it as a webstore install.
708 // Note that we ignore some older extensions with blank auto-update URLs
709 // because we are mostly concerned with restrictions on NaCl extensions,
710 // which are newer.
[email protected]a12ce8b22012-01-17 18:40:53711 int creation_flags = Extension::NO_FLAGS;
[email protected]75764512011-12-19 19:54:28712 if ((extension && extension->from_webstore()) ||
[email protected]7d8b7072012-04-07 01:07:46713 (extension && extension->UpdatesFromGallery()) ||
[email protected]963d13c2012-09-29 17:13:35714 (!extension && extension_urls::IsWebstoreUpdateUrl(
[email protected]51a3bf8b2012-06-08 22:53:06715 pending_extension_info->update_url()))) {
[email protected]a12ce8b22012-01-17 18:40:53716 creation_flags |= Extension::FROM_WEBSTORE;
717 }
718
719 // Bookmark apps being updated is kind of a contradiction, but that's because
720 // we mark the default apps as bookmark apps, and they're hosted in the web
721 // store, thus they can get updated. See http://crbug.com/101605 for more
722 // details.
723 if (extension && extension->from_bookmark())
724 creation_flags |= Extension::FROM_BOOKMARK;
725
[email protected]e33bbc22012-08-27 22:05:46726 if (extension && extension->was_installed_by_default())
727 creation_flags |= Extension::WAS_INSTALLED_BY_DEFAULT;
728
[email protected]a12ce8b22012-01-17 18:40:53729 installer->set_creation_flags(creation_flags);
730
[email protected]6dfbbf82010-03-12 23:09:16731 installer->set_delete_source(true);
[email protected]655b2b1a2011-10-13 17:13:06732 installer->set_download_url(download_url);
[email protected]cb0e50312011-05-09 15:03:07733 installer->set_install_cause(extension_misc::INSTALL_CAUSE_UPDATE);
[email protected]6dfbbf82010-03-12 23:09:16734 installer->InstallCrx(extension_path);
[email protected]420a0ec2011-06-01 01:07:03735
736 if (out_crx_installer)
737 *out_crx_installer = installer;
738
739 return true;
[email protected]e957fe52009-06-23 16:51:05740}
741
[email protected]eaa7dd182010-12-14 11:09:00742void ExtensionService::ReloadExtension(const std::string& extension_id) {
[email protected]32b36c62012-10-24 05:37:41743 int events = HasShellWindows(extension_id) ? EVENT_LAUNCHED : EVENT_NONE;
744 ReloadExtensionWithEvents(extension_id, events);
745}
746
747void ExtensionService::RestartExtension(const std::string& extension_id) {
748 int events = HasShellWindows(extension_id) ? EVENT_RESTARTED : EVENT_NONE;
749 ReloadExtensionWithEvents(extension_id, events);
750}
751
752void ExtensionService::ReloadExtensionWithEvents(
753 const std::string& extension_id,
754 int events) {
[email protected]a29a517a2011-01-21 21:11:12755 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]b65272f2009-08-31 15:47:06756 FilePath path;
[email protected]9adb9692010-10-29 23:14:02757 const Extension* current_extension = GetExtensionById(extension_id, false);
[email protected]9cddd4702009-07-27 22:09:40758
[email protected]f17dbd42010-08-16 23:21:10759 // Disable the extension if it's loaded. It might not be loaded if it crashed.
[email protected]b65272f2009-08-31 15:47:06760 if (current_extension) {
[email protected]4814b512009-11-07 00:12:29761 // If the extension has an inspector open for its background page, detach
762 // the inspector and hang onto a cookie for it, so that we can reattach
763 // later.
[email protected]31d8f5f22012-04-02 15:22:08764 // TODO(yoz): this is not incognito-safe!
765 ExtensionProcessManager* manager = system_->process_manager();
[email protected]3a1dc572012-07-31 22:25:13766 extensions::ExtensionHost* host =
767 manager->GetBackgroundHostForExtension(extension_id);
[email protected]0e12d7d2011-12-01 16:21:44768 if (host && DevToolsAgentHostRegistry::HasDevToolsAgentHost(
769 host->render_view_host())) {
[email protected]4814b512009-11-07 00:12:29770 // Look for an open inspector for the background page.
[email protected]0e12d7d2011-12-01 16:21:44771 DevToolsAgentHost* agent =
772 DevToolsAgentHostRegistry::GetDevToolsAgentHost(
773 host->render_view_host());
774 int devtools_cookie =
775 content::DevToolsManager::GetInstance()->DetachClientHost(agent);
[email protected]4814b512009-11-07 00:12:29776 if (devtools_cookie >= 0)
777 orphaned_dev_tools_[extension_id] = devtools_cookie;
778 }
779
[email protected]32b36c62012-10-24 05:37:41780 on_load_events_[extension_id] = events;
[email protected]6cafe35a2012-08-27 22:40:50781
[email protected]b65272f2009-08-31 15:47:06782 path = current_extension->path();
[email protected]44d62b62012-04-11 00:06:03783 DisableExtension(extension_id, Extension::DISABLE_RELOAD);
[email protected]f17dbd42010-08-16 23:21:10784 disabled_extension_paths_[extension_id] = path;
[email protected]1eb175082010-02-10 09:26:16785 } else {
786 path = unloaded_extension_paths_[extension_id];
[email protected]b65272f2009-08-31 15:47:06787 }
788
[email protected]0db124b02012-11-07 04:55:05789 if (pending_extension_updates_.Contains(extension_id)) {
[email protected]6f6101832012-11-27 22:10:48790 FinishDelayedInstallation(extension_id);
[email protected]0db124b02012-11-07 04:55:05791 return;
792 }
793
[email protected]43ceb002012-02-10 23:19:15794 // If we're reloading a component extension, use the component extension
795 // loader's reloader.
796 if (component_loader_->Exists(extension_id)) {
797 component_loader_->Reload(extension_id);
798 return;
799 }
800
[email protected]e6090e42010-03-23 22:44:08801 // Check the installed extensions to see if what we're reloading was already
802 // installed.
803 scoped_ptr<ExtensionInfo> installed_extension(
804 extension_prefs_->GetInstalledExtensionInfo(extension_id));
805 if (installed_extension.get() &&
806 installed_extension->extension_manifest.get()) {
[email protected]d8c8f25f2011-11-02 18:18:01807 extensions::InstalledLoader(this).Load(*installed_extension, false);
[email protected]e6090e42010-03-23 22:44:08808 } else {
[email protected]d8c8f25f2011-11-02 18:18:01809 // Otherwise, the extension is unpacked (location LOAD).
[email protected]e6090e42010-03-23 22:44:08810 // We should always be able to remember the extension's path. If it's not in
811 // the map, someone failed to update |unloaded_extension_paths_|.
812 CHECK(!path.empty());
[email protected]d8c8f25f2011-11-02 18:18:01813 extensions::UnpackedInstaller::Create(this)->Load(path);
[email protected]e6090e42010-03-23 22:44:08814 }
[email protected]9cddd4702009-07-27 22:09:40815}
816
[email protected]fa2416f2011-05-03 08:41:20817bool ExtensionService::UninstallExtension(
[email protected]a12c706e2011-12-01 00:58:08818 std::string extension_id,
[email protected]fa2416f2011-05-03 08:41:20819 bool external_uninstall,
[email protected]65187152012-06-02 13:14:14820 string16* error) {
[email protected]a29a517a2011-01-21 21:11:12821 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]a8af9fdb2010-10-28 21:52:20822
[email protected]0d6ec3a72011-09-02 02:09:43823 scoped_refptr<const Extension> extension(GetInstalledExtension(extension_id));
[email protected]631cf822009-05-15 07:01:25824
[email protected]e7afe2452010-08-22 16:19:13825 // Callers should not send us nonexistent extensions.
[email protected]aebe23a32010-12-10 22:15:48826 CHECK(extension);
[email protected]9f1087e2009-06-15 17:29:32827
[email protected]95da88c42011-03-31 10:07:33828 // Policy change which triggers an uninstall will always set
829 // |external_uninstall| to true so this is the only way to uninstall
830 // managed extensions.
[email protected]65187152012-06-02 13:14:14831 if (!external_uninstall &&
832 !system_->management_policy()->UserMayModifySettings(
833 extension.get(), error)) {
[email protected]ad50def52011-10-19 23:17:07834 content::NotificationService::current()->Notify(
[email protected]432115822011-07-10 15:52:27835 chrome::NOTIFICATION_EXTENSION_UNINSTALL_NOT_ALLOWED,
[email protected]6c2381d2011-10-19 02:52:53836 content::Source<Profile>(profile_),
837 content::Details<const Extension>(extension));
[email protected]d6ebc9792011-04-07 18:18:33838 return false;
839 }
[email protected]95da88c42011-03-31 10:07:33840
[email protected]3bdba0d2011-08-23 07:17:30841 // Extract the data we need for sync now, but don't actually sync until we've
842 // completed the uninstallation.
[email protected]65f173552012-06-28 22:43:58843 syncer::SyncChange sync_change;
[email protected]5db9ada2012-04-11 13:48:20844 if (app_sync_bundle_.HandlesApp(*extension)) {
845 sync_change = app_sync_bundle_.CreateSyncChangeToDelete(extension);
846 } else if (extension_sync_bundle_.HandlesExtension(*extension)) {
847 sync_change = extension_sync_bundle_.CreateSyncChangeToDelete(extension);
[email protected]3bdba0d2011-08-23 07:17:30848 }
849
[email protected]d96eb512012-11-01 23:44:08850 if (IsUnacknowledgedExternalExtension(extension)) {
851 UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalExtensionEvent",
852 EXTERNAL_EXTENSION_UNINSTALLED,
853 EXTERNAL_EXTENSION_BUCKET_BOUNDARY);
854 }
[email protected]9b217652010-10-08 22:04:23855 UMA_HISTOGRAM_ENUMERATION("Extensions.UninstallType",
[email protected]7fa19f82010-12-21 19:40:08856 extension->GetType(), 100);
[email protected]fe2dd7742011-04-19 22:52:49857 RecordPermissionMessagesHistogram(
858 extension, "Extensions.Permissions_Uninstall");
[email protected]9b217652010-10-08 22:04:23859
[email protected]8e5c89a2011-06-07 18:13:33860 TemplateURLService* url_service =
861 TemplateURLServiceFactory::GetForProfile(profile_);
862 if (url_service)
863 url_service->UnregisterExtensionKeyword(extension);
[email protected]56ad3792010-05-28 17:45:33864
[email protected]831aa212010-03-26 13:55:19865 // Unload before doing more cleanup to ensure that nothing is hanging on to
866 // any of these resources.
[email protected]814a7bf0f2011-08-13 05:30:59867 UnloadExtension(extension_id, extension_misc::UNLOAD_REASON_UNINSTALL);
[email protected]831aa212010-03-26 13:55:19868
[email protected]0d6ec3a72011-09-02 02:09:43869 extension_prefs_->OnExtensionUninstalled(extension_id, extension->location(),
[email protected]831aa212010-03-26 13:55:19870 external_uninstall);
[email protected]9f1087e2009-06-15 17:29:32871
872 // Tell the backend to start deleting installed extensions on the file thread.
[email protected]0d6ec3a72011-09-02 02:09:43873 if (Extension::LOAD != extension->location()) {
[email protected]7f8f24f2012-11-15 19:40:14874 if (!GetFileTaskRunner()->PostTask(
875 FROM_HERE,
[email protected]53612e82011-10-18 18:00:36876 base::Bind(
[email protected]14908b72011-04-20 06:54:36877 &extension_file_util::UninstallExtension,
878 install_directory_,
[email protected]fa2416f2011-05-03 08:41:20879 extension_id)))
[email protected]14908b72011-04-20 06:54:36880 NOTREACHED();
[email protected]9f1087e2009-06-15 17:29:32881 }
882
[email protected]0d6ec3a72011-09-02 02:09:43883 GURL launch_web_url_origin(extension->launch_web_url());
884 launch_web_url_origin = launch_web_url_origin.GetOrigin();
[email protected]605fb8102012-05-04 01:36:55885 bool is_storage_isolated = extension->is_storage_isolated();
[email protected]0d6ec3a72011-09-02 02:09:43886
887 if (extension->is_hosted_app() &&
888 !profile_->GetExtensionSpecialStoragePolicy()->
889 IsStorageProtected(launch_web_url_origin)) {
[email protected]d9ede582012-08-14 19:21:38890 extensions::DataDeleter::StartDeleting(
[email protected]dc0b5a12011-10-14 00:06:13891 profile_, extension_id, launch_web_url_origin, is_storage_isolated);
[email protected]0d6ec3a72011-09-02 02:09:43892 }
[email protected]d9ede582012-08-14 19:21:38893 extensions::DataDeleter::StartDeleting(
[email protected]dc0b5a12011-10-14 00:06:13894 profile_, extension_id, extension->url(), is_storage_isolated);
[email protected]0d6ec3a72011-09-02 02:09:43895
[email protected]0dfe05c2011-02-23 23:03:36896 UntrackTerminatedExtension(extension_id);
[email protected]211030342010-09-30 18:41:06897
898 // Notify interested parties that we've uninstalled this extension.
[email protected]ad50def52011-10-19 23:17:07899 content::NotificationService::current()->Notify(
[email protected]432115822011-07-10 15:52:27900 chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
[email protected]6c2381d2011-10-19 02:52:53901 content::Source<Profile>(profile_),
[email protected]d67d9412012-07-17 17:19:42902 content::Details<const Extension>(extension));
[email protected]d6ebc9792011-04-07 18:18:33903
[email protected]5db9ada2012-04-11 13:48:20904 if (app_sync_bundle_.HasExtensionId(extension_id) &&
[email protected]a4a147652012-07-03 23:41:32905 sync_change.sync_data().GetDataType() == syncer::APPS) {
[email protected]5db9ada2012-04-11 13:48:20906 app_sync_bundle_.ProcessDeletion(extension_id, sync_change);
907 } else if (extension_sync_bundle_.HasExtensionId(extension_id) &&
[email protected]a4a147652012-07-03 23:41:32908 sync_change.sync_data().GetDataType() == syncer::EXTENSIONS) {
[email protected]5db9ada2012-04-11 13:48:20909 extension_sync_bundle_.ProcessDeletion(extension_id, sync_change);
[email protected]3bdba0d2011-08-23 07:17:30910 }
911
[email protected]0db124b02012-11-07 04:55:05912 pending_extension_updates_.Remove(extension_id);
913
[email protected]333b1de2011-09-12 18:28:50914 // Track the uninstallation.
[email protected]49098f702011-10-13 03:47:18915 UMA_HISTOGRAM_ENUMERATION("Extensions.ExtensionUninstalled", 1, 2);
916
[email protected]d6ebc9792011-04-07 18:18:33917 return true;
[email protected]c10da4b02010-03-25 14:38:32918}
919
[email protected]c3cfb012011-04-06 22:07:35920bool ExtensionService::IsExtensionEnabled(
921 const std::string& extension_id) const {
[email protected]84df8332011-12-06 18:22:46922 if (extensions_.Contains(extension_id) ||
[email protected]dc9a74f72012-08-17 18:07:21923 terminated_extensions_.Contains(extension_id)) {
[email protected]36429da2011-07-11 20:25:18924 return true;
[email protected]dc9a74f72012-08-17 18:07:21925 }
[email protected]36429da2011-07-11 20:25:18926
[email protected]695b5712012-12-06 23:55:28927 if (disabled_extensions_.Contains(extension_id) ||
928 blacklisted_extensions_.Contains(extension_id)) {
[email protected]ad83ca242011-07-29 01:32:25929 return false;
[email protected]695b5712012-12-06 23:55:28930 }
[email protected]ad83ca242011-07-29 01:32:25931
932 // If the extension hasn't been loaded yet, check the prefs for it. Assume
933 // enabled unless otherwise noted.
934 return !extension_prefs_->IsExtensionDisabled(extension_id) &&
[email protected]f574c402012-12-04 23:20:31935 !extension_prefs_->IsExternalExtensionUninstalled(extension_id);
[email protected]c3cfb012011-04-06 22:07:35936}
937
938bool ExtensionService::IsExternalExtensionUninstalled(
939 const std::string& extension_id) const {
940 return extension_prefs_->IsExternalExtensionUninstalled(extension_id);
941}
942
[email protected]eaa7dd182010-12-14 11:09:00943void ExtensionService::EnableExtension(const std::string& extension_id) {
[email protected]a29a517a2011-01-21 21:11:12944 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]a8af9fdb2010-10-28 21:52:20945
[email protected]06f92562011-04-29 19:27:31946 if (IsExtensionEnabled(extension_id))
[email protected]0c6da502009-08-14 22:32:39947 return;
[email protected]0c6da502009-08-14 22:32:39948
[email protected]c0231d72012-11-26 22:37:57949 int disable_reasons = extension_prefs_->GetDisableReasons(extension_id);
[email protected]b3317ad2011-04-28 23:46:00950 extension_prefs_->SetExtensionState(extension_id, Extension::ENABLED);
[email protected]eb5e4f92012-08-15 23:33:28951 extension_prefs_->ClearDisableReasons(extension_id);
[email protected]1784e83a2009-09-08 21:01:52952
[email protected]695b5712012-12-06 23:55:28953 const Extension* extension = disabled_extensions_.GetByID(extension_id);
[email protected]06f92562011-04-29 19:27:31954 // This can happen if sync enables an extension that is not
955 // installed yet.
956 if (!extension)
957 return;
958
[email protected]d96eb512012-11-01 23:44:08959 if (IsUnacknowledgedExternalExtension(extension)) {
960 UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalExtensionEvent",
961 EXTERNAL_EXTENSION_REENABLED,
962 EXTERNAL_EXTENSION_BUCKET_BOUNDARY);
[email protected]612a1cb12012-10-17 13:18:03963 AcknowledgeExternalExtension(extension->id());
[email protected]d96eb512012-11-01 23:44:08964 }
[email protected]612a1cb12012-10-17 13:18:03965
[email protected]c0231d72012-11-26 22:37:57966 if (disable_reasons & Extension::DISABLE_SIDELOAD_WIPEOUT)
[email protected]94e14592012-11-19 10:49:42967 UMA_HISTOGRAM_BOOLEAN("DisabledExtension.ExtensionWipedStatus", false);
968
[email protected]0c6da502009-08-14 22:32:39969 // Move it over to the enabled list.
[email protected]84df8332011-12-06 18:22:46970 extensions_.Insert(make_scoped_refptr(extension));
971 disabled_extensions_.Remove(extension->id());
[email protected]0c6da502009-08-14 22:32:39972
[email protected]62d30f42009-10-01 22:36:06973 NotifyExtensionLoaded(extension);
[email protected]3bdba0d2011-08-23 07:17:30974
[email protected]f74d7f32012-06-19 19:22:51975 // Notify listeners that the extension was enabled.
976 content::NotificationService::current()->Notify(
977 chrome::NOTIFICATION_EXTENSION_ENABLED,
978 content::Source<Profile>(profile_),
979 content::Details<const Extension>(extension));
980
[email protected]3bdba0d2011-08-23 07:17:30981 SyncExtensionChangeIfNeeded(*extension);
[email protected]0c6da502009-08-14 22:32:39982}
983
[email protected]44d62b62012-04-11 00:06:03984void ExtensionService::DisableExtension(
985 const std::string& extension_id,
986 Extension::DisableReason disable_reason) {
[email protected]a29a517a2011-01-21 21:11:12987 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]a8af9fdb2010-10-28 21:52:20988
[email protected]b2ba9962009-12-10 20:10:15989 // The extension may have been disabled already.
[email protected]06f92562011-04-29 19:27:31990 if (!IsExtensionEnabled(extension_id))
[email protected]1784e83a2009-09-08 21:01:52991 return;
[email protected]1784e83a2009-09-08 21:01:52992
[email protected]06f92562011-04-29 19:27:31993 const Extension* extension = GetInstalledExtension(extension_id);
994 // |extension| can be NULL if sync disables an extension that is not
995 // installed yet.
[email protected]65187152012-06-02 13:14:14996 if (extension &&
997 !system_->management_policy()->UserMayModifySettings(extension, NULL)) {
[email protected]95da88c42011-03-31 10:07:33998 return;
[email protected]65187152012-06-02 13:14:14999 }
[email protected]95da88c42011-03-31 10:07:331000
[email protected]b3317ad2011-04-28 23:46:001001 extension_prefs_->SetExtensionState(extension_id, Extension::DISABLED);
[email protected]eb5e4f92012-08-15 23:33:281002 extension_prefs_->AddDisableReason(extension_id, disable_reason);
[email protected]1784e83a2009-09-08 21:01:521003
[email protected]695b5712012-12-06 23:55:281004 int include_mask = INCLUDE_EVERYTHING & ~INCLUDE_DISABLED;
1005 extension = GetExtensionById(extension_id, include_mask);
[email protected]06f92562011-04-29 19:27:311006 if (!extension)
1007 return;
1008
[email protected]5c094792012-09-07 19:44:531009 // Move it over to the disabled list. Don't send a second unload notification
1010 // for terminated extensions being disabled.
[email protected]84df8332011-12-06 18:22:461011 disabled_extensions_.Insert(make_scoped_refptr(extension));
[email protected]5c094792012-09-07 19:44:531012 if (extensions_.Contains(extension->id())) {
[email protected]84df8332011-12-06 18:22:461013 extensions_.Remove(extension->id());
[email protected]5c094792012-09-07 19:44:531014 NotifyExtensionUnloaded(extension, extension_misc::UNLOAD_REASON_DISABLE);
1015 } else {
[email protected]84df8332011-12-06 18:22:461016 terminated_extensions_.Remove(extension->id());
[email protected]5c094792012-09-07 19:44:531017 }
[email protected]3bdba0d2011-08-23 07:17:301018
1019 SyncExtensionChangeIfNeeded(*extension);
[email protected]1784e83a2009-09-08 21:01:521020}
1021
[email protected]eaa7dd182010-12-14 11:09:001022void ExtensionService::GrantPermissionsAndEnableExtension(
[email protected]b70a2d92012-06-28 19:51:211023 const Extension* extension, bool record_oauth2_grant) {
[email protected]be083862012-09-01 03:53:451024 GrantPermissions(extension, record_oauth2_grant);
[email protected]fe2dd7742011-04-19 22:52:491025 RecordPermissionMessagesHistogram(
1026 extension, "Extensions.Permissions_ReEnable");
[email protected]8d888c12010-11-30 00:00:251027 extension_prefs_->SetDidExtensionEscalatePermissions(extension, false);
1028 EnableExtension(extension->id());
1029}
1030
[email protected]be083862012-09-01 03:53:451031void ExtensionService::GrantPermissions(const Extension* extension,
1032 bool record_oauth2_grant) {
1033 CHECK(extension);
1034 extensions::PermissionsUpdater perms_updater(profile());
1035 perms_updater.GrantActivePermissions(extension, record_oauth2_grant);
1036}
1037
[email protected]fe2dd7742011-04-19 22:52:491038// static
1039void ExtensionService::RecordPermissionMessagesHistogram(
1040 const Extension* e, const char* histogram) {
1041 // Since this is called from multiple sources, and since the Histogram macros
1042 // use statics, we need to manually lookup the Histogram ourselves.
1043 base::Histogram* counter = base::LinearHistogram::FactoryGet(
1044 histogram,
1045 1,
[email protected]c2e66e12012-06-27 06:27:061046 PermissionMessage::kEnumBoundary,
1047 PermissionMessage::kEnumBoundary + 1,
[email protected]fe2dd7742011-04-19 22:52:491048 base::Histogram::kUmaTargetedHistogramFlag);
1049
[email protected]c2e66e12012-06-27 06:27:061050 PermissionMessages permissions = e->GetPermissionMessages();
[email protected]fe2dd7742011-04-19 22:52:491051 if (permissions.empty()) {
[email protected]c2e66e12012-06-27 06:27:061052 counter->Add(PermissionMessage::kNone);
[email protected]fe2dd7742011-04-19 22:52:491053 } else {
[email protected]c2e66e12012-06-27 06:27:061054 for (PermissionMessages::iterator it = permissions.begin();
[email protected]0d3e4a22011-06-23 19:02:521055 it != permissions.end(); ++it)
1056 counter->Add(it->id());
[email protected]fe2dd7742011-04-19 22:52:491057 }
1058}
1059
[email protected]eaa7dd182010-12-14 11:09:001060void ExtensionService::NotifyExtensionLoaded(const Extension* extension) {
[email protected]57a777f72010-03-31 01:09:421061 // The ChromeURLRequestContexts need to be first to know that the extension
[email protected]62d30f42009-10-01 22:36:061062 // was loaded, otherwise a race can arise where a renderer that is created
1063 // for the extension may try to load an extension URL with an extension id
[email protected]57a777f72010-03-31 01:09:421064 // that the request context doesn't yet know about. The profile is responsible
1065 // for ensuring its URLRequestContexts appropriately discover the loaded
1066 // extension.
[email protected]31d8f5f22012-04-02 15:22:081067 system_->RegisterExtensionWithRequestContexts(extension);
[email protected]62d30f42009-10-01 22:36:061068
[email protected]d5949312012-12-03 22:13:301069 // Tell renderers about the new extension, unless it's a theme (renderers
1070 // don't need to know about themes).
[email protected]a58f599c2012-12-01 03:08:191071 if (!extension->is_theme()) {
[email protected]19647262011-12-16 09:57:491072 for (content::RenderProcessHost::iterator i(
1073 content::RenderProcessHost::AllHostsIterator());
1074 !i.IsAtEnd(); i.Advance()) {
1075 content::RenderProcessHost* host = i.GetCurrentValue();
1076 Profile* host_profile =
1077 Profile::FromBrowserContext(host->GetBrowserContext());
1078 if (host_profile->GetOriginalProfile() ==
1079 profile_->GetOriginalProfile()) {
1080 std::vector<ExtensionMsg_Loaded_Params> loaded_extensions(
1081 1, ExtensionMsg_Loaded_Params(extension));
1082 host->Send(
1083 new ExtensionMsg_Loaded(loaded_extensions));
1084 }
[email protected]c8d407e2011-04-28 21:27:171085 }
[email protected]77a6970c2011-04-23 16:58:561086 }
1087
[email protected]3442a662012-01-12 08:06:171088 // Tell subsystems that use the EXTENSION_LOADED notification about the new
1089 // extension.
1090 //
1091 // NOTE: It is important that this happen after notifying the renderers about
1092 // the new extensions so that if we navigate to an extension URL in
1093 // NOTIFICATION_EXTENSION_LOADED, the renderer is guaranteed to know about it.
1094 content::NotificationService::current()->Notify(
1095 chrome::NOTIFICATION_EXTENSION_LOADED,
1096 content::Source<Profile>(profile_),
1097 content::Details<const Extension>(extension));
1098
[email protected]c8d407e2011-04-28 21:27:171099 // Tell a random-ass collection of other subsystems about the new extension.
1100 // TODO(aa): What should we do with all this goop? Can it move into the
1101 // relevant objects via EXTENSION_LOADED?
1102
1103 profile_->GetExtensionSpecialStoragePolicy()->
1104 GrantRightsForExtension(extension);
1105
1106 UpdateActiveExtensionsInCrashReporter();
1107
1108 ExtensionWebUI::RegisterChromeURLOverrides(
1109 profile_, extension->GetChromeURLOverrides());
1110
[email protected]8e5c89a2011-06-07 18:13:331111 TemplateURLService* url_service =
1112 TemplateURLServiceFactory::GetForProfile(profile_);
1113 if (url_service)
1114 url_service->RegisterExtensionKeyword(extension);
[email protected]c8d407e2011-04-28 21:27:171115
1116 // Load the icon for omnibox-enabled extensions so it will be ready to display
1117 // in the URL bar.
1118 if (!extension->omnibox_keyword().empty()) {
1119 omnibox_popup_icon_manager_.LoadIcon(extension);
1120 omnibox_icon_manager_.LoadIcon(extension);
1121 }
1122
1123 // If the extension has permission to load chrome://favicon/ resources we need
1124 // to make sure that the FaviconSource is registered with the
1125 // ChromeURLDataManager.
1126 if (extension->HasHostPermission(GURL(chrome::kChromeUIFaviconURL))) {
1127 FaviconSource* favicon_source = new FaviconSource(profile_,
1128 FaviconSource::FAVICON);
[email protected]ef92e172012-04-25 19:40:411129 ChromeURLDataManager::AddDataSource(profile_, favicon_source);
[email protected]c8d407e2011-04-28 21:27:171130 }
[email protected]b07e606e2012-09-15 20:16:151131
1132#if !defined(OS_ANDROID)
1133 // Same for chrome://theme/ resources.
1134 if (extension->HasHostPermission(GURL(chrome::kChromeUIThemeURL))) {
1135 ThemeSource* theme_source = new ThemeSource(profile_);
1136 ChromeURLDataManager::AddDataSource(profile_, theme_source);
1137 }
1138#endif
1139
[email protected]5eddc3e2011-10-26 04:33:311140 // Same for chrome://thumb/ resources.
1141 if (extension->HasHostPermission(GURL(chrome::kChromeUIThumbnailURL))) {
1142 ThumbnailSource* thumbnail_source = new ThumbnailSource(profile_);
[email protected]ef92e172012-04-25 19:40:411143 ChromeURLDataManagerFactory::GetForProfile(profile_)->
1144 AddDataSource(thumbnail_source);
[email protected]5eddc3e2011-10-26 04:33:311145 }
[email protected]c8d407e2011-04-28 21:27:171146
1147 // TODO(mpcomplete): This ends up affecting all profiles. See crbug.com/80757.
[email protected]2de307592011-04-05 21:16:581148 bool plugins_changed = false;
1149 for (size_t i = 0; i < extension->plugins().size(); ++i) {
1150 const Extension::PluginInfo& plugin = extension->plugins()[i];
[email protected]f520b5b2011-11-08 02:42:141151 PluginService::GetInstance()->RefreshPlugins();
1152 PluginService::GetInstance()->AddExtraPluginPath(plugin.path);
[email protected]2de307592011-04-05 21:16:581153 plugins_changed = true;
[email protected]476a27032011-09-13 13:40:491154 ChromePluginServiceFilter* filter =
1155 ChromePluginServiceFilter::GetInstance();
1156 if (plugin.is_public) {
1157 filter->RestrictPluginToProfileAndOrigin(
1158 plugin.path, profile_, GURL());
1159 } else {
1160 filter->RestrictPluginToProfileAndOrigin(
1161 plugin.path, profile_, extension->url());
[email protected]2de307592011-04-05 21:16:581162 }
1163 }
[email protected]84396dbc2011-04-14 06:33:421164
1165 bool nacl_modules_changed = false;
1166 for (size_t i = 0; i < extension->nacl_modules().size(); ++i) {
1167 const Extension::NaClModuleInfo& module = extension->nacl_modules()[i];
[email protected]cebc3dc2011-04-18 17:15:001168 RegisterNaClModule(module.url, module.mime_type);
[email protected]84396dbc2011-04-14 06:33:421169 nacl_modules_changed = true;
1170 }
1171
[email protected]ed0ba002011-05-26 16:55:131172 if (nacl_modules_changed)
1173 UpdatePluginListWithNaClModules();
[email protected]84396dbc2011-04-14 06:33:421174
1175 if (plugins_changed || nacl_modules_changed)
[email protected]45a22e62011-10-12 09:48:021176 PluginService::GetInstance()->PurgePluginListCache(profile_, false);
[email protected]b4d9d122011-06-17 01:58:541177
[email protected]14da67b02011-08-02 05:49:131178#if defined(OS_CHROMEOS)
[email protected]b4d9d122011-06-17 01:58:541179 for (std::vector<Extension::InputComponentInfo>::const_iterator component =
1180 extension->input_components().begin();
1181 component != extension->input_components().end();
1182 ++component) {
[email protected]14da67b02011-08-02 05:49:131183 if (component->type == Extension::INPUT_COMPONENT_TYPE_IME) {
[email protected]1364c6d2012-07-24 11:57:191184 extensions::InputImeEventRouter::GetInstance()->RegisterIme(
[email protected]14da67b02011-08-02 05:49:131185 profile_, extension->id(), *component);
1186 }
[email protected]b4d9d122011-06-17 01:58:541187 }
1188#endif
[email protected]62d30f42009-10-01 22:36:061189}
1190
[email protected]a9f39a312010-12-23 22:14:271191void ExtensionService::NotifyExtensionUnloaded(
[email protected]814a7bf0f2011-08-13 05:30:591192 const Extension* extension,
1193 extension_misc::UnloadedExtensionReason reason) {
[email protected]a9f39a312010-12-23 22:14:271194 UnloadedExtensionInfo details(extension, reason);
[email protected]ad50def52011-10-19 23:17:071195 content::NotificationService::current()->Notify(
[email protected]432115822011-07-10 15:52:271196 chrome::NOTIFICATION_EXTENSION_UNLOADED,
[email protected]6c2381d2011-10-19 02:52:531197 content::Source<Profile>(profile_),
1198 content::Details<UnloadedExtensionInfo>(&details));
[email protected]62d30f42009-10-01 22:36:061199
[email protected]903d70a2012-12-04 13:00:171200#if defined(ENABLE_THEMES)
1201 // If the current theme is being unloaded, tell ThemeService to revert back
1202 // to the default theme.
1203 if (reason != extension_misc::UNLOAD_REASON_UPDATE && extension->is_theme()) {
1204 ThemeService* theme_service = ThemeServiceFactory::GetForProfile(profile_);
1205 if (extension->id() == theme_service->GetThemeID())
1206 theme_service->UseDefaultTheme();
1207 }
1208#endif
1209
[email protected]f3b1a082011-11-18 00:34:301210 for (content::RenderProcessHost::iterator i(
1211 content::RenderProcessHost::AllHostsIterator());
[email protected]77a6970c2011-04-23 16:58:561212 !i.IsAtEnd(); i.Advance()) {
[email protected]f3b1a082011-11-18 00:34:301213 content::RenderProcessHost* host = i.GetCurrentValue();
[email protected]9b62ecf2011-07-27 20:23:081214 Profile* host_profile =
[email protected]f3b1a082011-11-18 00:34:301215 Profile::FromBrowserContext(host->GetBrowserContext());
[email protected]9b62ecf2011-07-27 20:23:081216 if (host_profile->GetOriginalProfile() == profile_->GetOriginalProfile())
[email protected]c8d407e2011-04-28 21:27:171217 host->Send(new ExtensionMsg_Unloaded(extension->id()));
[email protected]77a6970c2011-04-23 16:58:561218 }
1219
[email protected]31d8f5f22012-04-02 15:22:081220 system_->UnregisterExtensionWithRequestContexts(extension->id(), reason);
[email protected]c8d407e2011-04-28 21:27:171221 profile_->GetExtensionSpecialStoragePolicy()->
1222 RevokeRightsForExtension(extension);
1223
1224 ExtensionWebUI::UnregisterChromeURLOverrides(
1225 profile_, extension->GetChromeURLOverrides());
1226
[email protected]b777b332011-04-16 04:01:081227#if defined(OS_CHROMEOS)
[email protected]10eb28162012-09-18 03:04:091228 // Revoke external file access to third party extensions.
1229 fileapi::FileSystemContext* filesystem_context =
1230 BrowserContext::GetDefaultStoragePartition(profile_)->
1231 GetFileSystemContext();
1232 if (filesystem_context && filesystem_context->external_provider()) {
1233 filesystem_context->external_provider()->
[email protected]c8d407e2011-04-28 21:27:171234 RevokeAccessForExtension(extension->id());
[email protected]62d30f42009-10-01 22:36:061235 }
[email protected]54ccafa2011-12-06 23:36:321236
1237 if (extension->input_components().size() > 0) {
[email protected]1364c6d2012-07-24 11:57:191238 extensions::InputImeEventRouter::GetInstance()->UnregisterAllImes(
[email protected]54ccafa2011-12-06 23:36:321239 profile_, extension->id());
1240 }
[email protected]c8d407e2011-04-28 21:27:171241#endif
1242
1243 UpdateActiveExtensionsInCrashReporter();
[email protected]2de307592011-04-05 21:16:581244
1245 bool plugins_changed = false;
1246 for (size_t i = 0; i < extension->plugins().size(); ++i) {
1247 const Extension::PluginInfo& plugin = extension->plugins()[i];
[email protected]b6a2f8de2012-01-31 17:28:491248 PluginService::GetInstance()->ForcePluginShutdown(plugin.path);
[email protected]f520b5b2011-11-08 02:42:141249 PluginService::GetInstance()->RefreshPlugins();
1250 PluginService::GetInstance()->RemoveExtraPluginPath(plugin.path);
[email protected]2de307592011-04-05 21:16:581251 plugins_changed = true;
[email protected]476a27032011-09-13 13:40:491252 ChromePluginServiceFilter::GetInstance()->UnrestrictPlugin(plugin.path);
[email protected]2de307592011-04-05 21:16:581253 }
[email protected]84396dbc2011-04-14 06:33:421254
1255 bool nacl_modules_changed = false;
1256 for (size_t i = 0; i < extension->nacl_modules().size(); ++i) {
1257 const Extension::NaClModuleInfo& module = extension->nacl_modules()[i];
[email protected]cebc3dc2011-04-18 17:15:001258 UnregisterNaClModule(module.url);
[email protected]84396dbc2011-04-14 06:33:421259 nacl_modules_changed = true;
1260 }
1261
[email protected]ed0ba002011-05-26 16:55:131262 if (nacl_modules_changed)
1263 UpdatePluginListWithNaClModules();
[email protected]84396dbc2011-04-14 06:33:421264
1265 if (plugins_changed || nacl_modules_changed)
[email protected]45a22e62011-10-12 09:48:021266 PluginService::GetInstance()->PurgePluginListCache(profile_, false);
[email protected]62d30f42009-10-01 22:36:061267}
1268
[email protected]0a071a32011-02-08 00:18:241269Profile* ExtensionService::profile() {
1270 return profile_;
1271}
1272
[email protected]45759612012-07-10 17:21:231273extensions::ExtensionPrefs* ExtensionService::extension_prefs() {
[email protected]ddb1e5a2010-12-13 20:10:451274 return extension_prefs_;
1275}
1276
[email protected]0d9a2202011-11-09 13:48:411277extensions::SettingsFrontend* ExtensionService::settings_frontend() {
[email protected]cccdf0aa2011-11-11 03:43:381278 return settings_frontend_.get();
[email protected]b7f853e282011-08-10 09:24:201279}
1280
[email protected]e2d720aa2012-05-17 00:11:351281extensions::ContentSettingsStore* ExtensionService::GetContentSettingsStore() {
[email protected]b790b072011-05-20 09:46:441282 return extension_prefs()->content_settings_store();
1283}
1284
[email protected]25ae0152011-11-18 14:40:021285bool ExtensionService::is_ready() {
1286 return ready_;
1287}
1288
[email protected]7f8f24f2012-11-15 19:40:141289base::SequencedTaskRunner* ExtensionService::GetFileTaskRunner() {
1290 if (file_task_runner_)
1291 return file_task_runner_;
1292
1293 // We should be able to interrupt any part of extension install process during
1294 // shutdown. SKIP_ON_SHUTDOWN ensures that not started extension install tasks
1295 // will be ignored/deleted while we will block on started tasks.
1296 std::string token("ext_install-");
1297 token.append(profile_->GetPath().AsUTF8Unsafe());
1298 file_task_runner_ = BrowserThread::GetBlockingPool()->
1299 GetSequencedTaskRunnerWithShutdownBehavior(
1300 BrowserThread::GetBlockingPool()->GetNamedSequenceToken(token),
1301 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
1302 return file_task_runner_;
1303}
1304
[email protected]42a08162012-03-16 18:09:111305extensions::ExtensionUpdater* ExtensionService::updater() {
[email protected]2859946f2011-04-04 18:18:061306 return updater_.get();
1307}
1308
[email protected]4ee07c62012-08-21 12:40:421309void ExtensionService::CheckManagementPolicy() {
[email protected]aa96d3a2010-08-21 08:45:251310 std::vector<std::string> to_be_removed;
[email protected]695b5712012-12-06 23:55:281311
[email protected]aa96d3a2010-08-21 08:45:251312 // Loop through extensions list, unload installed extensions.
[email protected]84df8332011-12-06 18:22:461313 for (ExtensionSet::const_iterator iter = extensions_.begin();
[email protected]aa96d3a2010-08-21 08:45:251314 iter != extensions_.end(); ++iter) {
[email protected]9adb9692010-10-29 23:14:021315 const Extension* extension = (*iter);
[email protected]4ee07c62012-08-21 12:40:421316 if (!system_->management_policy()->UserMayLoad(extension, NULL))
[email protected]aa96d3a2010-08-21 08:45:251317 to_be_removed.push_back(extension->id());
1318 }
1319
1320 // UnloadExtension will change the extensions_ list. So, we should
1321 // call it outside the iterator loop.
[email protected]31bb5ee62012-09-12 22:58:401322 for (size_t i = 0; i < to_be_removed.size(); ++i)
[email protected]814a7bf0f2011-08-13 05:30:591323 UnloadExtension(to_be_removed[i], extension_misc::UNLOAD_REASON_DISABLE);
[email protected]aa96d3a2010-08-21 08:45:251324}
1325
[email protected]31206602011-04-13 23:07:321326void ExtensionService::CheckForUpdatesSoon() {
[email protected]c3cfb012011-04-06 22:07:351327 if (updater()) {
[email protected]94fde232012-04-27 10:22:301328 if (AreAllExternalProvidersReady()) {
1329 updater()->CheckSoon();
1330 } else {
1331 // Sync can start updating before all the external providers are ready
1332 // during startup. Start the update as soon as those providers are ready,
1333 // but not before.
1334 update_once_all_providers_are_ready_ = true;
1335 }
[email protected]c3cfb012011-04-06 22:07:351336 } else {
[email protected]31206602011-04-13 23:07:321337 LOG(WARNING) << "CheckForUpdatesSoon() called with auto-update turned off";
[email protected]c3cfb012011-04-06 22:07:351338 }
1339}
1340
[email protected]3f98fd92012-11-17 15:54:291341syncer::SyncMergeResult ExtensionService::MergeDataAndStartSyncing(
[email protected]a4a147652012-07-03 23:41:321342 syncer::ModelType type,
[email protected]65f173552012-06-28 22:43:581343 const syncer::SyncDataList& initial_sync_data,
1344 scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
1345 scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) {
[email protected]5db9ada2012-04-11 13:48:201346 CHECK(sync_processor.get());
[email protected]5d36e052012-04-20 20:12:281347 CHECK(sync_error_factory.get());
[email protected]3bdba0d2011-08-23 07:17:301348
1349 switch (type) {
[email protected]a4a147652012-07-03 23:41:321350 case syncer::EXTENSIONS:
[email protected]5db9ada2012-04-11 13:48:201351 extension_sync_bundle_.SetupSync(sync_processor.release(),
[email protected]5d36e052012-04-20 20:12:281352 sync_error_factory.release(),
[email protected]5db9ada2012-04-11 13:48:201353 initial_sync_data);
[email protected]3bdba0d2011-08-23 07:17:301354 break;
1355
[email protected]a4a147652012-07-03 23:41:321356 case syncer::APPS:
[email protected]5d36e052012-04-20 20:12:281357 app_sync_bundle_.SetupSync(sync_processor.release(),
1358 sync_error_factory.release(),
1359 initial_sync_data);
[email protected]3bdba0d2011-08-23 07:17:301360 break;
1361
1362 default:
1363 LOG(FATAL) << "Got " << type << " ModelType";
1364 }
[email protected]3bdba0d2011-08-23 07:17:301365
[email protected]b1417ab2011-12-15 17:09:111366 // Process local extensions.
1367 // TODO(yoz): Determine whether pending extensions should be considered too.
1368 // See crbug.com/104399.
[email protected]65f173552012-06-28 22:43:581369 syncer::SyncDataList sync_data_list = GetAllSyncData(type);
1370 syncer::SyncChangeList sync_change_list;
1371 for (syncer::SyncDataList::const_iterator i = sync_data_list.begin();
[email protected]3bdba0d2011-08-23 07:17:301372 i != sync_data_list.end();
1373 ++i) {
[email protected]5db9ada2012-04-11 13:48:201374 switch (type) {
[email protected]a4a147652012-07-03 23:41:321375 case syncer::EXTENSIONS:
[email protected]5db9ada2012-04-11 13:48:201376 sync_change_list.push_back(
1377 extension_sync_bundle_.CreateSyncChange(*i));
1378 break;
[email protected]a4a147652012-07-03 23:41:321379 case syncer::APPS:
[email protected]5db9ada2012-04-11 13:48:201380 sync_change_list.push_back(app_sync_bundle_.CreateSyncChange(*i));
1381 break;
1382 default:
1383 LOG(FATAL) << "Got " << type << " ModelType";
[email protected]31bb5ee62012-09-12 22:58:401384 }
[email protected]3bdba0d2011-08-23 07:17:301385 }
[email protected]3bdba0d2011-08-23 07:17:301386
[email protected]5db9ada2012-04-11 13:48:201387
[email protected]a4a147652012-07-03 23:41:321388 if (type == syncer::EXTENSIONS) {
[email protected]5db9ada2012-04-11 13:48:201389 extension_sync_bundle_.ProcessSyncChangeList(sync_change_list);
[email protected]a4a147652012-07-03 23:41:321390 } else if (type == syncer::APPS) {
[email protected]5db9ada2012-04-11 13:48:201391 app_sync_bundle_.ProcessSyncChangeList(sync_change_list);
1392 }
[email protected]0ffd9e52012-01-26 21:44:341393
[email protected]3f98fd92012-11-17 15:54:291394 return syncer::SyncMergeResult(type);
[email protected]3bdba0d2011-08-23 07:17:301395}
1396
[email protected]a4a147652012-07-03 23:41:321397void ExtensionService::StopSyncing(syncer::ModelType type) {
1398 if (type == syncer::APPS) {
[email protected]5db9ada2012-04-11 13:48:201399 app_sync_bundle_.Reset();
[email protected]a4a147652012-07-03 23:41:321400 } else if (type == syncer::EXTENSIONS) {
[email protected]5db9ada2012-04-11 13:48:201401 extension_sync_bundle_.Reset();
1402 }
[email protected]3bdba0d2011-08-23 07:17:301403}
1404
[email protected]65f173552012-06-28 22:43:581405syncer::SyncDataList ExtensionService::GetAllSyncData(
[email protected]a4a147652012-07-03 23:41:321406 syncer::ModelType type) const {
[email protected]31bb5ee62012-09-12 22:58:401407 if (type == syncer::EXTENSIONS)
[email protected]5db9ada2012-04-11 13:48:201408 return extension_sync_bundle_.GetAllSyncData();
[email protected]31bb5ee62012-09-12 22:58:401409 if (type == syncer::APPS)
[email protected]5db9ada2012-04-11 13:48:201410 return app_sync_bundle_.GetAllSyncData();
[email protected]5db9ada2012-04-11 13:48:201411
1412 // We should only get sync data for extensions and apps.
1413 NOTREACHED();
1414
[email protected]65f173552012-06-28 22:43:581415 return syncer::SyncDataList();
[email protected]3bdba0d2011-08-23 07:17:301416}
1417
[email protected]65f173552012-06-28 22:43:581418syncer::SyncError ExtensionService::ProcessSyncChanges(
[email protected]3bdba0d2011-08-23 07:17:301419 const tracked_objects::Location& from_here,
[email protected]65f173552012-06-28 22:43:581420 const syncer::SyncChangeList& change_list) {
1421 for (syncer::SyncChangeList::const_iterator i = change_list.begin();
[email protected]3bdba0d2011-08-23 07:17:301422 i != change_list.end();
1423 ++i) {
[email protected]a4a147652012-07-03 23:41:321424 syncer::ModelType type = i->sync_data().GetDataType();
1425 if (type == syncer::EXTENSIONS) {
[email protected]5db9ada2012-04-11 13:48:201426 extension_sync_bundle_.ProcessSyncChange(
1427 extensions::ExtensionSyncData(*i));
[email protected]a4a147652012-07-03 23:41:321428 } else if (type == syncer::APPS) {
[email protected]5db9ada2012-04-11 13:48:201429 app_sync_bundle_.ProcessSyncChange(extensions::AppSyncData(*i));
1430 }
[email protected]3bdba0d2011-08-23 07:17:301431 }
1432
[email protected]0ffd9e52012-01-26 21:44:341433 extension_prefs()->extension_sorting()->FixNTPOrdinalCollisions();
1434
[email protected]65f173552012-06-28 22:43:581435 return syncer::SyncError();
[email protected]b05fb9ff2011-04-23 00:07:561436}
1437
[email protected]5db9ada2012-04-11 13:48:201438extensions::ExtensionSyncData ExtensionService::GetExtensionSyncData(
1439 const Extension& extension) const {
1440 return extensions::ExtensionSyncData(extension,
1441 IsExtensionEnabled(extension.id()),
1442 IsIncognitoEnabled(extension.id()));
[email protected]b05fb9ff2011-04-23 00:07:561443}
1444
[email protected]5db9ada2012-04-11 13:48:201445extensions::AppSyncData ExtensionService::GetAppSyncData(
1446 const Extension& extension) const {
1447 return extensions::AppSyncData(
1448 extension,
1449 IsExtensionEnabled(extension.id()),
1450 IsIncognitoEnabled(extension.id()),
1451 extension_prefs_->GetAppNotificationClientId(extension.id()),
1452 extension_prefs_->IsAppNotificationDisabled(extension.id()),
1453 extension_prefs_->extension_sorting()->GetAppLaunchOrdinal(
1454 extension.id()),
1455 extension_prefs_->extension_sorting()->GetPageOrdinal(extension.id()));
1456}
[email protected]3bdba0d2011-08-23 07:17:301457
[email protected]5db9ada2012-04-11 13:48:201458std::vector<extensions::ExtensionSyncData>
1459 ExtensionService::GetExtensionSyncDataList() const {
1460 std::vector<extensions::ExtensionSyncData> extension_sync_list;
1461 extension_sync_bundle_.GetExtensionSyncDataListHelper(extensions_,
1462 &extension_sync_list);
1463 extension_sync_bundle_.GetExtensionSyncDataListHelper(disabled_extensions_,
1464 &extension_sync_list);
1465 extension_sync_bundle_.GetExtensionSyncDataListHelper(terminated_extensions_,
1466 &extension_sync_list);
1467
1468 std::vector<extensions::ExtensionSyncData> pending_extensions =
1469 extension_sync_bundle_.GetPendingData();
1470 extension_sync_list.insert(extension_sync_list.begin(),
1471 pending_extensions.begin(),
1472 pending_extensions.end());
[email protected]3bdba0d2011-08-23 07:17:301473
1474 return extension_sync_list;
[email protected]b05fb9ff2011-04-23 00:07:561475}
1476
[email protected]5db9ada2012-04-11 13:48:201477std::vector<extensions::AppSyncData> ExtensionService::GetAppSyncDataList()
1478 const {
1479 std::vector<extensions::AppSyncData> app_sync_list;
1480 app_sync_bundle_.GetAppSyncDataListHelper(extensions_, &app_sync_list);
1481 app_sync_bundle_.GetAppSyncDataListHelper(disabled_extensions_,
1482 &app_sync_list);
1483 app_sync_bundle_.GetAppSyncDataListHelper(terminated_extensions_,
1484 &app_sync_list);
1485
1486 std::vector<extensions::AppSyncData> pending_apps =
1487 app_sync_bundle_.GetPendingData();
1488 app_sync_list.insert(app_sync_list.begin(),
1489 pending_apps.begin(),
1490 pending_apps.end());
1491
1492 return app_sync_list;
1493}
1494
1495bool ExtensionService::ProcessExtensionSyncData(
1496 const extensions::ExtensionSyncData& extension_sync_data) {
1497 if (!ProcessExtensionSyncDataHelper(extension_sync_data,
[email protected]a4a147652012-07-03 23:41:321498 syncer::EXTENSIONS)) {
[email protected]5db9ada2012-04-11 13:48:201499 extension_sync_bundle_.AddPendingExtension(extension_sync_data.id(),
1500 extension_sync_data);
1501 CheckForUpdatesSoon();
1502 return false;
1503 }
1504
1505 return true;
1506}
1507
1508bool ExtensionService::ProcessAppSyncData(
1509 const extensions::AppSyncData& app_sync_data) {
1510 const std::string& id = app_sync_data.id();
1511 const Extension* extension = GetInstalledExtension(id);
1512 bool extension_installed = (extension != NULL);
1513
1514 if (app_sync_data.app_launch_ordinal().IsValid() &&
1515 app_sync_data.page_ordinal().IsValid()) {
1516 extension_prefs_->extension_sorting()->SetAppLaunchOrdinal(
1517 id,
1518 app_sync_data.app_launch_ordinal());
1519 extension_prefs_->extension_sorting()->SetPageOrdinal(
1520 id,
1521 app_sync_data.page_ordinal());
1522 }
1523
1524 if (extension_installed) {
1525 if (app_sync_data.notifications_disabled() !=
1526 extension_prefs_->IsAppNotificationDisabled(id)) {
1527 extension_prefs_->SetAppNotificationDisabled(
1528 id, app_sync_data.notifications_disabled());
1529 }
1530 }
1531
1532 if (!ProcessExtensionSyncDataHelper(app_sync_data.extension_sync_data(),
[email protected]a4a147652012-07-03 23:41:321533 syncer::APPS)) {
[email protected]5db9ada2012-04-11 13:48:201534 app_sync_bundle_.AddPendingApp(id, app_sync_data);
1535 CheckForUpdatesSoon();
1536 return false;
1537 }
1538
1539 return true;
1540}
1541
1542bool ExtensionService::IsCorrectSyncType(const Extension& extension,
[email protected]a4a147652012-07-03 23:41:321543 syncer::ModelType type) const {
1544 if (type == syncer::EXTENSIONS &&
[email protected]31bb5ee62012-09-12 22:58:401545 extension.GetSyncType() == Extension::SYNC_TYPE_EXTENSION) {
[email protected]5db9ada2012-04-11 13:48:201546 return true;
[email protected]31bb5ee62012-09-12 22:58:401547 }
[email protected]5db9ada2012-04-11 13:48:201548
[email protected]a4a147652012-07-03 23:41:321549 if (type == syncer::APPS &&
[email protected]31bb5ee62012-09-12 22:58:401550 extension.GetSyncType() == Extension::SYNC_TYPE_APP) {
[email protected]5db9ada2012-04-11 13:48:201551 return true;
[email protected]31bb5ee62012-09-12 22:58:401552 }
[email protected]5db9ada2012-04-11 13:48:201553
1554 return false;
1555}
1556
1557bool ExtensionService::ProcessExtensionSyncDataHelper(
1558 const extensions::ExtensionSyncData& extension_sync_data,
[email protected]a4a147652012-07-03 23:41:321559 syncer::ModelType type) {
[email protected]3bdba0d2011-08-23 07:17:301560 const std::string& id = extension_sync_data.id();
[email protected]96e989b2011-08-30 19:35:061561 const Extension* extension = GetInstalledExtension(id);
1562
1563 // TODO(bolms): we should really handle this better. The particularly bad
1564 // case is where an app becomes an extension or vice versa, and we end up with
1565 // a zombie extension that won't go away.
[email protected]5db9ada2012-04-11 13:48:201566 if (extension && !IsCorrectSyncType(*extension, type))
1567 return true;
[email protected]90310d92011-04-17 07:35:041568
1569 // Handle uninstalls first.
[email protected]3bdba0d2011-08-23 07:17:301570 if (extension_sync_data.uninstalled()) {
[email protected]90310d92011-04-17 07:35:041571 std::string error;
1572 if (!UninstallExtensionHelper(this, id)) {
1573 LOG(WARNING) << "Could not uninstall extension " << id
1574 << " for sync";
1575 }
[email protected]5db9ada2012-04-11 13:48:201576 return true;
[email protected]90310d92011-04-17 07:35:041577 }
1578
[email protected]caf2d442012-05-04 10:00:501579 // Extension from sync was uninstalled by the user as external extensions.
1580 // Honor user choice and skip installation/enabling.
1581 if (IsExternalExtensionUninstalled(id)) {
1582 LOG(WARNING) << "Extension with id " << id
1583 << " from sync was uninstalled as external extension";
1584 return true;
1585 }
1586
[email protected]06f92562011-04-29 19:27:311587 // Set user settings.
[email protected]31bb5ee62012-09-12 22:58:401588 if (extension_sync_data.enabled())
[email protected]06f92562011-04-29 19:27:311589 EnableExtension(id);
[email protected]31bb5ee62012-09-12 22:58:401590 else
[email protected]dad50522012-12-06 21:50:161591 DisableExtension(id, Extension::DISABLE_USER_ACTION);
[email protected]81b14cc2011-04-29 00:39:371592
[email protected]406b5a92011-11-08 11:58:261593 // We need to cache some version information here because setting the
1594 // incognito flag invalidates the |extension| pointer (it reloads the
1595 // extension).
[email protected]9060d8b02012-01-13 02:14:301596 bool extension_installed = (extension != NULL);
[email protected]406b5a92011-11-08 11:58:261597 int result = extension ?
1598 extension->version()->CompareTo(extension_sync_data.version()) : 0;
1599 SetIsIncognitoEnabled(id, extension_sync_data.incognito_enabled());
1600 extension = NULL; // No longer safe to use.
1601
1602 if (extension_installed) {
[email protected]06f92562011-04-29 19:27:311603 // If the extension is already installed, check if it's outdated.
[email protected]90310d92011-04-17 07:35:041604 if (result < 0) {
1605 // Extension is outdated.
[email protected]5db9ada2012-04-11 13:48:201606 return false;
[email protected]b020dc12011-12-06 04:35:421607 }
[email protected]06f92562011-04-29 19:27:311608 } else {
[email protected]06f92562011-04-29 19:27:311609 // TODO(akalin): Replace silent update with a list of enabled
1610 // permissions.
[email protected]6cc7dbae2011-04-29 21:18:331611 const bool kInstallSilently = true;
[email protected]5db9ada2012-04-11 13:48:201612
[email protected]a4a147652012-07-03 23:41:321613 CHECK(type == syncer::EXTENSIONS || type == syncer::APPS);
[email protected]5db9ada2012-04-11 13:48:201614 ExtensionFilter filter =
[email protected]a4a147652012-07-03 23:41:321615 (type == syncer::APPS) ? IsSyncableApp : IsSyncableExtension;
[email protected]5db9ada2012-04-11 13:48:201616
[email protected]06f92562011-04-29 19:27:311617 if (!pending_extension_manager()->AddFromSync(
1618 id,
[email protected]3bdba0d2011-08-23 07:17:301619 extension_sync_data.update_url(),
[email protected]5db9ada2012-04-11 13:48:201620 filter,
[email protected]6cc7dbae2011-04-29 21:18:331621 kInstallSilently)) {
[email protected]06f92562011-04-29 19:27:311622 LOG(WARNING) << "Could not add pending extension for " << id;
[email protected]3bdba0d2011-08-23 07:17:301623 // This means that the extension is already pending installation, with a
1624 // non-INTERNAL location. Add to pending_sync_data, even though it will
1625 // never be removed (we'll never install a syncable version of the
1626 // extension), so that GetAllSyncData() continues to send it.
[email protected]06f92562011-04-29 19:27:311627 }
[email protected]3bdba0d2011-08-23 07:17:301628 // Track pending extensions so that we can return them in GetAllSyncData().
[email protected]5db9ada2012-04-11 13:48:201629 return false;
[email protected]90310d92011-04-17 07:35:041630 }
[email protected]5db9ada2012-04-11 13:48:201631
1632 return true;
[email protected]90310d92011-04-17 07:35:041633}
1634
[email protected]c3cfb012011-04-06 22:07:351635bool ExtensionService::IsIncognitoEnabled(
1636 const std::string& extension_id) const {
[email protected]cdc7b1f42012-12-07 19:39:481637 const Extension* extension = GetInstalledExtension(extension_id);
1638 if (extension && !extension->can_be_incognito_enabled())
1639 return false;
[email protected]c3cfb012011-04-06 22:07:351640 // If this is an existing component extension we always allow it to
1641 // work in incognito mode.
[email protected]c3cfb012011-04-06 22:07:351642 if (extension && extension->location() == Extension::COMPONENT)
[email protected]cb0ce1e022010-03-10 19:54:411643 return true;
1644
1645 // Check the prefs.
[email protected]c3cfb012011-04-06 22:07:351646 return extension_prefs_->IsIncognitoEnabled(extension_id);
[email protected]db7331a2010-02-25 22:10:501647}
[email protected]55a35692010-02-11 23:25:211648
[email protected]c3cfb012011-04-06 22:07:351649void ExtensionService::SetIsIncognitoEnabled(
1650 const std::string& extension_id, bool enabled) {
[email protected]81b14cc2011-04-29 00:39:371651 const Extension* extension = GetInstalledExtension(extension_id);
[email protected]cdc7b1f42012-12-07 19:39:481652 if (extension && !extension->can_be_incognito_enabled())
1653 return;
[email protected]c3cfb012011-04-06 22:07:351654 if (extension && extension->location() == Extension::COMPONENT) {
[email protected]b873cd92012-02-09 21:51:481655 // This shouldn't be called for component extensions unless they are
1656 // syncable.
1657 DCHECK(extension->IsSyncable());
1658
1659 // If we are here, make sure the we aren't trying to change the value.
1660 DCHECK_EQ(enabled, IsIncognitoEnabled(extension_id));
1661
[email protected]c3cfb012011-04-06 22:07:351662 return;
1663 }
1664
[email protected]8c6c8c22011-03-09 12:52:341665 // Broadcast unloaded and loaded events to update browser state. Only bother
1666 // if the value changed and the extension is actually enabled, since there is
1667 // no UI otherwise.
[email protected]c3cfb012011-04-06 22:07:351668 bool old_enabled = extension_prefs_->IsIncognitoEnabled(extension_id);
[email protected]8c6c8c22011-03-09 12:52:341669 if (enabled == old_enabled)
1670 return;
1671
[email protected]c3cfb012011-04-06 22:07:351672 extension_prefs_->SetIsIncognitoEnabled(extension_id, enabled);
[email protected]81b14cc2011-04-29 00:39:371673
[email protected]ffbf3f12011-12-09 22:10:331674 bool extension_is_enabled = extensions_.Contains(extension_id);
[email protected]bd9892eb2011-11-11 19:41:341675
1676 // When we reload the extension the ID may be invalidated if we've passed it
1677 // by const ref everywhere. Make a copy to be safe.
1678 std::string id = extension_id;
[email protected]406b5a92011-11-08 11:58:261679 if (extension_is_enabled)
[email protected]ffbf3f12011-12-09 22:10:331680 ReloadExtension(id);
[email protected]3bdba0d2011-08-23 07:17:301681
[email protected]406b5a92011-11-08 11:58:261682 // Reloading the extension invalidates the |extension| pointer.
[email protected]bd9892eb2011-11-11 19:41:341683 extension = GetInstalledExtension(id);
[email protected]3bdba0d2011-08-23 07:17:301684 if (extension)
1685 SyncExtensionChangeIfNeeded(*extension);
[email protected]55a35692010-02-11 23:25:211686}
1687
[email protected]aa7599d2011-10-28 07:24:321688void ExtensionService::SetAppNotificationSetupDone(
1689 const std::string& extension_id,
[email protected]b2689a902011-12-01 00:41:091690 const std::string& oauth_client_id) {
[email protected]aa7599d2011-10-28 07:24:321691 const Extension* extension = GetInstalledExtension(extension_id);
1692 // This method is called when the user sets up app notifications.
1693 // So it is not expected to be called until the extension is installed.
1694 if (!extension) {
1695 NOTREACHED();
1696 return;
1697 }
[email protected]b2689a902011-12-01 00:41:091698 extension_prefs_->SetAppNotificationClientId(extension_id, oauth_client_id);
[email protected]aa7599d2011-10-28 07:24:321699 SyncExtensionChangeIfNeeded(*extension);
1700}
1701
1702void ExtensionService::SetAppNotificationDisabled(
1703 const std::string& extension_id,
1704 bool value) {
1705 const Extension* extension = GetInstalledExtension(extension_id);
1706 // This method is called when the user enables/disables app notifications.
1707 // So it is not expected to be called until the extension is installed.
1708 if (!extension) {
1709 NOTREACHED();
1710 return;
1711 }
[email protected]97e856b12011-12-14 00:21:131712 if (value)
1713 UMA_HISTOGRAM_COUNTS("Apps.SetAppNotificationsDisabled", 1);
1714 else
1715 UMA_HISTOGRAM_COUNTS("Apps.SetAppNotificationsEnabled", 1);
[email protected]aa7599d2011-10-28 07:24:321716 extension_prefs_->SetAppNotificationDisabled(extension_id, value);
1717 SyncExtensionChangeIfNeeded(*extension);
1718}
1719
[email protected]dc9a74f72012-08-17 18:07:211720bool ExtensionService::CanCrossIncognito(const Extension* extension) const {
[email protected]2a8f24e2010-11-03 21:37:051721 // We allow the extension to see events and data from another profile iff it
1722 // uses "spanning" behavior and it has incognito access. "split" mode
1723 // extensions only see events for a matching profile.
[email protected]0c41298f2011-09-13 21:17:221724 CHECK(extension);
[email protected]c3cfb012011-04-06 22:07:351725 return IsIncognitoEnabled(extension->id()) &&
1726 !extension->incognito_split_mode();
[email protected]2a8f24e2010-11-03 21:37:051727}
1728
[email protected]5ef7b002011-05-12 23:16:201729bool ExtensionService::CanLoadInIncognito(const Extension* extension) const {
1730 if (extension->is_hosted_app())
1731 return true;
1732 // Packaged apps and regular extensions need to be enabled specifically for
1733 // incognito (and split mode should be set).
1734 return extension->incognito_split_mode() &&
1735 IsIncognitoEnabled(extension->id());
1736}
1737
[email protected]168389f2011-12-20 17:12:481738void ExtensionService::OnExtensionMoved(
1739 const std::string& moved_extension_id,
1740 const std::string& predecessor_extension_id,
1741 const std::string& successor_extension_id) {
[email protected]3569b502012-01-12 20:08:231742 extension_prefs_->extension_sorting()->OnExtensionMoved(
1743 moved_extension_id,
1744 predecessor_extension_id,
1745 successor_extension_id);
[email protected]168389f2011-12-20 17:12:481746
1747 const Extension* extension = GetInstalledExtension(moved_extension_id);
1748 if (extension)
1749 SyncExtensionChangeIfNeeded(*extension);
1750}
1751
[email protected]dc9a74f72012-08-17 18:07:211752bool ExtensionService::AllowFileAccess(const Extension* extension) const {
[email protected]05c82182010-06-24 17:49:081753 return (CommandLine::ForCurrentProcess()->HasSwitch(
[email protected]334e04a2010-06-24 23:34:441754 switches::kDisableExtensionsFileAccessCheck) ||
[email protected]05c82182010-06-24 17:49:081755 extension_prefs_->AllowFileAccess(extension->id()));
1756}
1757
[email protected]eaa7dd182010-12-14 11:09:001758void ExtensionService::SetAllowFileAccess(const Extension* extension,
[email protected]3aff9ad2011-04-01 20:26:481759 bool allow) {
1760 // Reload to update browser state. Only bother if the value changed and the
1761 // extension is actually enabled, since there is no UI otherwise.
1762 bool old_allow = AllowFileAccess(extension);
1763 if (allow == old_allow)
1764 return;
1765
[email protected]05c82182010-06-24 17:49:081766 extension_prefs_->SetAllowFileAccess(extension->id(), allow);
[email protected]3aff9ad2011-04-01 20:26:481767
[email protected]84df8332011-12-06 18:22:461768 bool extension_is_enabled = extensions_.Contains(extension->id());
[email protected]3aff9ad2011-04-01 20:26:481769 if (extension_is_enabled)
1770 ReloadExtension(extension->id());
[email protected]05c82182010-06-24 17:49:081771}
1772
[email protected]8e4560b62011-01-14 10:09:141773// Some extensions will autoupdate themselves externally from Chrome. These
1774// are typically part of some larger client application package. To support
1775// these, the extension will register its location in the the preferences file
1776// (and also, on Windows, in the registry) and this code will periodically
1777// check that location for a .crx file, which it will then install locally if
1778// a new version is available.
1779// Errors are reported through ExtensionErrorReporter. Succcess is not
1780// reported.
[email protected]eaa7dd182010-12-14 11:09:001781void ExtensionService::CheckForExternalUpdates() {
[email protected]a29a517a2011-01-21 21:11:121782 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]8e4560b62011-01-14 10:09:141783
1784 // Note that this installation is intentionally silent (since it didn't
1785 // go through the front-end). Extensions that are registered in this
1786 // way are effectively considered 'pre-bundled', and so implicitly
1787 // trusted. In general, if something has HKLM or filesystem access,
1788 // they could install an extension manually themselves anyway.
[email protected]a29a517a2011-01-21 21:11:121789
[email protected]8e4560b62011-01-14 10:09:141790 // Ask each external extension provider to give us a call back for each
1791 // extension they know about. See OnExternalExtension(File|UpdateUrl)Found.
[email protected]5df038b2012-07-16 19:03:271792 extensions::ProviderCollection::const_iterator i;
[email protected]8e4560b62011-01-14 10:09:141793 for (i = external_extension_providers_.begin();
1794 i != external_extension_providers_.end(); ++i) {
[email protected]5df038b2012-07-16 19:03:271795 extensions::ExternalProviderInterface* provider = i->get();
[email protected]8e4560b62011-01-14 10:09:141796 provider->VisitRegisteredExtension();
1797 }
1798
[email protected]50067e52011-10-20 23:17:071799 // Do any required work that we would have done after completion of all
1800 // providers.
1801 if (external_extension_providers_.empty()) {
1802 OnAllExternalProvidersReady();
1803 }
[email protected]9f1087e2009-06-15 17:29:321804}
1805
[email protected]50067e52011-10-20 23:17:071806void ExtensionService::OnExternalProviderReady(
[email protected]5df038b2012-07-16 19:03:271807 const extensions::ExternalProviderInterface* provider) {
[email protected]a29a517a2011-01-21 21:11:121808 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]50067e52011-10-20 23:17:071809 CHECK(provider->IsReady());
[email protected]a29a517a2011-01-21 21:11:121810
1811 // An external provider has finished loading. We only take action
[email protected]8e4560b62011-01-14 10:09:141812 // if all of them are finished. So we check them first.
[email protected]94fde232012-04-27 10:22:301813 if (AreAllExternalProvidersReady())
1814 OnAllExternalProvidersReady();
1815}
1816
1817bool ExtensionService::AreAllExternalProvidersReady() const {
[email protected]5df038b2012-07-16 19:03:271818 extensions::ProviderCollection::const_iterator i;
[email protected]8e4560b62011-01-14 10:09:141819 for (i = external_extension_providers_.begin();
1820 i != external_extension_providers_.end(); ++i) {
[email protected]94fde232012-04-27 10:22:301821 if (!i->get()->IsReady())
1822 return false;
[email protected]8e4560b62011-01-14 10:09:141823 }
[email protected]94fde232012-04-27 10:22:301824 return true;
[email protected]50067e52011-10-20 23:17:071825}
1826
1827void ExtensionService::OnAllExternalProvidersReady() {
1828 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]94fde232012-04-27 10:22:301829 base::TimeDelta elapsed = base::Time::Now() - profile_->GetStartTime();
1830 UMA_HISTOGRAM_TIMES("Extension.ExternalProvidersReadyAfter", elapsed);
[email protected]50067e52011-10-20 23:17:071831
1832 // Install any pending extensions.
[email protected]94fde232012-04-27 10:22:301833 if (update_once_all_providers_are_ready_ && updater()) {
1834 update_once_all_providers_are_ready_ = false;
[email protected]42774e42012-11-14 21:01:061835 updater()->CheckNow(extensions::ExtensionUpdater::CheckParams());
[email protected]8e4560b62011-01-14 10:09:141836 }
1837
1838 // Uninstall all the unclaimed extensions.
[email protected]45759612012-07-10 17:21:231839 scoped_ptr<extensions::ExtensionPrefs::ExtensionsInfo> extensions_info(
[email protected]8e4560b62011-01-14 10:09:141840 extension_prefs_->GetInstalledExtensionsInfo());
1841 for (size_t i = 0; i < extensions_info->size(); ++i) {
1842 ExtensionInfo* info = extensions_info->at(i).get();
1843 if (Extension::IsExternalLocation(info->extension_location))
1844 CheckExternalUninstall(info->extension_id);
1845 }
[email protected]e5af875f2011-10-10 21:09:141846 IdentifyAlertableExtensions();
[email protected]e5af875f2011-10-10 21:09:141847}
1848
1849void ExtensionService::IdentifyAlertableExtensions() {
1850 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1851
[email protected]07c9f2f42012-02-29 18:45:221852 // Build up the lists of extensions that require acknowledgment. If this is
1853 // the first time, grandfather extensions that would have caused
1854 // notification.
[email protected]89226982012-07-16 20:09:181855 extension_error_ui_.reset(ExtensionErrorUI::Create(this));
[email protected]e5af875f2011-10-10 21:09:141856
[email protected]a9aa5932012-01-25 08:27:401857 bool did_show_alert = false;
[email protected]89226982012-07-16 20:09:181858 if (PopulateExtensionErrorUI(extension_error_ui_.get())) {
[email protected]e5af875f2011-10-10 21:09:141859 if (extension_prefs_->SetAlertSystemFirstRun()) {
[email protected]a9aa5932012-01-25 08:27:401860 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]89226982012-07-16 20:09:181861 did_show_alert = extension_error_ui_->ShowErrorInBubbleView();
[email protected]e5af875f2011-10-10 21:09:141862 } else {
1863 // First run. Just acknowledge all the extensions, silently, by
1864 // shortcutting the display of the UI and going straight to the
1865 // callback for pressing the Accept button.
[email protected]a9aa5932012-01-25 08:27:401866 HandleExtensionAlertAccept();
[email protected]e5af875f2011-10-10 21:09:141867 }
1868 }
[email protected]a9aa5932012-01-25 08:27:401869
[email protected]612a1cb12012-10-17 13:18:031870 UpdateExternalExtensionAlert();
1871
[email protected]a9aa5932012-01-25 08:27:401872 if (!did_show_alert)
[email protected]89226982012-07-16 20:09:181873 extension_error_ui_.reset();
[email protected]e5af875f2011-10-10 21:09:141874}
1875
[email protected]89226982012-07-16 20:09:181876bool ExtensionService::PopulateExtensionErrorUI(
1877 ExtensionErrorUI* extension_error_ui) {
[email protected]07c9f2f42012-02-29 18:45:221878 bool needs_alert = false;
[email protected]695b5712012-12-06 23:55:281879
1880 // Extensions that are blacklisted.
1881 for (ExtensionSet::const_iterator it = blacklisted_extensions_.begin();
1882 it != blacklisted_extensions_.end(); ++it) {
1883 std::string id = (*it)->id();
1884 if (!extension_prefs_->IsBlacklistedExtensionAcknowledged(id)) {
1885 extension_error_ui->AddBlacklistedExtension(id);
1886 needs_alert = true;
1887 }
1888 }
1889
[email protected]07c9f2f42012-02-29 18:45:221890 for (ExtensionSet::const_iterator iter = extensions_.begin();
1891 iter != extensions_.end(); ++iter) {
1892 const Extension* e = *iter;
[email protected]695b5712012-12-06 23:55:281893
1894 // Extensions disabled by policy. Note: this no longer includes blacklisted
1895 // extensions, though we still show the same UI.
[email protected]fdd679b2012-11-15 20:49:391896 if (!system_->management_policy()->UserMayLoad(e, NULL)) {
[email protected]07c9f2f42012-02-29 18:45:221897 if (!extension_prefs_->IsBlacklistedExtensionAcknowledged(e->id())) {
[email protected]89226982012-07-16 20:09:181898 extension_error_ui->AddBlacklistedExtension(e->id());
[email protected]07c9f2f42012-02-29 18:45:221899 needs_alert = true;
1900 }
1901 }
[email protected]695b5712012-12-06 23:55:281902
1903 // Orphaned extensions.
[email protected]07c9f2f42012-02-29 18:45:221904 if (extension_prefs_->IsExtensionOrphaned(e->id())) {
1905 if (!extension_prefs_->IsOrphanedExtensionAcknowledged(e->id())) {
[email protected]89226982012-07-16 20:09:181906 extension_error_ui->AddOrphanedExtension(e->id());
[email protected]07c9f2f42012-02-29 18:45:221907 needs_alert = true;
1908 }
1909 }
1910 }
[email protected]695b5712012-12-06 23:55:281911
[email protected]07c9f2f42012-02-29 18:45:221912 return needs_alert;
1913}
1914
[email protected]a9aa5932012-01-25 08:27:401915void ExtensionService::HandleExtensionAlertClosed() {
[email protected]89226982012-07-16 20:09:181916 extension_error_ui_.reset();
[email protected]62433d32011-10-12 22:33:121917}
1918
[email protected]a9aa5932012-01-25 08:27:401919void ExtensionService::HandleExtensionAlertAccept() {
[email protected]612a1cb12012-10-17 13:18:031920 const ExtensionIdSet* extension_ids =
1921 extension_error_ui_->get_blacklisted_extension_ids();
[email protected]e5af875f2011-10-10 21:09:141922 for (ExtensionIdSet::const_iterator iter = extension_ids->begin();
1923 iter != extension_ids->end(); ++iter) {
1924 extension_prefs_->AcknowledgeBlacklistedExtension(*iter);
1925 }
[email protected]89226982012-07-16 20:09:181926 extension_ids = extension_error_ui_->get_orphaned_extension_ids();
[email protected]e5af875f2011-10-10 21:09:141927 for (ExtensionIdSet::const_iterator iter = extension_ids->begin();
1928 iter != extension_ids->end(); ++iter) {
1929 extension_prefs_->AcknowledgeOrphanedExtension(*iter);
1930 }
1931}
1932
[email protected]47fc70c2011-12-06 07:29:511933void ExtensionService::AcknowledgeExternalExtension(const std::string& id) {
1934 extension_prefs_->AcknowledgeExternalExtension(id);
[email protected]612a1cb12012-10-17 13:18:031935 UpdateExternalExtensionAlert();
[email protected]47fc70c2011-12-06 07:29:511936}
1937
[email protected]d96eb512012-11-01 23:44:081938bool ExtensionService::IsUnacknowledgedExternalExtension(
1939 const Extension* extension) {
[email protected]b82d18da2012-11-09 00:11:321940 if (!FeatureSwitch::prompt_for_external_extensions()->IsEnabled())
1941 return false;
1942
[email protected]d96eb512012-11-01 23:44:081943 return (Extension::IsExternalLocation(extension->location()) &&
1944 !extension_prefs_->IsExternalExtensionAcknowledged(extension->id()) &&
1945 !(extension_prefs_->GetDisableReasons(extension->id()) &
1946 Extension::DISABLE_SIDELOAD_WIPEOUT));
1947}
1948
[email protected]89226982012-07-16 20:09:181949void ExtensionService::HandleExtensionAlertDetails() {
1950 extension_error_ui_->ShowExtensions();
[email protected]6c751e72010-11-23 10:11:101951}
1952
[email protected]612a1cb12012-10-17 13:18:031953void ExtensionService::UpdateExternalExtensionAlert() {
[email protected]41070e8d2012-10-24 01:34:361954 if (!FeatureSwitch::prompt_for_external_extensions()->IsEnabled())
[email protected]612a1cb12012-10-17 13:18:031955 return;
1956
1957 const Extension* extension = NULL;
1958 for (ExtensionSet::const_iterator iter = disabled_extensions_.begin();
1959 iter != disabled_extensions_.end(); ++iter) {
1960 const Extension* e = *iter;
[email protected]d96eb512012-11-01 23:44:081961 if (IsUnacknowledgedExternalExtension(e)) {
1962 extension = e;
1963 break;
[email protected]612a1cb12012-10-17 13:18:031964 }
1965 }
1966
1967 if (extension) {
[email protected]d96eb512012-11-01 23:44:081968 if (!extensions::HasExternalInstallError(this)) {
1969 if (extension_prefs_->IncrementAcknowledgePromptCount(extension->id()) >
[email protected]612a1cb12012-10-17 13:18:031970 kMaxExtensionAcknowledgePromptCount) {
[email protected]d96eb512012-11-01 23:44:081971 // Stop prompting for this extension, and check if there's another
1972 // one that needs prompting.
[email protected]612a1cb12012-10-17 13:18:031973 extension_prefs_->AcknowledgeExternalExtension(extension->id());
[email protected]d96eb512012-11-01 23:44:081974 UpdateExternalExtensionAlert();
1975 UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalExtensionEvent",
1976 EXTERNAL_EXTENSION_IGNORED,
1977 EXTERNAL_EXTENSION_BUCKET_BOUNDARY);
1978 return;
[email protected]612a1cb12012-10-17 13:18:031979 }
[email protected]d96eb512012-11-01 23:44:081980 extensions::AddExternalInstallError(this, extension);
[email protected]612a1cb12012-10-17 13:18:031981 }
1982 } else {
1983 extensions::RemoveExternalInstallError(this);
1984 }
[email protected]612a1cb12012-10-17 13:18:031985}
1986
[email protected]a9f39a312010-12-23 22:14:271987void ExtensionService::UnloadExtension(
1988 const std::string& extension_id,
[email protected]814a7bf0f2011-08-13 05:30:591989 extension_misc::UnloadedExtensionReason reason) {
[email protected]27e469a2010-01-11 20:35:091990 // Make sure the extension gets deleted after we return from this function.
[email protected]695b5712012-12-06 23:55:281991 int include_mask = INCLUDE_EVERYTHING & ~INCLUDE_TERMINATED;
[email protected]9adb9692010-10-29 23:14:021992 scoped_refptr<const Extension> extension(
[email protected]695b5712012-12-06 23:55:281993 GetExtensionById(extension_id, include_mask));
[email protected]631cf822009-05-15 07:01:251994
[email protected]fa0c96732010-11-17 00:14:231995 // This method can be called via PostTask, so the extension may have been
1996 // unloaded by the time this runs.
[email protected]dd163fb02011-05-04 22:22:171997 if (!extension) {
1998 // In case the extension may have crashed/uninstalled. Allow the profile to
1999 // clean up its RequestContexts.
[email protected]31d8f5f22012-04-02 15:22:082000 system_->UnregisterExtensionWithRequestContexts(extension_id, reason);
[email protected]fa0c96732010-11-17 00:14:232001 return;
[email protected]dd163fb02011-05-04 22:22:172002 }
[email protected]0c6da502009-08-14 22:32:392003
[email protected]1eb175082010-02-10 09:26:162004 // Keep information about the extension so that we can reload it later
2005 // even if it's not permanently installed.
2006 unloaded_extension_paths_[extension->id()] = extension->path();
2007
[email protected]f17dbd42010-08-16 23:21:102008 // Clean up if the extension is meant to be enabled after a reload.
2009 disabled_extension_paths_.erase(extension->id());
2010
[email protected]d7e9a862010-11-03 21:57:492011 // Clean up runtime data.
2012 extension_runtime_data_.erase(extension_id);
2013
[email protected]060d4972012-07-19 17:22:392014 if (disabled_extensions_.Contains(extension->id())) {
[email protected]a9f39a312010-12-23 22:14:272015 UnloadedExtensionInfo details(extension, reason);
2016 details.already_disabled = true;
[email protected]84df8332011-12-06 18:22:462017 disabled_extensions_.Remove(extension->id());
[email protected]ad50def52011-10-19 23:17:072018 content::NotificationService::current()->Notify(
[email protected]432115822011-07-10 15:52:272019 chrome::NOTIFICATION_EXTENSION_UNLOADED,
[email protected]6c2381d2011-10-19 02:52:532020 content::Source<Profile>(profile_),
2021 content::Details<UnloadedExtensionInfo>(&details));
[email protected]dd163fb02011-05-04 22:22:172022 // Make sure the profile cleans up its RequestContexts when an already
2023 // disabled extension is unloaded (since they are also tracking the disabled
2024 // extensions).
[email protected]31d8f5f22012-04-02 15:22:082025 system_->UnregisterExtensionWithRequestContexts(extension_id, reason);
[email protected]0c6da502009-08-14 22:32:392026 return;
2027 }
2028
[email protected]060d4972012-07-19 17:22:392029 // Remove the extension from our list.
[email protected]84df8332011-12-06 18:22:462030 extensions_.Remove(extension->id());
[email protected]631cf822009-05-15 07:01:252031
[email protected]a9f39a312010-12-23 22:14:272032 NotifyExtensionUnloaded(extension.get(), reason);
[email protected]631cf822009-05-15 07:01:252033}
2034
[email protected]eaa7dd182010-12-14 11:09:002035void ExtensionService::UnloadAllExtensions() {
[email protected]31bb5ee62012-09-12 22:58:402036 profile_->GetExtensionSpecialStoragePolicy()->RevokeRightsForAllExtensions();
[email protected]c8d407e2011-04-28 21:27:172037
[email protected]84df8332011-12-06 18:22:462038 extensions_.Clear();
2039 disabled_extensions_.Clear();
2040 terminated_extensions_.Clear();
[email protected]d7e9a862010-11-03 21:57:492041 extension_runtime_data_.clear();
[email protected]cd500f72010-06-25 23:44:322042
[email protected]c6e4a3412009-06-24 15:45:292043 // TODO(erikkay) should there be a notification for this? We can't use
2044 // EXTENSION_UNLOADED since that implies that the extension has been disabled
2045 // or uninstalled, and UnloadAll is just part of shutdown.
[email protected]9f1087e2009-06-15 17:29:322046}
2047
[email protected]eaa7dd182010-12-14 11:09:002048void ExtensionService::ReloadExtensions() {
[email protected]9f1087e2009-06-15 17:29:322049 UnloadAllExtensions();
[email protected]d8c8f25f2011-11-02 18:18:012050 component_loader_->LoadAll();
2051 extensions::InstalledLoader(this).LoadAllExtensions();
[email protected]9f1087e2009-06-15 17:29:322052}
2053
[email protected]eaa7dd182010-12-14 11:09:002054void ExtensionService::GarbageCollectExtensions() {
[email protected]2f8757c32012-06-19 19:17:472055 if (extension_prefs_->pref_service()->ReadOnly())
2056 return;
2057
[email protected]9bd9a6862012-11-29 09:24:222058 if (pending_extension_manager()->HasPendingExtensions()) {
2059 // Don't garbage collect while there are pending installations, which may
2060 // be using the temporary installation directory. Try to garbage collect
2061 // again later.
2062 MessageLoop::current()->PostDelayedTask(
2063 FROM_HERE,
2064 base::Bind(&ExtensionService::GarbageCollectExtensions, AsWeakPtr()),
2065 base::TimeDelta::FromSeconds(kGarbageCollectRetryDelay));
2066 return;
2067 }
2068
[email protected]45759612012-07-10 17:21:232069 scoped_ptr<extensions::ExtensionPrefs::ExtensionsInfo> info(
[email protected]2f8757c32012-06-19 19:17:472070 extension_prefs_->GetInstalledExtensionsInfo());
2071
[email protected]0db124b02012-11-07 04:55:052072 std::multimap<std::string, FilePath> extension_paths;
[email protected]2f8757c32012-06-19 19:17:472073 for (size_t i = 0; i < info->size(); ++i)
[email protected]0db124b02012-11-07 04:55:052074 extension_paths.insert(std::make_pair(info->at(i)->extension_id,
2075 info->at(i)->extension_path));
2076
2077 info = extension_prefs_->GetAllIdleInstallInfo();
2078 for (size_t i = 0; i < info->size(); ++i)
2079 extension_paths.insert(std::make_pair(info->at(i)->extension_id,
2080 info->at(i)->extension_path));
[email protected]2f8757c32012-06-19 19:17:472081
[email protected]7f8f24f2012-11-15 19:40:142082 if (!GetFileTaskRunner()->PostTask(
2083 FROM_HERE,
[email protected]2f8757c32012-06-19 19:17:472084 base::Bind(
2085 &extension_file_util::GarbageCollectExtensions,
2086 install_directory_,
[email protected]31bb5ee62012-09-12 22:58:402087 extension_paths))) {
[email protected]2f8757c32012-06-19 19:17:472088 NOTREACHED();
[email protected]31bb5ee62012-09-12 22:58:402089 }
[email protected]f6ccd652010-11-17 00:48:342090
[email protected]f766a9d2012-07-11 01:57:442091#if defined(ENABLE_THEMES)
[email protected]f6ccd652010-11-17 00:48:342092 // Also garbage-collect themes. We check |profile_| to be
2093 // defensive; in the future, we may call GarbageCollectExtensions()
2094 // from somewhere other than Init() (e.g., in a timer).
2095 if (profile_) {
[email protected]d5949312012-12-03 22:13:302096 ThemeServiceFactory::GetForProfile(profile_)->RemoveUnusedThemes();
[email protected]f6ccd652010-11-17 00:48:342097 }
[email protected]f766a9d2012-07-11 01:57:442098#endif
[email protected]3cf4f0992009-02-03 23:00:302099}
2100
[email protected]fb82dcd2012-03-21 14:15:462101void ExtensionService::SyncExtensionChangeIfNeeded(const Extension& extension) {
[email protected]5db9ada2012-04-11 13:48:202102 if (app_sync_bundle_.HandlesApp(extension)) {
2103 app_sync_bundle_.SyncChangeIfNeeded(extension);
2104 } else if (extension_sync_bundle_.HandlesExtension(extension)) {
2105 extension_sync_bundle_.SyncChangeIfNeeded(extension);
[email protected]fb82dcd2012-03-21 14:15:462106 }
2107}
2108
[email protected]eaa7dd182010-12-14 11:09:002109void ExtensionService::OnLoadedInstalledExtensions() {
[email protected]31bb5ee62012-09-12 22:58:402110 if (updater_.get())
[email protected]93fd78f42009-07-10 16:43:172111 updater_->Start();
[email protected]fa6a9102010-11-22 15:38:502112
2113 ready_ = true;
[email protected]ad50def52011-10-19 23:17:072114 content::NotificationService::current()->Notify(
[email protected]432115822011-07-10 15:52:272115 chrome::NOTIFICATION_EXTENSIONS_READY,
[email protected]6c2381d2011-10-19 02:52:532116 content::Source<Profile>(profile_),
[email protected]ad50def52011-10-19 23:17:072117 content::NotificationService::NoDetails());
[email protected]e72e8eb82009-06-18 17:21:512118}
2119
[email protected]fcb58a862012-05-01 01:03:152120void ExtensionService::AddExtension(const Extension* extension) {
[email protected]c8d407e2011-04-28 21:27:172121 // TODO(jstritar): We may be able to get rid of this branch by overriding the
2122 // default extension state to DISABLED when the --disable-extensions flag
2123 // is set (http://crbug.com/29067).
2124 if (!extensions_enabled() &&
2125 !extension->is_theme() &&
2126 extension->location() != Extension::COMPONENT &&
[email protected]330840c2012-08-29 22:21:012127 !Extension::IsExternalLocation(extension->location())) {
[email protected]fcb58a862012-05-01 01:03:152128 return;
[email protected]330840c2012-08-29 22:21:012129 }
[email protected]c8d407e2011-04-28 21:27:172130
2131 SetBeingUpgraded(extension, false);
2132
[email protected]1eb175082010-02-10 09:26:162133 // The extension is now loaded, remove its data from unloaded extension map.
2134 unloaded_extension_paths_.erase(extension->id());
2135
[email protected]bb7f40952011-01-13 00:21:202136 // If a terminated extension is loaded, remove it from the terminated list.
2137 UntrackTerminatedExtension(extension->id());
2138
[email protected]f17dbd42010-08-16 23:21:102139 // If the extension was disabled for a reload, then enable it.
2140 if (disabled_extension_paths_.erase(extension->id()) > 0)
2141 EnableExtension(extension->id());
2142
[email protected]d728e002010-12-08 04:46:232143 // Check if the extension's privileges have changed and disable the
2144 // extension if necessary.
[email protected]902fd7b2011-07-27 18:42:312145 InitializePermissions(extension);
[email protected]0c6da502009-08-14 22:32:392146
[email protected]215a7be2012-10-22 19:53:422147 // If this extension is a sideloaded extension and we've not performed a
2148 // wipeout before, we might disable this extension here.
2149 MaybeWipeout(extension);
2150
[email protected]695b5712012-12-06 23:55:282151 // Communicated to the Blacklist.
2152 std::set<std::string> already_in_blacklist;
2153
2154 if (extension_prefs_->IsExtensionBlacklisted(extension->id())) {
2155 // Don't check the Blacklist yet because it's asynchronous (we do it at
2156 // the end). This pre-emptive check is because we will always store the
2157 // blacklisted state of *installed* extensions in prefs, and it's important
2158 // not to re-enable blacklisted extensions.
2159 blacklisted_extensions_.Insert(extension);
2160 already_in_blacklist.insert(extension->id());
2161 } else if (extension_prefs_->IsExtensionDisabled(extension->id())) {
[email protected]6f6101832012-11-27 22:10:482162 disabled_extensions_.Insert(extension);
[email protected]3bdba0d2011-08-23 07:17:302163 SyncExtensionChangeIfNeeded(*extension);
[email protected]44d62b62012-04-11 00:06:032164 content::NotificationService::current()->Notify(
2165 chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED,
2166 content::Source<Profile>(profile_),
2167 content::Details<const Extension>(extension));
[email protected]62f051c2012-03-29 17:04:442168
[email protected]dad50522012-12-06 21:50:162169 if (extension_prefs_->GetDisableReasons(extension->id()) &
[email protected]44d62b62012-04-11 00:06:032170 Extension::DISABLE_PERMISSIONS_INCREASE) {
[email protected]62f051c2012-03-29 17:04:442171 extensions::AddExtensionDisabledError(this, extension);
2172 }
[email protected]695b5712012-12-06 23:55:282173 } else {
2174 // All apps that are displayed in the launcher are ordered by their ordinals
2175 // so we must ensure they have valid ordinals.
2176 if (extension->RequiresSortOrdinal()) {
2177 extension_prefs_->extension_sorting()->EnsureValidOrdinals(
2178 extension->id(), syncer::StringOrdinal());
2179 }
2180
2181 extensions_.Insert(extension);
2182 SyncExtensionChangeIfNeeded(*extension);
2183 NotifyExtensionLoaded(extension);
2184 DoPostLoadTasks(extension);
[email protected]f574c402012-12-04 23:20:312185 }
2186
[email protected]695b5712012-12-06 23:55:282187 // Lastly, begin the process for checking the blacklist status of extensions.
2188 // This may need to go to other threads so is asynchronous.
2189 std::set<std::string> id_set;
2190 id_set.insert(extension->id());
2191 blacklist_->GetBlacklistedIDs(
2192 id_set,
2193 base::Bind(&ExtensionService::ManageBlacklist,
2194 AsWeakPtr(),
2195 already_in_blacklist));
[email protected]aab98a52009-12-02 03:22:352196}
2197
[email protected]8c484b742012-11-29 06:05:362198void ExtensionService::AddComponentExtension(const Extension* extension) {
2199 const std::string old_version_string(
2200 extension_prefs_->GetVersionString(extension->id()));
2201 const Version old_version(old_version_string);
2202
2203 if (!old_version.IsValid() || !old_version.Equals(*extension->version())) {
2204 VLOG(1) << "Component extension " << extension->name() << " ("
2205 << extension->id() << ") installing/upgrading from '"
2206 << old_version_string << "' to " << extension->version()->GetString();
2207
2208 AddNewOrUpdatedExtension(extension,
2209 syncer::StringOrdinal(),
2210 Extension::ENABLED_COMPONENT);
2211 return;
2212 }
2213
2214 AddExtension(extension);
2215}
2216
[email protected]902fd7b2011-07-27 18:42:312217void ExtensionService::InitializePermissions(const Extension* extension) {
2218 // If the extension has used the optional permissions API, it will have a
2219 // custom set of active permissions defined in the extension prefs. Here,
2220 // we update the extension's active permissions based on the prefs.
[email protected]c2e66e12012-06-27 06:27:062221 scoped_refptr<PermissionSet> active_permissions =
[email protected]902fd7b2011-07-27 18:42:312222 extension_prefs()->GetActivePermissions(extension->id());
2223
2224 if (active_permissions.get()) {
2225 // We restrict the active permissions to be within the bounds defined in the
2226 // extension's manifest.
2227 // a) active permissions must be a subset of optional + default permissions
2228 // b) active permissions must contains all default permissions
[email protected]c2e66e12012-06-27 06:27:062229 scoped_refptr<PermissionSet> total_permissions =
2230 PermissionSet::CreateUnion(
[email protected]902fd7b2011-07-27 18:42:312231 extension->required_permission_set(),
2232 extension->optional_permission_set());
2233
2234 // Make sure the active permissions contain no more than optional + default.
[email protected]c2e66e12012-06-27 06:27:062235 scoped_refptr<PermissionSet> adjusted_active =
2236 PermissionSet::CreateIntersection(
[email protected]902fd7b2011-07-27 18:42:312237 total_permissions.get(), active_permissions.get());
2238
2239 // Make sure the active permissions contain the default permissions.
[email protected]c2e66e12012-06-27 06:27:062240 adjusted_active = PermissionSet::CreateUnion(
[email protected]902fd7b2011-07-27 18:42:312241 extension->required_permission_set(), adjusted_active.get());
2242
[email protected]c333e792012-01-06 16:57:392243 extensions::PermissionsUpdater perms_updater(profile());
2244 perms_updater.UpdateActivePermissions(extension, adjusted_active);
[email protected]902fd7b2011-07-27 18:42:312245 }
2246
[email protected]8d888c12010-11-30 00:00:252247 // We keep track of all permissions the user has granted each extension.
2248 // This allows extensions to gracefully support backwards compatibility
2249 // by including unknown permissions in their manifests. When the user
2250 // installs the extension, only the recognized permissions are recorded.
2251 // When the unknown permissions become recognized (e.g., through browser
2252 // upgrade), we can prompt the user to accept these new permissions.
2253 // Extensions can also silently upgrade to less permissions, and then
2254 // silently upgrade to a version that adds these permissions back.
2255 //
2256 // For example, pretend that Chrome 10 includes a permission "omnibox"
2257 // for an API that adds suggestions to the omnibox. An extension can
2258 // maintain backwards compatibility while still having "omnibox" in the
2259 // manifest. If a user installs the extension on Chrome 9, the browser
2260 // will record the permissions it recognized, not including "omnibox."
2261 // When upgrading to Chrome 10, "omnibox" will be recognized and Chrome
2262 // will disable the extension and prompt the user to approve the increase
2263 // in privileges. The extension could then release a new version that
2264 // removes the "omnibox" permission. When the user upgrades, Chrome will
2265 // still remember that "omnibox" had been granted, so that if the
2266 // extension once again includes "omnibox" in an upgrade, the extension
2267 // can upgrade without requiring this user's approval.
[email protected]695b5712012-12-06 23:55:282268 const Extension* old = GetInstalledExtension(extension->id());
[email protected]8d888c12010-11-30 00:00:252269 bool is_extension_upgrade = old != NULL;
2270 bool is_privilege_increase = false;
[email protected]44d62b62012-04-11 00:06:032271 bool previously_disabled = false;
[email protected]eb5e4f92012-08-15 23:33:282272 int disable_reasons = extension_prefs_->GetDisableReasons(extension->id());
[email protected]8d888c12010-11-30 00:00:252273
[email protected]902fd7b2011-07-27 18:42:312274 // We only need to compare the granted permissions to the current permissions
2275 // if the extension is not allowed to silently increase its permissions.
[email protected]be083862012-09-01 03:53:452276 bool is_default_app_install =
2277 (!is_extension_upgrade && extension->was_installed_by_default());
2278 if (!(extension->CanSilentlyIncreasePermissions()
2279 || is_default_app_install)) {
[email protected]8d888c12010-11-30 00:00:252280 // Add all the recognized permissions if the granted permissions list
2281 // hasn't been initialized yet.
[email protected]c2e66e12012-06-27 06:27:062282 scoped_refptr<PermissionSet> granted_permissions =
[email protected]902fd7b2011-07-27 18:42:312283 extension_prefs_->GetGrantedPermissions(extension->id());
[email protected]0d3e4a22011-06-23 19:02:522284 CHECK(granted_permissions.get());
[email protected]8d888c12010-11-30 00:00:252285
2286 // Here, we check if an extension's privileges have increased in a manner
2287 // that requires the user's approval. This could occur because the browser
2288 // upgraded and recognized additional privileges, or an extension upgrades
2289 // to a version that requires additional privileges.
[email protected]0d3e4a22011-06-23 19:02:522290 is_privilege_increase =
[email protected]902fd7b2011-07-27 18:42:312291 granted_permissions->HasLessPrivilegesThan(
2292 extension->GetActivePermissions());
[email protected]8d888c12010-11-30 00:00:252293 }
2294
[email protected]be083862012-09-01 03:53:452295 // Silently grant all active permissions to default apps only on install.
2296 // After install they should behave like other apps.
[email protected]c856e9762012-10-12 19:42:382297 if (is_default_app_install)
2298 GrantPermissions(extension, true);
[email protected]be083862012-09-01 03:53:452299
[email protected]8d888c12010-11-30 00:00:252300 if (is_extension_upgrade) {
[email protected]66e26872010-12-03 20:07:252301 // Other than for unpacked extensions, CrxInstaller should have guaranteed
2302 // that we aren't downgrading.
2303 if (extension->location() != Extension::LOAD)
[email protected]31bb5ee62012-09-12 22:58:402304 CHECK_GE(extension->version()->CompareTo(*(old->version())), 0);
[email protected]8d888c12010-11-30 00:00:252305
2306 // Extensions get upgraded if the privileges are allowed to increase or
2307 // the privileges haven't increased.
2308 if (!is_privilege_increase) {
2309 SetBeingUpgraded(old, true);
2310 SetBeingUpgraded(extension, true);
2311 }
2312
[email protected]44d62b62012-04-11 00:06:032313 // If the extension was already disabled, suppress any alerts for becoming
2314 // disabled on permissions increase.
2315 previously_disabled = extension_prefs_->IsExtensionDisabled(old->id());
[email protected]dad50522012-12-06 21:50:162316 if (previously_disabled) {
2317 int reasons = extension_prefs_->GetDisableReasons(old->id());
2318 if (reasons == Extension::DISABLE_NONE) {
2319 // Initialize the reason for legacy disabled extensions from whether the
2320 // extension already exceeded granted permissions.
2321 if (extension_prefs_->DidExtensionEscalatePermissions(old->id()))
2322 disable_reasons = Extension::DISABLE_PERMISSIONS_INCREASE;
2323 else
2324 disable_reasons = Extension::DISABLE_USER_ACTION;
2325 }
2326 } else {
2327 disable_reasons = Extension::DISABLE_PERMISSIONS_INCREASE;
[email protected]44d62b62012-04-11 00:06:032328 }
2329
[email protected]8d888c12010-11-30 00:00:252330 // To upgrade an extension in place, unload the old one and
2331 // then load the new one.
[email protected]814a7bf0f2011-08-13 05:30:592332 UnloadExtension(old->id(), extension_misc::UNLOAD_REASON_UPDATE);
[email protected]8d888c12010-11-30 00:00:252333 old = NULL;
2334 }
2335
2336 // Extension has changed permissions significantly. Disable it. A
2337 // notification should be sent by the caller.
2338 if (is_privilege_increase) {
[email protected]fe2dd7742011-04-19 22:52:492339 if (!extension_prefs_->DidExtensionEscalatePermissions(extension->id())) {
2340 RecordPermissionMessagesHistogram(
2341 extension, "Extensions.Permissions_AutoDisable");
2342 }
[email protected]b3317ad2011-04-28 23:46:002343 extension_prefs_->SetExtensionState(extension->id(), Extension::DISABLED);
[email protected]8d888c12010-11-30 00:00:252344 extension_prefs_->SetDidExtensionEscalatePermissions(extension, true);
[email protected]eb5e4f92012-08-15 23:33:282345 extension_prefs_->AddDisableReason(
2346 extension->id(),
2347 static_cast<Extension::DisableReason>(disable_reasons));
[email protected]8d888c12010-11-30 00:00:252348 }
2349}
2350
[email protected]215a7be2012-10-22 19:53:422351void ExtensionService::MaybeWipeout(
2352 const extensions::Extension* extension) {
[email protected]1ff4d282012-12-08 00:39:212353 if (!wipeout_is_active_)
[email protected]215a7be2012-10-22 19:53:422354 return;
2355
[email protected]1ff4d282012-12-08 00:39:212356 if (extension->GetType() != Extension::TYPE_EXTENSION)
[email protected]215a7be2012-10-22 19:53:422357 return;
2358
[email protected]1ff4d282012-12-08 00:39:212359 Extension::Location location = extension->location();
2360 bool wipable = location == Extension::EXTERNAL_REGISTRY ||
2361 (location == Extension::INTERNAL &&
2362 !extension->UpdatesFromGallery());
2363 if (!wipable)
2364 return;
2365
2366 if (extension_prefs_->IsExternalExtensionExcludedFromWipeout(extension->id()))
2367 return;
2368
[email protected]215a7be2012-10-22 19:53:422369 int disable_reasons = extension_prefs_->GetDisableReasons(extension->id());
[email protected]1ff4d282012-12-08 00:39:212370 if (disable_reasons == Extension::DISABLE_NONE) {
2371 extension_prefs_->SetExtensionState(extension->id(), Extension::DISABLED);
2372 extension_prefs_->AddDisableReason(
2373 extension->id(),
2374 static_cast<Extension::DisableReason>(
2375 Extension::DISABLE_SIDELOAD_WIPEOUT));
2376 UMA_HISTOGRAM_BOOLEAN("DisabledExtension.ExtensionWipedStatus", true);
[email protected]215a7be2012-10-22 19:53:422377 }
2378}
2379
[email protected]eaa7dd182010-12-14 11:09:002380void ExtensionService::UpdateActiveExtensionsInCrashReporter() {
[email protected]c8865962009-12-16 07:47:392381 std::set<std::string> extension_ids;
[email protected]84df8332011-12-06 18:22:462382 for (ExtensionSet::const_iterator iter = extensions_.begin();
2383 iter != extensions_.end(); ++iter) {
2384 const Extension* extension = *iter;
2385 if (!extension->is_theme() && extension->location() != Extension::COMPONENT)
2386 extension_ids.insert(extension->id());
[email protected]aab98a52009-12-02 03:22:352387 }
2388
2389 child_process_logging::SetActiveExtensions(extension_ids);
[email protected]6014d672008-12-05 00:38:252390}
2391
[email protected]8266d662011-07-12 21:53:262392void ExtensionService::OnExtensionInstalled(
[email protected]36a5c4c2011-12-14 16:34:502393 const Extension* extension,
[email protected]98270432012-09-11 20:51:242394 const syncer::StringOrdinal& page_ordinal,
[email protected]0db124b02012-11-07 04:55:052395 bool has_requirement_errors,
2396 bool wait_for_idle) {
[email protected]a29a517a2011-01-21 21:11:122397 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]a8af9fdb2010-10-28 21:52:202398
[email protected]c3cfb012011-04-06 22:07:352399 const std::string& id = extension->id();
[email protected]612a1cb12012-10-17 13:18:032400 bool initial_enable = ShouldEnableOnInstall(extension);
[email protected]3f213ad2012-07-26 23:39:412401 const extensions::PendingExtensionInfo* pending_extension_info = NULL;
[email protected]51a3bf8b2012-06-08 22:53:062402 if ((pending_extension_info = pending_extension_manager()->GetById(id))) {
2403 if (!pending_extension_info->ShouldAllowInstall(*extension)) {
2404 pending_extension_manager()->Remove(id);
[email protected]8ef78fd2010-08-19 17:14:322405
[email protected]31bb5ee62012-09-12 22:58:402406 LOG(WARNING) << "ShouldAllowInstall() returned false for "
2407 << id << " of type " << extension->GetType()
2408 << " and update URL " << extension->update_url().spec()
2409 << "; not installing";
[email protected]ae6cb3022011-04-04 20:11:542410
[email protected]ad50def52011-10-19 23:17:072411 content::NotificationService::current()->Notify(
[email protected]432115822011-07-10 15:52:272412 chrome::NOTIFICATION_EXTENSION_INSTALL_NOT_ALLOWED,
[email protected]6c2381d2011-10-19 02:52:532413 content::Source<Profile>(profile_),
2414 content::Details<const Extension>(extension));
[email protected]ae6cb3022011-04-04 20:11:542415
[email protected]4416c5a2010-06-26 01:28:572416 // Delete the extension directory since we're not going to
2417 // load it.
[email protected]7f8f24f2012-11-15 19:40:142418 if (!GetFileTaskRunner()->PostTask(
2419 FROM_HERE,
[email protected]53612e82011-10-18 18:00:362420 base::Bind(&extension_file_util::DeleteFile,
[email protected]31bb5ee62012-09-12 22:58:402421 extension->path(), true))) {
[email protected]14908b72011-04-20 06:54:362422 NOTREACHED();
[email protected]31bb5ee62012-09-12 22:58:402423 }
[email protected]4416c5a2010-06-26 01:28:572424 return;
2425 }
[email protected]51a3bf8b2012-06-08 22:53:062426
2427 pending_extension_manager()->Remove(id);
[email protected]4416c5a2010-06-26 01:28:572428 } else {
[email protected]c3cfb012011-04-06 22:07:352429 // We explicitly want to re-enable an uninstalled external
2430 // extension; if we're here, that means the user is manually
2431 // installing the extension.
[email protected]6cc7dbae2011-04-29 21:18:332432 if (IsExternalExtensionUninstalled(id)) {
2433 initial_enable = true;
2434 }
[email protected]aa142702010-03-26 01:26:332435 }
2436
[email protected]98270432012-09-11 20:51:242437 // Unsupported requirements overrides the management policy.
2438 if (has_requirement_errors) {
2439 initial_enable = false;
2440 extension_prefs_->AddDisableReason(
2441 id, Extension::DISABLE_UNSUPPORTED_REQUIREMENT);
2442 // If the extension was disabled because of unsupported requirements but
2443 // now supports all requirements after an update and there are not other
2444 // disable reasons, enable it.
2445 } else if (extension_prefs_->GetDisableReasons(id) ==
2446 Extension::DISABLE_UNSUPPORTED_REQUIREMENT) {
2447 initial_enable = true;
2448 extension_prefs_->ClearDisableReasons(id);
2449 }
2450
[email protected]695b5712012-12-06 23:55:282451 if (!GetInstalledExtension(extension->id())) {
[email protected]07533022011-06-27 20:42:552452 UMA_HISTOGRAM_ENUMERATION("Extensions.InstallType",
2453 extension->GetType(), 100);
[email protected]69084dc2012-11-17 07:39:302454 UMA_HISTOGRAM_ENUMERATION("Extensions.InstallSource",
2455 extension->location(), Extension::NUM_LOCATIONS);
[email protected]07533022011-06-27 20:42:552456 RecordPermissionMessagesHistogram(
2457 extension, "Extensions.Permissions_Install");
[email protected]69084dc2012-11-17 07:39:302458 } else {
2459 UMA_HISTOGRAM_ENUMERATION("Extensions.UpdateType",
2460 extension->GetType(), 100);
2461 UMA_HISTOGRAM_ENUMERATION("Extensions.UpdateSource",
2462 extension->location(), Extension::NUM_LOCATIONS);
[email protected]07533022011-06-27 20:42:552463 }
2464
[email protected]a39921b42012-02-28 03:42:542465 // Certain extension locations are specific enough that we can
2466 // auto-acknowledge any extension that came from one of them.
[email protected]31bb5ee62012-09-12 22:58:402467 if (extension->location() == Extension::EXTERNAL_POLICY_DOWNLOAD)
[email protected]a39921b42012-02-28 03:42:542468 AcknowledgeExternalExtension(extension->id());
[email protected]a39921b42012-02-28 03:42:542469
[email protected]e7aa7b7e2012-11-27 04:51:222470 if (ShouldDelayExtensionUpdate(id, wait_for_idle)) {
[email protected]0db124b02012-11-07 04:55:052471 extension_prefs_->SetIdleInstallInfo(
[email protected]69084dc2012-11-17 07:39:302472 extension,
2473 initial_enable ? Extension::ENABLED : Extension::DISABLED);
[email protected]0db124b02012-11-07 04:55:052474
2475 // Transfer ownership of |extension|.
[email protected]6f6101832012-11-27 22:10:482476 pending_extension_updates_.Insert(extension);
[email protected]0db124b02012-11-07 04:55:052477
2478 // Notify extension of available update.
2479 extensions::RuntimeEventRouter::DispatchOnUpdateAvailableEvent(
2480 profile_, id, extension->manifest()->value());
2481 return;
2482 }
2483
[email protected]8c484b742012-11-29 06:05:362484 // Transfer ownership of |extension|.
2485 AddNewOrUpdatedExtension(
2486 extension,
2487 page_ordinal,
2488 initial_enable ? Extension::ENABLED : Extension::DISABLED);
2489}
2490
2491void ExtensionService::AddNewOrUpdatedExtension(
2492 const Extension* extension,
2493 const syncer::StringOrdinal& page_ordinal,
2494 Extension::State initial_state) {
2495 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2496
[email protected]4416c5a2010-06-26 01:28:572497 extension_prefs_->OnExtensionInstalled(
[email protected]8266d662011-07-12 21:53:262498 extension,
[email protected]8c484b742012-11-29 06:05:362499 initial_state,
[email protected]36a5c4c2011-12-14 16:34:502500 page_ordinal);
[email protected]25b34332009-06-05 21:53:192501
[email protected]cdfca9702011-08-08 16:07:012502 // Unpacked extensions default to allowing file access, but if that has been
2503 // overridden, don't reset the value.
[email protected]b6e64fd2011-08-09 19:49:192504 if (Extension::ShouldAlwaysAllowFileAccess(extension->location()) &&
[email protected]8c484b742012-11-29 06:05:362505 !extension_prefs_->HasAllowFileAccessSetting(extension->id())) {
2506 extension_prefs_->SetAllowFileAccess(extension->id(), true);
[email protected]cdfca9702011-08-08 16:07:012507 }
2508
[email protected]6f6101832012-11-27 22:10:482509 FinishInstallation(extension);
2510}
2511
2512void ExtensionService::MaybeFinishDelayedInstallation(
2513 const std::string& extension_id) {
2514 // Check if the extension already got updated.
2515 if (!pending_extension_updates_.Contains(extension_id))
2516 return;
2517 // Check if the extension is idle.
2518 if (!IsExtensionIdle(extension_id))
2519 return;
2520
2521 FinishDelayedInstallation(extension_id);
2522}
2523
2524void ExtensionService::FinishDelayedInstallation(
2525 const std::string& extension_id) {
2526 scoped_refptr<const Extension> extension(
2527 GetPendingExtensionUpdate(extension_id));
2528 CHECK(extension);
2529 pending_extension_updates_.Remove(extension_id);
2530
2531 if (!extension_prefs_->FinishIdleInstallInfo(extension_id))
2532 NOTREACHED();
2533
2534 FinishInstallation(extension);
2535}
2536
2537void ExtensionService::FinishInstallation(const Extension* extension) {
[email protected]fcb58a862012-05-01 01:03:152538 content::NotificationService::current()->Notify(
2539 chrome::NOTIFICATION_EXTENSION_INSTALLED,
2540 content::Source<Profile>(profile_),
2541 content::Details<const Extension>(extension));
2542
[email protected]d96eb512012-11-01 23:44:082543 bool unacknowledged_external = IsUnacknowledgedExternalExtension(extension);
[email protected]41070e8d2012-10-24 01:34:362544
[email protected]6f6101832012-11-27 22:10:482545 AddExtension(extension);
[email protected]612a1cb12012-10-17 13:18:032546
2547 // If this is a new external extension that was disabled, alert the user
[email protected]d96eb512012-11-01 23:44:082548 // so he can reenable it. We do this last so that it has already been
2549 // added to our list of extensions.
2550 if (unacknowledged_external) {
[email protected]612a1cb12012-10-17 13:18:032551 UpdateExternalExtensionAlert();
[email protected]d96eb512012-11-01 23:44:082552 UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalExtensionEvent",
2553 EXTERNAL_EXTENSION_INSTALLED,
2554 EXTERNAL_EXTENSION_BUCKET_BOUNDARY);
2555 }
[email protected]4a190632009-05-09 01:07:422556}
2557
[email protected]76b65442012-11-17 14:11:482558const Extension* ExtensionService::GetPendingExtensionUpdate(
2559 const std::string& id) const {
2560 return pending_extension_updates_.GetByID(id);
2561}
2562
[email protected]bb7f40952011-01-13 00:21:202563void ExtensionService::TrackTerminatedExtension(const Extension* extension) {
[email protected]84df8332011-12-06 18:22:462564 if (!terminated_extensions_.Contains(extension->id()))
2565 terminated_extensions_.Insert(make_scoped_refptr(extension));
[email protected]fa2416f2011-05-03 08:41:202566
[email protected]b3f7fe22011-11-11 19:27:562567 UnloadExtension(extension->id(), extension_misc::UNLOAD_REASON_TERMINATE);
[email protected]bb7f40952011-01-13 00:21:202568}
2569
2570void ExtensionService::UntrackTerminatedExtension(const std::string& id) {
[email protected]fa2416f2011-05-03 08:41:202571 std::string lowercase_id = StringToLowerASCII(id);
[email protected]84df8332011-12-06 18:22:462572 terminated_extensions_.Remove(lowercase_id);
[email protected]bb7f40952011-01-13 00:21:202573}
2574
[email protected]0dfe05c2011-02-23 23:03:362575const Extension* ExtensionService::GetTerminatedExtension(
[email protected]8001df22011-04-28 19:59:472576 const std::string& id) const {
[email protected]695b5712012-12-06 23:55:282577 return GetExtensionById(id, INCLUDE_TERMINATED);
[email protected]8001df22011-04-28 19:59:472578}
2579
2580const Extension* ExtensionService::GetInstalledExtension(
2581 const std::string& id) const {
[email protected]695b5712012-12-06 23:55:282582 int include_mask = INCLUDE_ENABLED |
2583 INCLUDE_DISABLED |
2584 INCLUDE_TERMINATED |
2585 INCLUDE_BLACKLISTED;
2586 return GetExtensionById(id, include_mask);
[email protected]0dfe05c2011-02-23 23:03:362587}
2588
[email protected]eaa7dd182010-12-14 11:09:002589bool ExtensionService::ExtensionBindingsAllowed(const GURL& url) {
[email protected]615d88f2011-12-13 01:47:442590 // Allow bindings for all packaged extensions and component hosted apps.
2591 const Extension* extension = extensions_.GetExtensionOrAppByURL(
2592 ExtensionURLInfo(url));
2593 return extension && (!extension->is_hosted_app() ||
2594 extension->location() == Extension::COMPONENT);
[email protected]6d2e60bd2010-06-03 22:37:392595}
2596
[email protected]4d007b312012-10-17 03:00:482597bool ExtensionService::ShouldBlockUrlInBrowserTab(GURL* url) {
2598 const Extension* extension = extensions_.GetExtensionOrAppByURL(
2599 ExtensionURLInfo(*url));
2600 if (extension && extension->is_platform_app()) {
2601 *url = GURL(chrome::kExtensionInvalidRequestURL);
2602 return true;
2603 }
2604
2605 return false;
2606}
2607
[email protected]e8476c992012-08-20 20:27:592608gfx::Image ExtensionService::GetOmniboxIcon(
[email protected]b671760b2010-07-15 21:13:472609 const std::string& extension_id) {
[email protected]e8476c992012-08-20 20:27:592610 return gfx::Image(omnibox_icon_manager_.GetIcon(extension_id));
[email protected]b671760b2010-07-15 21:13:472611}
2612
[email protected]e8476c992012-08-20 20:27:592613gfx::Image ExtensionService::GetOmniboxPopupIcon(
[email protected]29d0d4ac2010-09-08 21:10:312614 const std::string& extension_id) {
[email protected]e8476c992012-08-20 20:27:592615 return gfx::Image(omnibox_popup_icon_manager_.GetIcon(extension_id));
[email protected]29d0d4ac2010-09-08 21:10:312616}
2617
[email protected]9060d8b02012-01-13 02:14:302618bool ExtensionService::OnExternalExtensionFileFound(
[email protected]8ef78fd2010-08-19 17:14:322619 const std::string& id,
[email protected]8e4560b62011-01-14 10:09:142620 const Version* version,
[email protected]8ef78fd2010-08-19 17:14:322621 const FilePath& path,
[email protected]1bf73cc32011-10-26 22:38:312622 Extension::Location location,
[email protected]47fc70c2011-12-06 07:29:512623 int creation_flags,
2624 bool mark_acknowledged) {
[email protected]ab22ba42011-01-14 16:36:382625 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2626 CHECK(Extension::IdIsValid(id));
[email protected]79c833b52011-04-05 18:31:012627 if (extension_prefs_->IsExternalExtensionUninstalled(id))
[email protected]9060d8b02012-01-13 02:14:302628 return false;
[email protected]a8af9fdb2010-10-28 21:52:202629
[email protected]7577a5c52009-07-30 06:21:582630 // Before even bothering to unpack, check and see if we already have this
[email protected]4c967932009-07-31 01:15:492631 // version. This is important because these extensions are going to get
[email protected]7577a5c52009-07-30 06:21:582632 // installed on every startup.
[email protected]9adb9692010-10-29 23:14:022633 const Extension* existing = GetExtensionById(id, true);
[email protected]910f72ce2012-08-24 01:38:352634
[email protected]7577a5c52009-07-30 06:21:582635 if (existing) {
[email protected]910f72ce2012-08-24 01:38:352636 // The default apps will have the location set as INTERNAL. Since older
2637 // default apps are installed as EXTERNAL, we override them. However, if the
2638 // app is already installed as internal, then do the version check.
[email protected]31bb5ee62012-09-12 22:58:402639 // TODO(grv) : Remove after Q1-2013.
[email protected]910f72ce2012-08-24 01:38:352640 bool is_default_apps_migration =
2641 (location == Extension::INTERNAL &&
2642 Extension::IsExternalLocation(existing->location()));
2643
2644 if (!is_default_apps_migration) {
2645 DCHECK(version);
2646
2647 switch (existing->version()->CompareTo(*version)) {
2648 case -1: // existing version is older, we should upgrade
2649 break;
2650 case 0: // existing version is same, do nothing
2651 return false;
2652 case 1: // existing version is newer, uh-oh
2653 LOG(WARNING) << "Found external version of extension " << id
2654 << "that is older than current version. Current version "
2655 << "is: " << existing->VersionString() << ". New "
2656 << "version is: " << version->GetString()
2657 << ". Keeping current version.";
2658 return false;
2659 }
[email protected]7577a5c52009-07-30 06:21:582660 }
2661 }
2662
[email protected]9060d8b02012-01-13 02:14:302663 // If the extension is already pending, don't start an install.
[email protected]e3987852012-05-04 10:06:302664 if (!pending_extension_manager()->AddFromExternalFile(
2665 id, location, *version)) {
[email protected]9060d8b02012-01-13 02:14:302666 return false;
[email protected]e3987852012-05-04 10:06:302667 }
[email protected]9c635f22010-12-02 09:36:362668
[email protected]14908b72011-04-20 06:54:362669 // no client (silent install)
[email protected]d8c8f25f2011-11-02 18:18:012670 scoped_refptr<CrxInstaller> installer(CrxInstaller::Create(this, NULL));
[email protected]6dfbbf82010-03-12 23:09:162671 installer->set_install_source(location);
2672 installer->set_expected_id(id);
[email protected]cb0e50312011-05-09 15:03:072673 installer->set_expected_version(*version);
2674 installer->set_install_cause(extension_misc::INSTALL_CAUSE_EXTERNAL_FILE);
[email protected]1bf73cc32011-10-26 22:38:312675 installer->set_creation_flags(creation_flags);
[email protected]6dfbbf82010-03-12 23:09:162676 installer->InstallCrx(path);
[email protected]47fc70c2011-12-06 07:29:512677
2678 // Depending on the source, a new external extension might not need a user
2679 // notification on installation. For such extensions, mark them acknowledged
2680 // now to suppress the notification.
2681 if (mark_acknowledged)
2682 AcknowledgeExternalExtension(id);
[email protected]9060d8b02012-01-13 02:14:302683
2684 return true;
[email protected]7577a5c52009-07-30 06:21:582685}
2686
[email protected]eaa7dd182010-12-14 11:09:002687void ExtensionService::ReportExtensionLoadError(
[email protected]d11c8e92009-10-20 23:26:402688 const FilePath& extension_path,
2689 const std::string &error,
[email protected]d11c8e92009-10-20 23:26:402690 bool be_noisy) {
[email protected]d8c8f25f2011-11-02 18:18:012691 content::NotificationService::current()->Notify(
2692 chrome::NOTIFICATION_EXTENSION_LOAD_ERROR,
2693 content::Source<Profile>(profile_),
2694 content::Details<const std::string>(&error));
[email protected]d11c8e92009-10-20 23:26:402695
[email protected]8a205c02011-02-04 20:41:332696 std::string path_str = UTF16ToUTF8(extension_path.LossyDisplayName());
[email protected]438afb12012-07-05 03:18:212697 string16 message = UTF8ToUTF16(base::StringPrintf(
[email protected]18d4b6c2010-09-21 03:21:042698 "Could not load extension from '%s'. %s",
[email protected]fc670822011-12-17 09:33:492699 path_str.c_str(), error.c_str()));
[email protected]d11c8e92009-10-20 23:26:402700 ExtensionErrorReporter::GetInstance()->ReportError(message, be_noisy);
2701}
2702
[email protected]eaa7dd182010-12-14 11:09:002703void ExtensionService::DidCreateRenderViewForBackgroundPage(
[email protected]3a1dc572012-07-31 22:25:132704 extensions::ExtensionHost* host) {
[email protected]406027c02010-09-27 08:03:182705 OrphanedDevTools::iterator iter =
[email protected]2d2f6cfc2011-05-06 21:09:332706 orphaned_dev_tools_.find(host->extension_id());
[email protected]406027c02010-09-27 08:03:182707 if (iter == orphaned_dev_tools_.end())
2708 return;
2709
[email protected]0e12d7d2011-12-01 16:21:442710 DevToolsAgentHost* agent = DevToolsAgentHostRegistry::GetDevToolsAgentHost(
2711 host->render_view_host());
2712 content::DevToolsManager::GetInstance()->AttachClientHost(iter->second,
2713 agent);
[email protected]406027c02010-09-27 08:03:182714 orphaned_dev_tools_.erase(iter);
2715}
2716
[email protected]432115822011-07-10 15:52:272717void ExtensionService::Observe(int type,
[email protected]6c2381d2011-10-19 02:52:532718 const content::NotificationSource& source,
2719 const content::NotificationDetails& details) {
[email protected]432115822011-07-10 15:52:272720 switch (type) {
[email protected]3c4abc82012-10-22 22:25:542721 case chrome::NOTIFICATION_APP_TERMINATING:
2722 // Shutdown has started. Don't start any more extension installs.
2723 // (We cannot use ExtensionService::Shutdown() for this because it
2724 // happens too late in browser teardown.)
2725 browser_terminating_ = true;
2726 break;
[email protected]432115822011-07-10 15:52:272727 case chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED: {
[email protected]6c2381d2011-10-19 02:52:532728 if (profile_ !=
2729 content::Source<Profile>(source).ptr()->GetOriginalProfile()) {
[email protected]bc535ee52010-08-31 18:40:322730 break;
[email protected]6c2381d2011-10-19 02:52:532731 }
[email protected]a4ed6282009-12-14 20:51:162732
[email protected]3a1dc572012-07-31 22:25:132733 extensions::ExtensionHost* host =
2734 content::Details<extensions::ExtensionHost>(details).ptr();
[email protected]f128af42010-08-05 18:05:262735
[email protected]fa2416f2011-05-03 08:41:202736 // Mark the extension as terminated and Unload it. We want it to
2737 // be in a consistent state: either fully working or not loaded
2738 // at all, but never half-crashed. We do it in a PostTask so
2739 // that other handlers of this notification will still have
2740 // access to the Extension and ExtensionHost.
[email protected]14908b72011-04-20 06:54:362741 MessageLoop::current()->PostTask(
2742 FROM_HERE,
[email protected]53612e82011-10-18 18:00:362743 base::Bind(
[email protected]fa2416f2011-05-03 08:41:202744 &ExtensionService::TrackTerminatedExtension,
[email protected]d8c8f25f2011-11-02 18:18:012745 AsWeakPtr(),
[email protected]fa2416f2011-05-03 08:41:202746 host->extension()));
[email protected]31f77262009-12-02 20:48:532747 break;
2748 }
[email protected]432115822011-07-10 15:52:272749 case content::NOTIFICATION_RENDERER_PROCESS_CREATED: {
[email protected]f3b1a082011-11-18 00:34:302750 content::RenderProcessHost* process =
2751 content::Source<content::RenderProcessHost>(source).ptr();
[email protected]fc30ef082011-08-18 04:07:192752 Profile* host_profile =
[email protected]f3b1a082011-11-18 00:34:302753 Profile::FromBrowserContext(process->GetBrowserContext());
[email protected]fc30ef082011-08-18 04:07:192754 if (!profile_->IsSameProfile(host_profile->GetOriginalProfile()))
2755 break;
2756
[email protected]15397b42012-05-16 23:56:062757 // Extensions need to know the channel for API restrictions.
2758 process->Send(new ExtensionMsg_SetChannel(
[email protected]5243df072012-07-11 21:41:012759 extensions::Feature::GetCurrentChannel()));
[email protected]15397b42012-05-16 23:56:062760
[email protected]77a6970c2011-04-23 16:58:562761 // Valid extension function names, used to setup bindings in renderer.
2762 std::vector<std::string> function_names;
2763 ExtensionFunctionDispatcher::GetAllFunctionNames(&function_names);
2764 process->Send(new ExtensionMsg_SetFunctionNames(function_names));
[email protected]31f77262009-12-02 20:48:532765
[email protected]77a6970c2011-04-23 16:58:562766 // Scripting whitelist. This is modified by tests and must be communicated
2767 // to renderers.
2768 process->Send(new ExtensionMsg_SetScriptingWhitelist(
2769 *Extension::GetScriptingWhitelist()));
2770
2771 // Loaded extensions.
[email protected]9776e82e2011-11-15 02:17:532772 std::vector<ExtensionMsg_Loaded_Params> loaded_extensions;
[email protected]84df8332011-12-06 18:22:462773 for (ExtensionSet::const_iterator iter = extensions_.begin();
2774 iter != extensions_.end(); ++iter) {
[email protected]19647262011-12-16 09:57:492775 // Renderers don't need to know about themes.
2776 if (!(*iter)->is_theme())
2777 loaded_extensions.push_back(ExtensionMsg_Loaded_Params(*iter));
[email protected]77a6970c2011-04-23 16:58:562778 }
[email protected]9776e82e2011-11-15 02:17:532779 process->Send(new ExtensionMsg_Loaded(loaded_extensions));
[email protected]77a6970c2011-04-23 16:58:562780 break;
2781 }
[email protected]432115822011-07-10 15:52:272782 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: {
[email protected]f3b1a082011-11-18 00:34:302783 content::RenderProcessHost* process =
2784 content::Source<content::RenderProcessHost>(source).ptr();
[email protected]fc30ef082011-08-18 04:07:192785 Profile* host_profile =
[email protected]f3b1a082011-11-18 00:34:302786 Profile::FromBrowserContext(process->GetBrowserContext());
[email protected]fc30ef082011-08-18 04:07:192787 if (!profile_->IsSameProfile(host_profile->GetOriginalProfile()))
2788 break;
2789
[email protected]6bc04fd82011-12-04 02:29:352790 process_map_.RemoveAllFromProcess(process->GetID());
[email protected]6f371442011-11-09 06:45:462791 BrowserThread::PostTask(
2792 BrowserThread::IO, FROM_HERE,
2793 base::Bind(&ExtensionInfoMap::UnregisterAllExtensionsInProcess,
[email protected]31d8f5f22012-04-02 15:22:082794 system_->info_map(),
[email protected]f3b1a082011-11-18 00:34:302795 process->GetID()));
[email protected]da5683db2011-04-23 17:12:212796 break;
2797 }
[email protected]d91268022011-08-26 13:17:372798 case chrome::NOTIFICATION_IMPORT_FINISHED: {
[email protected]cf593af2011-12-30 05:44:392799 InitAfterImport();
[email protected]d91268022011-08-26 13:17:372800 break;
2801 }
[email protected]0db124b02012-11-07 04:55:052802 case chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED: {
2803 extensions::ExtensionHost* host =
2804 content::Details<extensions::ExtensionHost>(details).ptr();
[email protected]e7aa7b7e2012-11-27 04:51:222805 std::string extension_id = host->extension_id();
2806 if (pending_extension_updates_.Contains(extension_id)) {
2807 // We were waiting for this extension to become idle, it now might have,
2808 // so maybe finish installation.
2809 MessageLoop::current()->PostDelayedTask(
[email protected]0db124b02012-11-07 04:55:052810 FROM_HERE,
[email protected]6f6101832012-11-27 22:10:482811 base::Bind(&ExtensionService::MaybeFinishDelayedInstallation,
[email protected]0db124b02012-11-07 04:55:052812 AsWeakPtr(), extension_id),
2813 base::TimeDelta::FromSeconds(kUpdateIdleDelay));
[email protected]0db124b02012-11-07 04:55:052814 }
2815 break;
2816 }
[email protected]aa96d3a2010-08-21 08:45:252817
[email protected]4814b512009-11-07 00:12:292818 default:
2819 NOTREACHED() << "Unexpected notification type.";
2820 }
2821}
2822
[email protected]90bb38d2012-11-14 18:36:032823void ExtensionService::OnExtensionInstallPrefChanged() {
[email protected]a6a7ced2012-11-01 17:24:182824 IdentifyAlertableExtensions();
2825 CheckManagementPolicy();
2826}
2827
[email protected]eaa7dd182010-12-14 11:09:002828bool ExtensionService::HasApps() const {
[email protected]ec5b50d2010-10-09 16:35:182829 return !GetAppIds().empty();
2830}
[email protected]377011d2010-07-20 04:18:502831
[email protected]eaa7dd182010-12-14 11:09:002832ExtensionIdSet ExtensionService::GetAppIds() const {
[email protected]ec5b50d2010-10-09 16:35:182833 ExtensionIdSet result;
[email protected]84df8332011-12-06 18:22:462834 for (ExtensionSet::const_iterator it = extensions_.begin();
[email protected]377011d2010-07-20 04:18:502835 it != extensions_.end(); ++it) {
[email protected]ec5b50d2010-10-09 16:35:182836 if ((*it)->is_app() && (*it)->location() != Extension::COMPONENT)
2837 result.insert((*it)->id());
[email protected]377011d2010-07-20 04:18:502838 }
2839
[email protected]ec5b50d2010-10-09 16:35:182840 return result;
[email protected]377011d2010-07-20 04:18:502841}
[email protected]d7e9a862010-11-03 21:57:492842
[email protected]dc9a74f72012-08-17 18:07:212843bool ExtensionService::IsBackgroundPageReady(const Extension* extension) const {
2844 if (!extension->has_persistent_background_page())
2845 return true;
2846 ExtensionRuntimeDataMap::const_iterator it =
2847 extension_runtime_data_.find(extension->id());
2848 return it == extension_runtime_data_.end() ? false :
2849 it->second.background_page_ready;
[email protected]d7e9a862010-11-03 21:57:492850}
2851
[email protected]eaa7dd182010-12-14 11:09:002852void ExtensionService::SetBackgroundPageReady(const Extension* extension) {
[email protected]a03d4448f2012-01-10 23:25:282853 DCHECK(extension->has_background_page());
[email protected]d7e9a862010-11-03 21:57:492854 extension_runtime_data_[extension->id()].background_page_ready = true;
[email protected]ad50def52011-10-19 23:17:072855 content::NotificationService::current()->Notify(
[email protected]432115822011-07-10 15:52:272856 chrome::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY,
[email protected]6c2381d2011-10-19 02:52:532857 content::Source<const Extension>(extension),
[email protected]ad50def52011-10-19 23:17:072858 content::NotificationService::NoDetails());
[email protected]d7e9a862010-11-03 21:57:492859}
2860
[email protected]65992d52012-09-19 23:05:312861void ExtensionService::InspectBackgroundPage(const Extension* extension) {
2862 DCHECK(extension);
2863
[email protected]fdd679b2012-11-15 20:49:392864 ExtensionProcessManager* pm = system_->process_manager();
[email protected]65992d52012-09-19 23:05:312865 extensions::LazyBackgroundTaskQueue* queue =
[email protected]fdd679b2012-11-15 20:49:392866 system_->lazy_background_task_queue();
[email protected]65992d52012-09-19 23:05:312867
2868 extensions::ExtensionHost* host =
2869 pm->GetBackgroundHostForExtension(extension->id());
2870 if (host) {
2871 InspectExtensionHost(host);
2872 } else {
2873 queue->AddPendingTask(
2874 profile_, extension->id(),
2875 base::Bind(&ExtensionService::InspectExtensionHost,
2876 base::Unretained(this)));
2877 }
2878}
2879
[email protected]dc9a74f72012-08-17 18:07:212880bool ExtensionService::IsBeingUpgraded(const Extension* extension) const {
2881 ExtensionRuntimeDataMap::const_iterator it =
2882 extension_runtime_data_.find(extension->id());
2883 return it == extension_runtime_data_.end() ? false :
2884 it->second.being_upgraded;
[email protected]d7e9a862010-11-03 21:57:492885}
2886
[email protected]eaa7dd182010-12-14 11:09:002887void ExtensionService::SetBeingUpgraded(const Extension* extension,
[email protected]d7e9a862010-11-03 21:57:492888 bool value) {
2889 extension_runtime_data_[extension->id()].being_upgraded = value;
2890}
[email protected]1bead0712010-11-27 17:41:532891
[email protected]dc9a74f72012-08-17 18:07:212892bool ExtensionService::HasUsedWebRequest(const Extension* extension) const {
2893 ExtensionRuntimeDataMap::const_iterator it =
2894 extension_runtime_data_.find(extension->id());
2895 return it == extension_runtime_data_.end() ? false :
2896 it->second.has_used_webrequest;
[email protected]39a5b532011-10-22 01:47:072897}
2898
2899void ExtensionService::SetHasUsedWebRequest(const Extension* extension,
2900 bool value) {
2901 extension_runtime_data_[extension->id()].has_used_webrequest = value;
2902}
2903
[email protected]cebc3dc2011-04-18 17:15:002904void ExtensionService::RegisterNaClModule(const GURL& url,
2905 const std::string& mime_type) {
2906 NaClModuleInfo info;
2907 info.url = url;
2908 info.mime_type = mime_type;
2909
2910 DCHECK(FindNaClModule(url) == nacl_module_list_.end());
2911 nacl_module_list_.push_front(info);
2912}
2913
2914void ExtensionService::UnregisterNaClModule(const GURL& url) {
2915 NaClModuleInfoList::iterator iter = FindNaClModule(url);
2916 DCHECK(iter != nacl_module_list_.end());
2917 nacl_module_list_.erase(iter);
2918}
2919
[email protected]ed0ba002011-05-26 16:55:132920void ExtensionService::UpdatePluginListWithNaClModules() {
[email protected]300c0ea2011-07-15 23:04:332921 // An extension has been added which has a nacl_module component, which means
2922 // there is a MIME type that module wants to handle, so we need to add that
2923 // MIME type to plugins which handle NaCl modules in order to allow the
2924 // individual modules to handle these types.
[email protected]1e127022011-11-29 21:11:472925 FilePath path;
2926 if (!PathService::Get(chrome::FILE_NACL_PLUGIN, &path))
2927 return;
2928 const content::PepperPluginInfo* pepper_info =
2929 PluginService::GetInstance()->GetRegisteredPpapiPluginInfo(path);
2930 if (!pepper_info)
2931 return;
[email protected]300c0ea2011-07-15 23:04:332932
[email protected]1e127022011-11-29 21:11:472933 std::vector<webkit::WebPluginMimeType>::const_iterator mime_iter;
2934 // Check each MIME type the plugins handle for the NaCl MIME type.
2935 for (mime_iter = pepper_info->mime_types.begin();
2936 mime_iter != pepper_info->mime_types.end(); ++mime_iter) {
2937 if (mime_iter->mime_type == kNaClPluginMimeType) {
2938 // This plugin handles "application/x-nacl".
[email protected]300c0ea2011-07-15 23:04:332939
[email protected]1e127022011-11-29 21:11:472940 PluginService::GetInstance()->
2941 UnregisterInternalPlugin(pepper_info->path);
[email protected]300c0ea2011-07-15 23:04:332942
[email protected]1e127022011-11-29 21:11:472943 webkit::WebPluginInfo info = pepper_info->ToWebPluginInfo();
[email protected]300c0ea2011-07-15 23:04:332944
[email protected]1e127022011-11-29 21:11:472945 for (ExtensionService::NaClModuleInfoList::const_iterator iter =
2946 nacl_module_list_.begin();
2947 iter != nacl_module_list_.end(); ++iter) {
2948 // Add the MIME type specified in the extension to this NaCl plugin,
2949 // With an extra "nacl" argument to specify the location of the NaCl
2950 // manifest file.
2951 webkit::WebPluginMimeType mime_type_info;
2952 mime_type_info.mime_type = iter->mime_type;
2953 mime_type_info.additional_param_names.push_back(UTF8ToUTF16("nacl"));
2954 mime_type_info.additional_param_values.push_back(
2955 UTF8ToUTF16(iter->url.spec()));
2956 info.mime_types.push_back(mime_type_info);
[email protected]300c0ea2011-07-15 23:04:332957 }
[email protected]1e127022011-11-29 21:11:472958
2959 PluginService::GetInstance()->RefreshPlugins();
[email protected]c6f3dea2012-01-14 02:23:112960 PluginService::GetInstance()->RegisterInternalPlugin(info, true);
[email protected]1e127022011-11-29 21:11:472961 // This plugin has been modified, no need to check the rest of its
2962 // types, but continue checking other plugins.
2963 break;
[email protected]ed0ba002011-05-26 16:55:132964 }
2965 }
[email protected]ed0ba002011-05-26 16:55:132966}
2967
[email protected]cebc3dc2011-04-18 17:15:002968ExtensionService::NaClModuleInfoList::iterator
2969 ExtensionService::FindNaClModule(const GURL& url) {
2970 for (NaClModuleInfoList::iterator iter = nacl_module_list_.begin();
2971 iter != nacl_module_list_.end(); ++iter) {
2972 if (iter->url == url)
2973 return iter;
2974 }
2975 return nacl_module_list_.end();
2976}
[email protected]6cafe35a2012-08-27 22:40:502977
[email protected]32b36c62012-10-24 05:37:412978void ExtensionService::DoPostLoadTasks(const Extension* extension) {
2979 std::map<std::string, int>::iterator it =
2980 on_load_events_.find(extension->id());
2981 if (it == on_load_events_.end())
2982 return;
2983
2984 int events_to_fire = it->second;
2985 extensions::LazyBackgroundTaskQueue* queue =
2986 system_->lazy_background_task_queue();
2987 if (queue->ShouldEnqueueTask(profile(), extension)) {
2988 if (events_to_fire & EVENT_LAUNCHED)
[email protected]6cafe35a2012-08-27 22:40:502989 queue->AddPendingTask(profile(), extension->id(),
2990 base::Bind(&ExtensionService::LaunchApplication));
[email protected]32b36c62012-10-24 05:37:412991 if (events_to_fire & EVENT_RESTARTED)
2992 queue->AddPendingTask(profile(), extension->id(),
2993 base::Bind(&ExtensionService::RestartApplication));
[email protected]6cafe35a2012-08-27 22:40:502994 }
[email protected]32b36c62012-10-24 05:37:412995
2996 on_load_events_.erase(it);
[email protected]6cafe35a2012-08-27 22:40:502997}
2998
2999// static
3000void ExtensionService::LaunchApplication(
3001 extensions::ExtensionHost* extension_host) {
3002 if (!extension_host)
3003 return;
3004
3005#if !defined(OS_ANDROID)
3006 extensions::LaunchPlatformApp(extension_host->profile(),
3007 extension_host->extension(),
3008 NULL, FilePath());
3009#endif
3010}
[email protected]65992d52012-09-19 23:05:313011
[email protected]32b36c62012-10-24 05:37:413012// static
3013void ExtensionService::RestartApplication(
3014 extensions::ExtensionHost* extension_host) {
3015 if (!extension_host)
3016 return;
3017
3018#if !defined(OS_ANDROID)
3019 extensions::AppEventRouter::DispatchOnRestartedEvent(
3020 extension_host->profile(), extension_host->extension());
3021#endif
3022}
3023
3024bool ExtensionService::HasShellWindows(const std::string& extension_id) {
3025 const Extension* current_extension = GetExtensionById(extension_id, false);
3026 return current_extension && current_extension->is_platform_app() &&
3027 !extensions::ShellWindowRegistry::Get(profile_)->
3028 GetShellWindowsForApp(extension_id).empty();
3029}
3030
[email protected]65992d52012-09-19 23:05:313031void ExtensionService::InspectExtensionHost(
3032 extensions::ExtensionHost* host) {
3033 if (host)
3034 DevToolsWindow::OpenDevToolsWindow(host->render_view_host());
3035}
[email protected]612a1cb12012-10-17 13:18:033036
3037bool ExtensionService::ShouldEnableOnInstall(const Extension* extension) {
3038 // Extensions installed by policy can't be disabled. So even if a previous
3039 // installation disabled the extension, make sure it is now enabled.
3040 if (system_->management_policy()->MustRemainEnabled(extension, NULL))
3041 return true;
3042
3043 if (extension_prefs_->IsExtensionDisabled(extension->id()))
3044 return false;
3045
[email protected]41070e8d2012-10-24 01:34:363046 if (FeatureSwitch::prompt_for_external_extensions()->IsEnabled()) {
[email protected]612a1cb12012-10-17 13:18:033047 // External extensions are initially disabled. We prompt the user before
3048 // enabling them.
3049 if (Extension::IsExternalLocation(extension->location()) &&
3050 !extension_prefs_->IsExternalExtensionAcknowledged(extension->id())) {
3051 return false;
3052 }
3053 }
[email protected]612a1cb12012-10-17 13:18:033054
3055 return true;
3056}
[email protected]0db124b02012-11-07 04:55:053057
3058bool ExtensionService::IsExtensionIdle(const std::string& extension_id) const {
[email protected]d9a61e12012-11-14 02:43:473059 ExtensionProcessManager* process_manager = system_->process_manager();
[email protected]fc332ae2012-11-14 20:17:333060 DCHECK(process_manager);
[email protected]0db124b02012-11-07 04:55:053061 extensions::ExtensionHost* host =
[email protected]d9a61e12012-11-14 02:43:473062 process_manager->GetBackgroundHostForExtension(extension_id);
[email protected]e7aa7b7e2012-11-27 04:51:223063 if (host)
3064 return false;
3065 return process_manager->GetRenderViewHostsForExtension(extension_id).empty();
3066}
3067
3068bool ExtensionService::ShouldDelayExtensionUpdate(
3069 const std::string& extension_id,
3070 bool wait_for_idle) const {
3071 const char kOnUpdateAvailableEvent[] = "runtime.onUpdateAvailable";
3072
3073 // If delayed updates are globally disabled, or just for this extension,
3074 // don't delay.
3075 if (!install_updates_when_idle_ || !wait_for_idle)
3076 return false;
3077
[email protected]695b5712012-12-06 23:55:283078 const Extension* old = GetInstalledExtension(extension_id);
[email protected]e7aa7b7e2012-11-27 04:51:223079 // If there is no old extension, this is not an update, so don't delay.
3080 if (!old)
3081 return false;
3082
3083 if (old->has_persistent_background_page()) {
3084 // Delay installation if the extension listens for the onUpdateAvailable
3085 // event.
3086 return system_->event_router()->ExtensionHasEventListener(
3087 extension_id, kOnUpdateAvailableEvent);
3088 } else {
3089 // Delay installation if the extension is not idle.
3090 return !IsExtensionIdle(extension_id);
3091 }
[email protected]0db124b02012-11-07 04:55:053092}
[email protected]fdd679b2012-11-15 20:49:393093
3094void ExtensionService::OnBlacklistUpdated() {
[email protected]695b5712012-12-06 23:55:283095 blacklist_->GetBlacklistedIDs(
3096 GenerateInstalledExtensionsSet()->GetIDs(),
3097 base::Bind(&ExtensionService::ManageBlacklist,
3098 AsWeakPtr(),
3099 blacklisted_extensions_.GetIDs()));
3100}
3101
3102void ExtensionService::ManageBlacklist(
3103 const std::set<std::string>& old_blacklisted_ids,
3104 const std::set<std::string>& new_blacklisted_ids) {
3105 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3106
3107 std::set<std::string> no_longer_blacklisted;
3108 std::set_difference(old_blacklisted_ids.begin(), old_blacklisted_ids.end(),
3109 new_blacklisted_ids.begin(), new_blacklisted_ids.end(),
3110 std::inserter(no_longer_blacklisted,
3111 no_longer_blacklisted.begin()));
3112 std::set<std::string> not_yet_blacklisted;
3113 std::set_difference(new_blacklisted_ids.begin(), new_blacklisted_ids.end(),
3114 old_blacklisted_ids.begin(), old_blacklisted_ids.end(),
3115 std::inserter(not_yet_blacklisted,
3116 not_yet_blacklisted.begin()));
3117
3118 for (std::set<std::string>::iterator it = no_longer_blacklisted.begin();
3119 it != no_longer_blacklisted.end(); ++it) {
3120 scoped_refptr<const Extension> extension =
3121 blacklisted_extensions_.GetByID(*it);
3122 DCHECK(extension);
3123 if (!extension)
3124 continue;
3125 blacklisted_extensions_.Remove(*it);
3126 AddExtension(extension);
3127 }
3128
3129 for (std::set<std::string>::iterator it = not_yet_blacklisted.begin();
3130 it != not_yet_blacklisted.end(); ++it) {
3131 scoped_refptr<const Extension> extension = GetInstalledExtension(*it);
3132 DCHECK(extension);
3133 if (!extension)
3134 continue;
3135 blacklisted_extensions_.Insert(extension);
3136 UnloadExtension(*it, extension_misc::UNLOAD_REASON_BLACKLIST);
3137 }
3138
3139 IdentifyAlertableExtensions();
[email protected]fdd679b2012-11-15 20:49:393140}