blob: 5f22ed95c8452d9d9c074a9b39234f3118111990 [file] [log] [blame]
[email protected]1e8c93f2010-02-08 22:58:311// Copyright (c) 2010 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
5#include "chrome/browser/extensions/extensions_service.h"
6
[email protected]24b538a2010-02-27 01:22:447#include "base/basictypes.h"
[email protected]e2eb43112009-05-29 21:19:548#include "base/command_line.h"
[email protected]6014d672008-12-05 00:38:259#include "base/file_util.h"
[email protected]cc2c3432009-11-06 17:24:3610#include "base/histogram.h"
[email protected]cd500f72010-06-25 23:44:3211#include "base/stl_util-inl.h"
[email protected]24b538a2010-02-27 01:22:4412#include "base/string16.h"
[email protected]6014d672008-12-05 00:38:2513#include "base/string_util.h"
[email protected]cc2c3432009-11-06 17:24:3614#include "base/time.h"
[email protected]cc655912009-01-29 23:19:1915#include "base/values.h"
[email protected]aa142702010-03-26 01:26:3316#include "base/version.h"
[email protected]15730c42009-09-03 00:03:2017#include "chrome/browser/browser_process.h"
[email protected]dbb92e0d2009-08-20 16:18:2118#include "chrome/browser/chrome_thread.h"
[email protected]4814b512009-11-07 00:12:2919#include "chrome/browser/debugger/devtools_manager.h"
[email protected]7577a5c52009-07-30 06:21:5820#include "chrome/browser/extensions/crx_installer.h"
[email protected]5cbe1e22010-01-30 01:18:5621#include "chrome/browser/extensions/extension_accessibility_api.h"
[email protected]840b0db2009-11-20 03:00:3822#include "chrome/browser/extensions/extension_bookmarks_module.h"
[email protected]b68d5ed2009-04-16 02:41:2823#include "chrome/browser/extensions/extension_browser_event_router.h"
[email protected]2c5e1e12010-06-10 13:14:4424#include "chrome/browser/extensions/extension_cookies_api.h"
[email protected]c10da4b02010-03-25 14:38:3225#include "chrome/browser/extensions/extension_data_deleter.h"
[email protected]86c008e82009-08-28 20:26:0526#include "chrome/browser/extensions/extension_dom_ui.h"
[email protected]14a000d2010-04-29 21:44:2427#include "chrome/browser/extensions/extension_error_reporter.h"
[email protected]de768a832009-10-30 05:25:0128#include "chrome/browser/extensions/extension_history_api.h"
[email protected]b1748b1d82009-11-30 20:32:5629#include "chrome/browser/extensions/extension_host.h"
[email protected]4814b512009-11-07 00:12:2930#include "chrome/browser/extensions/extension_process_manager.h"
[email protected]93fd78f42009-07-10 16:43:1731#include "chrome/browser/extensions/extension_updater.h"
[email protected]a1257b12009-06-12 02:51:3432#include "chrome/browser/extensions/external_extension_provider.h"
33#include "chrome/browser/extensions/external_pref_extension_provider.h"
[email protected]56ad3792010-05-28 17:45:3334#include "chrome/browser/net/chrome_url_request_context.h"
[email protected]052313b2010-02-19 09:43:0835#include "chrome/browser/pref_service.h"
[email protected]81e63782009-02-27 19:35:0936#include "chrome/browser/profile.h"
[email protected]56ad3792010-05-28 17:45:3337#include "chrome/browser/search_engines/template_url_model.h"
[email protected]aab98a52009-12-02 03:22:3538#include "chrome/common/child_process_logging.h"
[email protected]e2eb43112009-05-29 21:19:5439#include "chrome/common/chrome_switches.h"
[email protected]5b1a0e22009-05-26 19:00:5840#include "chrome/common/extensions/extension.h"
[email protected]d7b36dc2009-10-29 21:47:4041#include "chrome/common/extensions/extension_constants.h"
[email protected]05c82182010-06-24 17:49:0842#include "chrome/common/extensions/extension_error_utils.h"
[email protected]7c927b62010-02-24 09:54:1343#include "chrome/common/extensions/extension_file_util.h"
[email protected]c6d474f82009-12-16 21:11:0644#include "chrome/common/extensions/extension_l10n_util.h"
[email protected]82891262008-12-24 00:21:2645#include "chrome/common/notification_service.h"
[email protected]4814b512009-11-07 00:12:2946#include "chrome/common/notification_type.h"
[email protected]1952c7d2010-03-04 23:48:3447#include "chrome/common/json_value_serializer.h"
[email protected]25b34332009-06-05 21:53:1948#include "chrome/common/pref_names.h"
[email protected]a57209872009-05-04 22:53:1449#include "chrome/common/url_constants.h"
[email protected]c10da4b02010-03-25 14:38:3250#include "googleurl/src/gurl.h"
[email protected]24b538a2010-02-27 01:22:4451#include "webkit/database/database_tracker.h"
52#include "webkit/database/database_util.h"
[email protected]c64631652009-04-29 22:24:3153
[email protected]79db6232009-02-13 20:51:2054#if defined(OS_WIN)
[email protected]a1257b12009-06-12 02:51:3455#include "chrome/browser/extensions/external_registry_extension_provider_win.h"
[email protected]79db6232009-02-13 20:51:2056#endif
[email protected]6014d672008-12-05 00:38:2557
[email protected]5ef47ec2010-01-28 05:58:0558using base::Time;
59
[email protected]c6d474f82009-12-16 21:11:0660namespace errors = extension_manifest_errors;
61
[email protected]b6ab96d2009-08-20 18:58:1962namespace {
63
[email protected]2111b1a2010-03-12 18:12:4464static bool ShouldReloadExtensionManifest(const ExtensionInfo& info) {
65 // Always reload LOAD extension manifests, because they can change on disk
66 // independent of the manifest in our prefs.
67 if (info.extension_location == Extension::LOAD)
68 return true;
69
70 // Otherwise, reload the manifest it needs to be relocalized.
71 return extension_l10n_util::ShouldRelocalizeManifest(info);
72}
73
[email protected]c6d474f82009-12-16 21:11:0674} // namespace
[email protected]b6ab96d2009-08-20 18:58:1975
[email protected]aa142702010-03-26 01:26:3376PendingExtensionInfo::PendingExtensionInfo(const GURL& update_url,
[email protected]aa142702010-03-26 01:26:3377 bool is_theme,
[email protected]4416c5a2010-06-26 01:28:5778 bool install_silently,
79 bool enable_on_install,
80 bool enable_incognito_on_install)
[email protected]aa142702010-03-26 01:26:3381 : update_url(update_url),
[email protected]aa142702010-03-26 01:26:3382 is_theme(is_theme),
[email protected]4416c5a2010-06-26 01:28:5783 install_silently(install_silently),
84 enable_on_install(enable_on_install),
85 enable_incognito_on_install(enable_incognito_on_install) {}
[email protected]aa142702010-03-26 01:26:3386
87PendingExtensionInfo::PendingExtensionInfo()
88 : update_url(),
[email protected]aa142702010-03-26 01:26:3389 is_theme(false),
[email protected]4416c5a2010-06-26 01:28:5790 install_silently(false),
91 enable_on_install(false),
92 enable_incognito_on_install(false) {}
[email protected]aa142702010-03-26 01:26:3393
[email protected]25b34332009-06-05 21:53:1994// ExtensionsService.
[email protected]6014d672008-12-05 00:38:2595
[email protected]cc655912009-01-29 23:19:1996const char* ExtensionsService::kInstallDirectoryName = "Extensions";
97const char* ExtensionsService::kCurrentVersionFileName = "Current Version";
[email protected]494c06e2009-07-25 01:06:4298
[email protected]334e04a2010-06-24 23:34:4499bool ExtensionsService::IsGalleryDownloadURL(const GURL& download_url) {
[email protected]b7c2f252009-12-08 00:47:23100 if (StartsWithASCII(download_url.spec(),
[email protected]334e04a2010-06-24 23:34:44101 extension_urls::kMiniGalleryDownloadPrefix, false))
102 return true;
[email protected]b7c2f252009-12-08 00:47:23103
[email protected]334e04a2010-06-24 23:34:44104 GURL gallery_download_prefix(extension_urls::kGalleryDownloadPrefix);
105 if (download_url.host() == gallery_download_prefix.host() &&
106 StartsWithASCII(download_url.path(),
107 gallery_download_prefix.path(), false))
[email protected]b7c2f252009-12-08 00:47:23108 return true;
[email protected]b7c2f252009-12-08 00:47:23109
[email protected]473ff6e2010-05-12 15:31:55110 // Allow command line gallery url to be referrer for the gallery downloads.
111 std::string command_line_gallery_url =
112 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
[email protected]2bce5e12010-05-13 01:18:07113 switches::kAppsGalleryURL);
[email protected]473ff6e2010-05-12 15:31:55114 if (!command_line_gallery_url.empty() &&
115 StartsWithASCII(download_url.spec(),
[email protected]334e04a2010-06-24 23:34:44116 extension_urls::kGalleryDownloadPrefix, false))
[email protected]473ff6e2010-05-12 15:31:55117 return true;
[email protected]334e04a2010-06-24 23:34:44118
119 return false;
120}
121
122// static
123bool ExtensionsService::IsDownloadFromGallery(const GURL& download_url,
124 const GURL& referrer_url) {
125 if (!IsGalleryDownloadURL(download_url))
126 return false;
127
128 if (StartsWithASCII(referrer_url.spec(),
129 extension_urls::kMiniGalleryBrowsePrefix, false))
130 return true;
131
132 if (StartsWithASCII(referrer_url.spec(),
133 Extension::ChromeStoreURL(), false))
134 return true;
135
136 // Allow command line gallery url to be referrer for the gallery downloads.
137 std::string command_line_gallery_url =
138 CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
139 switches::kAppsGalleryURL);
140 if (!command_line_gallery_url.empty() &&
141 StartsWithASCII(referrer_url.spec(),
142 command_line_gallery_url, false))
143 return true;
[email protected]473ff6e2010-05-12 15:31:55144
[email protected]b7c2f252009-12-08 00:47:23145 return false;
146}
147
[email protected]ac025282009-12-16 19:16:38148bool ExtensionsService::IsDownloadFromMiniGallery(const GURL& download_url) {
149 return StartsWithASCII(download_url.spec(),
150 extension_urls::kMiniGalleryDownloadPrefix,
151 false); // case_sensitive
152}
153
[email protected]81e63782009-02-27 19:35:09154ExtensionsService::ExtensionsService(Profile* profile,
[email protected]36a784c2009-06-23 06:21:08155 const CommandLine* command_line,
[email protected]a9b00ac2009-06-25 21:03:23156 PrefService* prefs,
157 const FilePath& install_directory,
[email protected]93fd78f42009-07-10 16:43:17158 bool autoupdate_enabled)
[email protected]6ef635e42009-07-26 06:16:12159 : profile_(profile),
160 extension_prefs_(new ExtensionPrefs(prefs, install_directory)),
[email protected]a9b00ac2009-06-25 21:03:23161 install_directory_(install_directory),
[email protected]6d60703b2009-08-29 01:29:23162 extensions_enabled_(true),
[email protected]e81dba32009-06-19 20:19:13163 show_extensions_prompts_(true),
[email protected]e0360f2c2009-12-07 22:34:31164 ready_(false),
165 ALLOW_THIS_IN_INITIALIZER_LIST(toolbar_model_(this)) {
[email protected]36a784c2009-06-23 06:21:08166 // Figure out if extension installation should be enabled.
[email protected]6d60703b2009-08-29 01:29:23167 if (command_line->HasSwitch(switches::kDisableExtensions)) {
168 extensions_enabled_ = false;
169 } else if (profile->GetPrefs()->GetBoolean(prefs::kDisableExtensions)) {
170 extensions_enabled_ = false;
[email protected]6b75ec32009-08-14 06:37:18171 }
[email protected]36a784c2009-06-23 06:21:08172
[email protected]4814b512009-11-07 00:12:29173 registrar_.Add(this, NotificationType::EXTENSION_HOST_DID_STOP_LOADING,
174 NotificationService::AllSources());
[email protected]a4ed6282009-12-14 20:51:16175 registrar_.Add(this, NotificationType::EXTENSION_PROCESS_TERMINATED,
[email protected]31f77262009-12-02 20:48:53176 Source<Profile>(profile_));
[email protected]4814b512009-11-07 00:12:29177
[email protected]93fd78f42009-07-10 16:43:17178 // Set up the ExtensionUpdater
179 if (autoupdate_enabled) {
180 int update_frequency = kDefaultUpdateFrequencySeconds;
181 if (command_line->HasSwitch(switches::kExtensionsUpdateFrequency)) {
[email protected]c4e52f0d2009-11-06 19:55:16182 update_frequency = StringToInt(command_line->GetSwitchValueASCII(
183 switches::kExtensionsUpdateFrequency));
[email protected]93fd78f42009-07-10 16:43:17184 }
[email protected]95d29192009-10-30 01:49:06185 updater_ = new ExtensionUpdater(this, prefs, update_frequency);
[email protected]93fd78f42009-07-10 16:43:17186 }
187
[email protected]95d29192009-10-30 01:49:06188 backend_ = new ExtensionsServiceBackend(install_directory_);
[email protected]6014d672008-12-05 00:38:25189}
190
191ExtensionsService::~ExtensionsService() {
[email protected]9f1087e2009-06-15 17:29:32192 UnloadAllExtensions();
[email protected]93fd78f42009-07-10 16:43:17193 if (updater_.get()) {
194 updater_->Stop();
195 }
[email protected]6014d672008-12-05 00:38:25196}
197
[email protected]c5ae74ab2010-04-15 18:14:37198void ExtensionsService::InitEventRouters() {
199 ExtensionHistoryEventRouter::GetInstance()->ObserveProfile(profile_);
200 ExtensionAccessibilityEventRouter::GetInstance()->ObserveProfile(profile_);
[email protected]56ee0152010-06-16 01:54:42201 ExtensionBrowserEventRouter::GetInstance()->Init(profile_);
[email protected]c5ae74ab2010-04-15 18:14:37202 ExtensionBookmarkEventRouter::GetSingleton()->Observe(
203 profile_->GetBookmarkModel());
[email protected]2c5e1e12010-06-10 13:14:44204 ExtensionCookiesEventRouter::GetInstance()->Init();
[email protected]c5ae74ab2010-04-15 18:14:37205}
206
[email protected]9f1087e2009-06-15 17:29:32207void ExtensionsService::Init() {
[email protected]c6e4a3412009-06-24 15:45:29208 DCHECK(!ready_);
[email protected]93fd78f42009-07-10 16:43:17209 DCHECK_EQ(extensions_.size(), 0u);
[email protected]9f1087e2009-06-15 17:29:32210
[email protected]95dd38f2009-10-20 20:09:15211 // Hack: we need to ensure the ResourceDispatcherHost is ready before we load
212 // the first extension, because its members listen for loaded notifications.
213 g_browser_process->resource_dispatcher_host();
214
[email protected]9f1087e2009-06-15 17:29:32215 LoadAllExtensions();
[email protected]894bb502009-05-21 22:39:57216
[email protected]9f1087e2009-06-15 17:29:32217 // TODO(erikkay) this should probably be deferred to a future point
218 // rather than running immediately at startup.
[email protected]93fd78f42009-07-10 16:43:17219 CheckForExternalUpdates();
[email protected]894bb502009-05-21 22:39:57220
[email protected]9f1087e2009-06-15 17:29:32221 // TODO(erikkay) this should probably be deferred as well.
222 GarbageCollectExtensions();
[email protected]6014d672008-12-05 00:38:25223}
224
[email protected]3cf4f0992009-02-03 23:00:30225void ExtensionsService::InstallExtension(const FilePath& extension_path) {
[email protected]6dfbbf82010-03-12 23:09:16226 scoped_refptr<CrxInstaller> installer(
227 new CrxInstaller(install_directory_,
228 this, // frontend
229 NULL)); // no client (silent install)
230 installer->set_allow_privilege_increase(true);
231 installer->InstallCrx(extension_path);
[email protected]3cf4f0992009-02-03 23:00:30232}
233
[email protected]aa142702010-03-26 01:26:33234namespace {
235 // TODO(akalin): Put this somewhere where both crx_installer.cc and
236 // this file can use it.
237 void DeleteFileHelper(const FilePath& path, bool recursive) {
238 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
239 file_util::Delete(path, recursive);
240 }
241} // namespace
242
[email protected]e957fe52009-06-23 16:51:05243void ExtensionsService::UpdateExtension(const std::string& id,
[email protected]5c8516202010-03-18 21:43:34244 const FilePath& extension_path,
245 const GURL& download_url) {
[email protected]aa142702010-03-26 01:26:33246 PendingExtensionMap::const_iterator it = pending_extensions_.find(id);
247 if ((it == pending_extensions_.end()) &&
248 !GetExtensionByIdInternal(id, true, true)) {
249 LOG(WARNING) << "Will not update extension " << id
250 << " because it is not installed or pending";
251 // Delete extension_path since we're not creating a CrxInstaller
252 // that would do it for us.
253 ChromeThread::PostTask(
254 ChromeThread::FILE, FROM_HERE,
255 NewRunnableFunction(&DeleteFileHelper, extension_path, false));
[email protected]4c967932009-07-31 01:15:49256 return;
[email protected]e957fe52009-06-23 16:51:05257 }
258
[email protected]aa142702010-03-26 01:26:33259 // We want a silent install only for non-pending extensions and
260 // pending extensions that have install_silently set.
261 ExtensionInstallUI* client =
262 ((it == pending_extensions_.end()) || it->second.install_silently) ?
263 NULL : new ExtensionInstallUI(profile_);
264
[email protected]6dfbbf82010-03-12 23:09:16265 scoped_refptr<CrxInstaller> installer(
266 new CrxInstaller(install_directory_,
267 this, // frontend
[email protected]aa142702010-03-26 01:26:33268 client));
[email protected]6dfbbf82010-03-12 23:09:16269 installer->set_expected_id(id);
270 installer->set_delete_source(true);
[email protected]9f72aa02010-06-25 10:01:05271 installer->set_limit_web_extent_to_download_host(true);
[email protected]5c8516202010-03-18 21:43:34272 installer->set_original_url(download_url);
[email protected]6dfbbf82010-03-12 23:09:16273 installer->InstallCrx(extension_path);
[email protected]e957fe52009-06-23 16:51:05274}
275
[email protected]aa142702010-03-26 01:26:33276void ExtensionsService::AddPendingExtension(
277 const std::string& id, const GURL& update_url,
[email protected]4416c5a2010-06-26 01:28:57278 bool is_theme, bool install_silently,
279 bool enable_on_install, bool enable_incognito_on_install) {
[email protected]aa142702010-03-26 01:26:33280 if (GetExtensionByIdInternal(id, true, true)) {
[email protected]efee9f262010-03-29 21:26:25281 LOG(DFATAL) << "Trying to add pending extension " << id
282 << " which already exists";
[email protected]aa142702010-03-26 01:26:33283 return;
284 }
[email protected]4416c5a2010-06-26 01:28:57285 AddPendingExtensionInternal(
286 id, update_url, is_theme, install_silently,
287 enable_on_install, enable_incognito_on_install);
[email protected]aa142702010-03-26 01:26:33288}
289
290void ExtensionsService::AddPendingExtensionInternal(
291 const std::string& id, const GURL& update_url,
[email protected]4416c5a2010-06-26 01:28:57292 bool is_theme, bool install_silently,
293 bool enable_on_install, bool enable_incognito_on_install) {
[email protected]aa142702010-03-26 01:26:33294 pending_extensions_[id] =
[email protected]4416c5a2010-06-26 01:28:57295 PendingExtensionInfo(update_url, is_theme, install_silently,
296 enable_on_install, enable_incognito_on_install);
[email protected]aa142702010-03-26 01:26:33297}
298
[email protected]9cddd4702009-07-27 22:09:40299void ExtensionsService::ReloadExtension(const std::string& extension_id) {
[email protected]b65272f2009-08-31 15:47:06300 FilePath path;
[email protected]61b411612009-11-10 23:17:41301 Extension* current_extension = GetExtensionById(extension_id, false);
[email protected]9cddd4702009-07-27 22:09:40302
[email protected]b65272f2009-08-31 15:47:06303 // Unload the extension if it's loaded. It might not be loaded if it crashed.
304 if (current_extension) {
[email protected]4814b512009-11-07 00:12:29305 // If the extension has an inspector open for its background page, detach
306 // the inspector and hang onto a cookie for it, so that we can reattach
307 // later.
308 ExtensionProcessManager* manager = profile_->GetExtensionProcessManager();
309 ExtensionHost* host = manager->GetBackgroundHostForExtension(
310 current_extension);
311 if (host) {
312 // Look for an open inspector for the background page.
313 int devtools_cookie = DevToolsManager::GetInstance()->DetachClientHost(
314 host->render_view_host());
315 if (devtools_cookie >= 0)
316 orphaned_dev_tools_[extension_id] = devtools_cookie;
317 }
318
[email protected]b65272f2009-08-31 15:47:06319 path = current_extension->path();
320 UnloadExtension(extension_id);
[email protected]1eb175082010-02-10 09:26:16321 } else {
322 path = unloaded_extension_paths_[extension_id];
[email protected]b65272f2009-08-31 15:47:06323 }
324
[email protected]e6090e42010-03-23 22:44:08325 // Check the installed extensions to see if what we're reloading was already
326 // installed.
327 scoped_ptr<ExtensionInfo> installed_extension(
328 extension_prefs_->GetInstalledExtensionInfo(extension_id));
329 if (installed_extension.get() &&
330 installed_extension->extension_manifest.get()) {
331 LoadInstalledExtension(*installed_extension, false);
332 } else {
333 // We should always be able to remember the extension's path. If it's not in
334 // the map, someone failed to update |unloaded_extension_paths_|.
335 CHECK(!path.empty());
336 LoadExtension(path);
337 }
[email protected]9cddd4702009-07-27 22:09:40338}
339
[email protected]27b985d2009-06-25 17:53:15340void ExtensionsService::UninstallExtension(const std::string& extension_id,
341 bool external_uninstall) {
[email protected]0c6da502009-08-14 22:32:39342 Extension* extension = GetExtensionByIdInternal(extension_id, true, true);
[email protected]631cf822009-05-15 07:01:25343
[email protected]9f1087e2009-06-15 17:29:32344 // Callers should not send us nonexistant extensions.
[email protected]e72e8eb82009-06-18 17:21:51345 DCHECK(extension);
[email protected]9f1087e2009-06-15 17:29:32346
[email protected]831aa212010-03-26 13:55:19347 // Get hold of information we need after unloading, since the extension
348 // pointer will be invalid then.
349 GURL extension_url(extension->url());
350 Extension::Location location(extension->location());
351
352 // Also copy the extension identifier since the reference might have been
353 // obtained via Extension::id().
354 std::string extension_id_copy(extension_id);
355
[email protected]56ad3792010-05-28 17:45:33356 if (profile_->GetTemplateURLModel())
357 profile_->GetTemplateURLModel()->UnregisterExtensionKeyword(extension);
358
[email protected]831aa212010-03-26 13:55:19359 // Unload before doing more cleanup to ensure that nothing is hanging on to
360 // any of these resources.
361 UnloadExtension(extension_id);
362
363 extension_prefs_->OnExtensionUninstalled(extension_id_copy, location,
364 external_uninstall);
[email protected]9f1087e2009-06-15 17:29:32365
366 // Tell the backend to start deleting installed extensions on the file thread.
[email protected]831aa212010-03-26 13:55:19367 if (Extension::LOAD != location) {
[email protected]95d29192009-10-30 01:49:06368 ChromeThread::PostTask(
369 ChromeThread::FILE, FROM_HERE,
370 NewRunnableFunction(
[email protected]ca3dbf52010-05-19 22:27:06371 &extension_file_util::UninstallExtension,
372 install_directory_,
373 extension_id_copy));
[email protected]9f1087e2009-06-15 17:29:32374 }
375
[email protected]c10da4b02010-03-25 14:38:32376 ClearExtensionData(extension_url);
377}
378
379void ExtensionsService::ClearExtensionData(const GURL& extension_url) {
380 scoped_refptr<ExtensionDataDeleter> deleter(
381 new ExtensionDataDeleter(profile_, extension_url));
382 deleter->StartDeleting();
[email protected]9f1087e2009-06-15 17:29:32383}
384
[email protected]0c6da502009-08-14 22:32:39385void ExtensionsService::EnableExtension(const std::string& extension_id) {
386 Extension* extension = GetExtensionByIdInternal(extension_id, false, true);
387 if (!extension) {
388 NOTREACHED() << "Trying to enable an extension that isn't disabled.";
389 return;
390 }
391
[email protected]e8c729a2010-03-09 19:55:19392 extension_prefs_->SetExtensionState(extension, Extension::ENABLED);
[email protected]1784e83a2009-09-08 21:01:52393
[email protected]0c6da502009-08-14 22:32:39394 // Move it over to the enabled list.
[email protected]0c6da502009-08-14 22:32:39395 extensions_.push_back(extension);
396 ExtensionList::iterator iter = std::find(disabled_extensions_.begin(),
397 disabled_extensions_.end(),
398 extension);
399 disabled_extensions_.erase(iter);
400
[email protected]86c008e82009-08-28 20:26:05401 ExtensionDOMUI::RegisterChromeURLOverrides(profile_,
402 extension->GetChromeURLOverrides());
403
[email protected]62d30f42009-10-01 22:36:06404 NotifyExtensionLoaded(extension);
[email protected]aab98a52009-12-02 03:22:35405 UpdateActiveExtensionsInCrashReporter();
[email protected]0c6da502009-08-14 22:32:39406}
407
[email protected]1784e83a2009-09-08 21:01:52408void ExtensionsService::DisableExtension(const std::string& extension_id) {
409 Extension* extension = GetExtensionByIdInternal(extension_id, true, false);
[email protected]b2ba9962009-12-10 20:10:15410 // The extension may have been disabled already.
411 if (!extension)
[email protected]1784e83a2009-09-08 21:01:52412 return;
[email protected]1784e83a2009-09-08 21:01:52413
[email protected]e8c729a2010-03-09 19:55:19414 extension_prefs_->SetExtensionState(extension, Extension::DISABLED);
[email protected]1784e83a2009-09-08 21:01:52415
416 // Move it over to the disabled list.
417 disabled_extensions_.push_back(extension);
418 ExtensionList::iterator iter = std::find(extensions_.begin(),
419 extensions_.end(),
420 extension);
421 extensions_.erase(iter);
422
423 ExtensionDOMUI::UnregisterChromeURLOverrides(profile_,
424 extension->GetChromeURLOverrides());
425
[email protected]62d30f42009-10-01 22:36:06426 NotifyExtensionUnloaded(extension);
[email protected]aab98a52009-12-02 03:22:35427 UpdateActiveExtensionsInCrashReporter();
[email protected]1784e83a2009-09-08 21:01:52428}
429
[email protected]9f1087e2009-06-15 17:29:32430void ExtensionsService::LoadExtension(const FilePath& extension_path) {
[email protected]95d29192009-10-30 01:49:06431 ChromeThread::PostTask(
432 ChromeThread::FILE, FROM_HERE,
433 NewRunnableMethod(
434 backend_.get(),
435 &ExtensionsServiceBackend::LoadSingleExtension,
436 extension_path, scoped_refptr<ExtensionsService>(this)));
[email protected]9f1087e2009-06-15 17:29:32437}
438
[email protected]1952c7d2010-03-04 23:48:34439void ExtensionsService::LoadComponentExtensions() {
440 for (RegisteredComponentExtensions::iterator it =
441 component_extension_manifests_.begin();
442 it != component_extension_manifests_.end(); ++it) {
443 JSONStringValueSerializer serializer(it->manifest);
[email protected]ba399672010-04-06 15:42:39444 scoped_ptr<Value> manifest(serializer.Deserialize(NULL, NULL));
[email protected]999731f2010-03-22 19:13:53445 if (!manifest.get()) {
[email protected]960ef8ae2010-05-06 17:12:29446 DLOG(ERROR) << "Failed to retrieve manifest for extension";
[email protected]999731f2010-03-22 19:13:53447 continue;
448 }
[email protected]1952c7d2010-03-04 23:48:34449
450 scoped_ptr<Extension> extension(new Extension(it->root_directory));
451 extension->set_location(Extension::COMPONENT);
452
453 std::string error;
454 if (!extension->InitFromValue(
455 *static_cast<DictionaryValue*>(manifest.get()),
456 true, // require key
457 &error)) {
458 NOTREACHED();
459 return;
460 }
461
462 OnExtensionLoaded(extension.release(), false); // Don't allow privilege
463 // increase.
464 }
465}
466
[email protected]9f1087e2009-06-15 17:29:32467void ExtensionsService::LoadAllExtensions() {
[email protected]cc2c3432009-11-06 17:24:36468 base::TimeTicks start_time = base::TimeTicks::Now();
469
[email protected]1952c7d2010-03-04 23:48:34470 // Load any component extensions.
471 LoadComponentExtensions();
472
[email protected]e72e8eb82009-06-18 17:21:51473 // Load the previously installed extensions.
[email protected]c6d474f82009-12-16 21:11:06474 scoped_ptr<ExtensionPrefs::ExtensionsInfo> info(
[email protected]e6090e42010-03-23 22:44:08475 extension_prefs_->GetInstalledExtensionsInfo());
[email protected]c6d474f82009-12-16 21:11:06476
477 // If any extensions need localization, we bounce them all to the file thread
478 // for re-reading and localization.
479 for (size_t i = 0; i < info->size(); ++i) {
[email protected]2111b1a2010-03-12 18:12:44480 if (ShouldReloadExtensionManifest(*info->at(i))) {
[email protected]c6d474f82009-12-16 21:11:06481 ChromeThread::PostTask(
482 ChromeThread::FILE, FROM_HERE, NewRunnableMethod(
483 backend_.get(),
[email protected]2111b1a2010-03-12 18:12:44484 &ExtensionsServiceBackend::ReloadExtensionManifests,
[email protected]c6d474f82009-12-16 21:11:06485 info.release(), // Callee takes ownership of the memory.
486 start_time,
487 scoped_refptr<ExtensionsService>(this)));
488 return;
489 }
490 }
491
492 // Don't update prefs.
493 // Callee takes ownership of the memory.
494 ContinueLoadAllExtensions(info.release(), start_time, false);
495}
496
497void ExtensionsService::ContinueLoadAllExtensions(
498 ExtensionPrefs::ExtensionsInfo* extensions_info,
499 base::TimeTicks start_time,
500 bool write_to_prefs) {
501 scoped_ptr<ExtensionPrefs::ExtensionsInfo> info(extensions_info);
502
503 for (size_t i = 0; i < info->size(); ++i) {
504 LoadInstalledExtension(*info->at(i), write_to_prefs);
505 }
506
[email protected]ae09ca62009-08-21 19:46:46507 OnLoadedInstalledExtensions();
[email protected]cc2c3432009-11-06 17:24:36508
509 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAll", extensions_.size());
510 UMA_HISTOGRAM_COUNTS_100("Extensions.Disabled", disabled_extensions_.size());
511
[email protected]1952c7d2010-03-04 23:48:34512 UMA_HISTOGRAM_TIMES("Extensions.LoadAllTime",
513 base::TimeTicks::Now() - start_time);
[email protected]cc2c3432009-11-06 17:24:36514
[email protected]1952c7d2010-03-04 23:48:34515 int user_script_count = 0;
516 int extension_count = 0;
517 int theme_count = 0;
518 int external_count = 0;
519 int page_action_count = 0;
520 int browser_action_count = 0;
521 ExtensionList::iterator ex;
522 for (ex = extensions_.begin(); ex != extensions_.end(); ++ex) {
523 // Don't count component extensions, since they are only extensions as an
524 // implementation detail.
525 if ((*ex)->location() == Extension::COMPONENT)
526 continue;
527
[email protected]e8c729a2010-03-09 19:55:19528 // Don't count unpacked extensions, since they're a developer-specific
529 // feature.
530 if ((*ex)->location() == Extension::LOAD)
531 continue;
532
[email protected]3ba0fd32010-06-19 05:39:10533 if ((*ex)->is_theme()) {
[email protected]1952c7d2010-03-04 23:48:34534 theme_count++;
535 } else if ((*ex)->converted_from_user_script()) {
536 user_script_count++;
537 } else {
538 extension_count++;
[email protected]cc2c3432009-11-06 17:24:36539 }
[email protected]1952c7d2010-03-04 23:48:34540 if (Extension::IsExternalLocation((*ex)->location())) {
541 external_count++;
542 }
543 if ((*ex)->page_action() != NULL) {
544 page_action_count++;
545 }
546 if ((*ex)->browser_action() != NULL) {
547 browser_action_count++;
548 }
[email protected]cc2c3432009-11-06 17:24:36549 }
[email protected]1952c7d2010-03-04 23:48:34550 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtension", extension_count);
551 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadUserScript", user_script_count);
552 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadTheme", theme_count);
553 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExternal", external_count);
554 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPageAction", page_action_count);
555 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadBrowserAction",
556 browser_action_count);
[email protected]ae09ca62009-08-21 19:46:46557}
558
[email protected]c6d474f82009-12-16 21:11:06559void ExtensionsService::LoadInstalledExtension(const ExtensionInfo& info,
560 bool write_to_prefs) {
[email protected]ae09ca62009-08-21 19:46:46561 std::string error;
562 Extension* extension = NULL;
[email protected]c6d474f82009-12-16 21:11:06563 if (info.extension_manifest.get()) {
564 scoped_ptr<Extension> tmp(new Extension(info.extension_path));
[email protected]e8c729a2010-03-09 19:55:19565 bool require_key = info.extension_location != Extension::LOAD;
566 if (tmp->InitFromValue(*info.extension_manifest, require_key, &error))
[email protected]ae09ca62009-08-21 19:46:46567 extension = tmp.release();
[email protected]ae09ca62009-08-21 19:46:46568 } else {
[email protected]c6d474f82009-12-16 21:11:06569 error = errors::kManifestUnreadable;
[email protected]ae09ca62009-08-21 19:46:46570 }
571
572 if (!extension) {
[email protected]c6d474f82009-12-16 21:11:06573 ReportExtensionLoadError(info.extension_path,
[email protected]d11c8e92009-10-20 23:26:40574 error,
575 NotificationType::EXTENSION_INSTALL_ERROR,
576 false);
[email protected]ae09ca62009-08-21 19:46:46577 return;
578 }
579
[email protected]c6d474f82009-12-16 21:11:06580 extension->set_location(info.extension_location);
581
582 if (write_to_prefs)
583 extension_prefs_->UpdateManifest(extension);
584
[email protected]2a409532009-08-28 19:39:44585 OnExtensionLoaded(extension, true);
[email protected]ae09ca62009-08-21 19:46:46586
[email protected]c6d474f82009-12-16 21:11:06587 if (info.extension_location == Extension::EXTERNAL_PREF ||
588 info.extension_location == Extension::EXTERNAL_REGISTRY) {
[email protected]95d29192009-10-30 01:49:06589 ChromeThread::PostTask(
590 ChromeThread::FILE, FROM_HERE,
591 NewRunnableMethod(
[email protected]c6d474f82009-12-16 21:11:06592 backend_.get(),
593 &ExtensionsServiceBackend::CheckExternalUninstall,
594 scoped_refptr<ExtensionsService>(this),
595 info.extension_id,
596 info.extension_location));
[email protected]ae09ca62009-08-21 19:46:46597 }
[email protected]9f1087e2009-06-15 17:29:32598}
599
[email protected]62d30f42009-10-01 22:36:06600void ExtensionsService::NotifyExtensionLoaded(Extension* extension) {
[email protected]57a777f72010-03-31 01:09:42601 // The ChromeURLRequestContexts need to be first to know that the extension
[email protected]62d30f42009-10-01 22:36:06602 // was loaded, otherwise a race can arise where a renderer that is created
603 // for the extension may try to load an extension URL with an extension id
[email protected]57a777f72010-03-31 01:09:42604 // that the request context doesn't yet know about. The profile is responsible
605 // for ensuring its URLRequestContexts appropriately discover the loaded
606 // extension.
607 if (profile_) {
608 profile_->RegisterExtensionWithRequestContexts(extension);
[email protected]24b538a2010-02-27 01:22:44609
610 // Check if this permission requires unlimited storage quota
611 if (extension->HasApiPermission(Extension::kUnlimitedStoragePermission)) {
612 string16 origin_identifier =
613 webkit_database::DatabaseUtil::GetOriginIdentifier(extension->url());
614 ChromeThread::PostTask(
615 ChromeThread::FILE, FROM_HERE,
616 NewRunnableMethod(
617 profile_->GetDatabaseTracker(),
618 &webkit_database::DatabaseTracker::SetOriginQuotaInMemory,
619 origin_identifier,
620 kint64max));
621 }
[email protected]62d30f42009-10-01 22:36:06622 }
623
[email protected]57a777f72010-03-31 01:09:42624 LOG(INFO) << "Sending EXTENSION_LOADED";
625
[email protected]62d30f42009-10-01 22:36:06626 NotificationService::current()->Notify(
627 NotificationType::EXTENSION_LOADED,
[email protected]24e7a9d2009-11-04 11:11:34628 Source<Profile>(profile_),
[email protected]62d30f42009-10-01 22:36:06629 Details<Extension>(extension));
630}
631
632void ExtensionsService::NotifyExtensionUnloaded(Extension* extension) {
633 LOG(INFO) << "Sending EXTENSION_UNLOADED";
634
635 NotificationService::current()->Notify(
636 NotificationType::EXTENSION_UNLOADED,
[email protected]24e7a9d2009-11-04 11:11:34637 Source<Profile>(profile_),
[email protected]62d30f42009-10-01 22:36:06638 Details<Extension>(extension));
639
[email protected]57a777f72010-03-31 01:09:42640 if (profile_) {
641 profile_->UnregisterExtensionWithRequestContexts(extension);
642
643 // Check if this permission required unlimited storage quota, reset its
644 // in-memory quota.
645 if (extension->HasApiPermission(Extension::kUnlimitedStoragePermission)) {
646 string16 origin_identifier =
647 webkit_database::DatabaseUtil::GetOriginIdentifier(extension->url());
[email protected]95d29192009-10-30 01:49:06648 ChromeThread::PostTask(
[email protected]57a777f72010-03-31 01:09:42649 ChromeThread::FILE, FROM_HERE,
[email protected]be180c802009-10-23 06:33:31650 NewRunnableMethod(
[email protected]57a777f72010-03-31 01:09:42651 profile_->GetDatabaseTracker(),
652 &webkit_database::DatabaseTracker::ResetOriginQuotaInMemory,
653 origin_identifier));
[email protected]62d30f42009-10-01 22:36:06654 }
655 }
656}
657
[email protected]6b75ec32009-08-14 06:37:18658void ExtensionsService::UpdateExtensionBlacklist(
659 const std::vector<std::string>& blacklist) {
660 // Use this set to indicate if an extension in the blacklist has been used.
661 std::set<std::string> blacklist_set;
662 for (unsigned int i = 0; i < blacklist.size(); ++i) {
663 if (Extension::IdIsValid(blacklist[i])) {
664 blacklist_set.insert(blacklist[i]);
665 }
666 }
667 extension_prefs_->UpdateBlacklist(blacklist_set);
668 std::vector<std::string> to_be_removed;
669 // Loop current extensions, unload installed extensions.
670 for (ExtensionList::const_iterator iter = extensions_.begin();
671 iter != extensions_.end(); ++iter) {
672 Extension* extension = (*iter);
673 if (blacklist_set.find(extension->id()) != blacklist_set.end()) {
674 to_be_removed.push_back(extension->id());
675 }
676 }
677
678 // UnloadExtension will change the extensions_ list. So, we should
679 // call it outside the iterator loop.
680 for (unsigned int i = 0; i < to_be_removed.size(); ++i) {
681 UnloadExtension(to_be_removed[i]);
682 }
683}
684
[email protected]cb0ce1e022010-03-10 19:54:41685bool ExtensionsService::IsIncognitoEnabled(const Extension* extension) {
686 // If this is a component extension we always allow it to work in incognito
687 // mode.
688 if (extension->location() == Extension::COMPONENT)
689 return true;
690
691 // Check the prefs.
692 return extension_prefs_->IsIncognitoEnabled(extension->id());
[email protected]db7331a2010-02-25 22:10:50693}
[email protected]55a35692010-02-11 23:25:21694
[email protected]cb0ce1e022010-03-10 19:54:41695void ExtensionsService::SetIsIncognitoEnabled(Extension* extension,
[email protected]db7331a2010-02-25 22:10:50696 bool enabled) {
[email protected]cb0ce1e022010-03-10 19:54:41697 extension_prefs_->SetIsIncognitoEnabled(extension->id(), enabled);
[email protected]c1499f3d2010-03-05 00:33:24698
699 // Broadcast unloaded and loaded events to update browser state.
700 NotifyExtensionUnloaded(extension);
701 NotifyExtensionLoaded(extension);
[email protected]55a35692010-02-11 23:25:21702}
703
[email protected]05c82182010-06-24 17:49:08704bool ExtensionsService::AllowFileAccess(const Extension* extension) {
705 return (CommandLine::ForCurrentProcess()->HasSwitch(
[email protected]334e04a2010-06-24 23:34:44706 switches::kDisableExtensionsFileAccessCheck) ||
[email protected]05c82182010-06-24 17:49:08707 extension_prefs_->AllowFileAccess(extension->id()));
708}
709
710void ExtensionsService::SetAllowFileAccess(Extension* extension, bool allow) {
711 extension_prefs_->SetAllowFileAccess(extension->id(), allow);
712 NotificationService::current()->Notify(
713 NotificationType::EXTENSION_USER_SCRIPTS_UPDATED,
714 Source<Profile>(profile_),
715 Details<Extension>(extension));
716}
717
718bool ExtensionsService::CanExecuteScriptOnHost(Extension* extension,
719 const GURL& url,
720 std::string* error) const {
721 // No extensions are allowed to execute script on the gallery because that
722 // would allow extensions to manipulate their own install pages.
723 if (url.host() == GURL(Extension::ChromeStoreURL()).host()) {
724 if (error)
725 *error = errors::kCannotScriptGallery;
726 return false;
727 }
728
729 if (extension->HasHostPermission(url))
730 return true;
731
732 if (error) {
733 *error = ExtensionErrorUtils::FormatErrorMessage(errors::kCannotAccessPage,
734 url.spec());
735 }
736
737 return false;
738}
739
[email protected]93fd78f42009-07-10 16:43:17740void ExtensionsService::CheckForExternalUpdates() {
[email protected]9f1087e2009-06-15 17:29:32741 // This installs or updates externally provided extensions.
[email protected]7577a5c52009-07-30 06:21:58742 // TODO(aa): Why pass this list into the provider, why not just filter it
743 // later?
[email protected]9f1087e2009-06-15 17:29:32744 std::set<std::string> killed_extensions;
[email protected]e72e8eb82009-06-18 17:21:51745 extension_prefs_->GetKilledExtensionIds(&killed_extensions);
[email protected]95d29192009-10-30 01:49:06746 ChromeThread::PostTask(
747 ChromeThread::FILE, FROM_HERE,
748 NewRunnableMethod(
749 backend_.get(), &ExtensionsServiceBackend::CheckForExternalUpdates,
750 killed_extensions, scoped_refptr<ExtensionsService>(this)));
[email protected]9f1087e2009-06-15 17:29:32751}
752
753void ExtensionsService::UnloadExtension(const std::string& extension_id) {
[email protected]27e469a2010-01-11 20:35:09754 // Make sure the extension gets deleted after we return from this function.
[email protected]0c6da502009-08-14 22:32:39755 scoped_ptr<Extension> extension(
756 GetExtensionByIdInternal(extension_id, true, true));
[email protected]631cf822009-05-15 07:01:25757
[email protected]894bb502009-05-21 22:39:57758 // Callers should not send us nonexistant extensions.
[email protected]0c6da502009-08-14 22:32:39759 CHECK(extension.get());
760
[email protected]1eb175082010-02-10 09:26:16761 // Keep information about the extension so that we can reload it later
762 // even if it's not permanently installed.
763 unloaded_extension_paths_[extension->id()] = extension->path();
764
[email protected]86c008e82009-08-28 20:26:05765 ExtensionDOMUI::UnregisterChromeURLOverrides(profile_,
766 extension->GetChromeURLOverrides());
767
[email protected]0c6da502009-08-14 22:32:39768 ExtensionList::iterator iter = std::find(disabled_extensions_.begin(),
769 disabled_extensions_.end(),
770 extension.get());
771 if (iter != disabled_extensions_.end()) {
[email protected]0c6da502009-08-14 22:32:39772 disabled_extensions_.erase(iter);
[email protected]866930682009-08-18 22:53:47773 NotificationService::current()->Notify(
774 NotificationType::EXTENSION_UNLOADED_DISABLED,
[email protected]24e7a9d2009-11-04 11:11:34775 Source<Profile>(profile_),
[email protected]866930682009-08-18 22:53:47776 Details<Extension>(extension.get()));
[email protected]0c6da502009-08-14 22:32:39777 return;
778 }
779
780 iter = std::find(extensions_.begin(), extensions_.end(), extension.get());
[email protected]894bb502009-05-21 22:39:57781
[email protected]631cf822009-05-15 07:01:25782 // Remove the extension from our list.
783 extensions_.erase(iter);
784
[email protected]62d30f42009-10-01 22:36:06785 NotifyExtensionUnloaded(extension.get());
[email protected]aab98a52009-12-02 03:22:35786 UpdateActiveExtensionsInCrashReporter();
[email protected]631cf822009-05-15 07:01:25787}
788
[email protected]9f1087e2009-06-15 17:29:32789void ExtensionsService::UnloadAllExtensions() {
[email protected]cd500f72010-06-25 23:44:32790 STLDeleteContainerPointers(extensions_.begin(), extensions_.end());
[email protected]9f1087e2009-06-15 17:29:32791 extensions_.clear();
[email protected]c6e4a3412009-06-24 15:45:29792
[email protected]cd500f72010-06-25 23:44:32793 STLDeleteContainerPointers(disabled_extensions_.begin(),
794 disabled_extensions_.end());
795 disabled_extensions_.clear();
796
[email protected]c6e4a3412009-06-24 15:45:29797 // TODO(erikkay) should there be a notification for this? We can't use
798 // EXTENSION_UNLOADED since that implies that the extension has been disabled
799 // or uninstalled, and UnloadAll is just part of shutdown.
[email protected]9f1087e2009-06-15 17:29:32800}
801
802void ExtensionsService::ReloadExtensions() {
803 UnloadAllExtensions();
804 LoadAllExtensions();
805}
806
807void ExtensionsService::GarbageCollectExtensions() {
[email protected]ba399672010-04-06 15:42:39808 if (extension_prefs_->pref_service()->read_only())
809 return;
810
[email protected]ca3dbf52010-05-19 22:27:06811 scoped_ptr<ExtensionPrefs::ExtensionsInfo> info(
812 extension_prefs_->GetInstalledExtensionsInfo());
813
814 std::map<std::string, FilePath> extension_paths;
815 for (size_t i = 0; i < info->size(); ++i)
816 extension_paths[info->at(i)->extension_id] = info->at(i)->extension_path;
817
[email protected]95d29192009-10-30 01:49:06818 ChromeThread::PostTask(
819 ChromeThread::FILE, FROM_HERE,
820 NewRunnableFunction(
821 &extension_file_util::GarbageCollectExtensions, install_directory_,
[email protected]ca3dbf52010-05-19 22:27:06822 extension_paths));
[email protected]3cf4f0992009-02-03 23:00:30823}
824
[email protected]e72e8eb82009-06-18 17:21:51825void ExtensionsService::OnLoadedInstalledExtensions() {
[email protected]e81dba32009-06-19 20:19:13826 ready_ = true;
[email protected]93fd78f42009-07-10 16:43:17827 if (updater_.get()) {
828 updater_->Start();
829 }
[email protected]e72e8eb82009-06-18 17:21:51830 NotificationService::current()->Notify(
831 NotificationType::EXTENSIONS_READY,
[email protected]24e7a9d2009-11-04 11:11:34832 Source<Profile>(profile_),
[email protected]e72e8eb82009-06-18 17:21:51833 NotificationService::NoDetails());
834}
835
[email protected]6d2e60bd2010-06-03 22:37:39836void ExtensionsService::OnExtensionLoaded(Extension* extension,
[email protected]2a409532009-08-28 19:39:44837 bool allow_privilege_increase) {
[email protected]ae09ca62009-08-21 19:46:46838 // Ensure extension is deleted unless we transfer ownership.
839 scoped_ptr<Extension> scoped_extension(extension);
[email protected]9f1087e2009-06-15 17:29:32840
[email protected]1eb175082010-02-10 09:26:16841 // The extension is now loaded, remove its data from unloaded extension map.
842 unloaded_extension_paths_.erase(extension->id());
843
[email protected]ceefd3d2010-03-12 09:10:29844 // TODO(aa): Need to re-evaluate this branch. Does this still make sense now
845 // that extensions are enabled by default?
[email protected]ae09ca62009-08-21 19:46:46846 if (extensions_enabled() ||
[email protected]3ba0fd32010-06-19 05:39:10847 extension->is_theme() ||
[email protected]ae09ca62009-08-21 19:46:46848 extension->location() == Extension::LOAD ||
849 Extension::IsExternalLocation(extension->location())) {
850 Extension* old = GetExtensionByIdInternal(extension->id(), true, true);
851 if (old) {
[email protected]ca3dbf52010-05-19 22:27:06852 // CrxInstaller should have guaranteed that we aren't downgrading.
853 CHECK(extension->version()->CompareTo(*(old->version())) >= 0);
[email protected]0c6da502009-08-14 22:32:39854
[email protected]ca3dbf52010-05-19 22:27:06855 bool allow_silent_upgrade =
856 allow_privilege_increase || !Extension::IsPrivilegeIncrease(
857 old, extension);
[email protected]1e8c93f2010-02-08 22:58:31858
[email protected]ca3dbf52010-05-19 22:27:06859 // Extensions get upgraded if silent upgrades are allowed, otherwise
860 // they get disabled.
861 if (allow_silent_upgrade) {
862 old->set_being_upgraded(true);
863 extension->set_being_upgraded(true);
864 }
[email protected]0c6da502009-08-14 22:32:39865
[email protected]ca3dbf52010-05-19 22:27:06866 // To upgrade an extension in place, unload the old one and
867 // then load the new one.
868 UnloadExtension(old->id());
869 old = NULL;
870
871 if (!allow_silent_upgrade) {
872 // Extension has changed permissions significantly. Disable it. We
873 // send a notification below.
874 extension_prefs_->SetExtensionState(extension, Extension::DISABLED);
875 extension_prefs_->SetDidExtensionEscalatePermissions(extension, true);
[email protected]0c6da502009-08-14 22:32:39876 }
[email protected]ba74f352009-06-11 18:54:45877 }
[email protected]86a274072009-06-11 02:06:45878
[email protected]ae09ca62009-08-21 19:46:46879 switch (extension_prefs_->GetExtensionState(extension->id())) {
880 case Extension::ENABLED:
881 extensions_.push_back(scoped_extension.release());
882
[email protected]62d30f42009-10-01 22:36:06883 NotifyExtensionLoaded(extension);
[email protected]ae09ca62009-08-21 19:46:46884
[email protected]e8c729a2010-03-09 19:55:19885 ExtensionDOMUI::RegisterChromeURLOverrides(profile_,
886 extension->GetChromeURLOverrides());
[email protected]ae09ca62009-08-21 19:46:46887 break;
888 case Extension::DISABLED:
[email protected]6d27a7b2009-12-18 23:25:45889 disabled_extensions_.push_back(scoped_extension.release());
[email protected]d11c8e92009-10-20 23:26:40890 NotificationService::current()->Notify(
891 NotificationType::EXTENSION_UPDATE_DISABLED,
[email protected]24e7a9d2009-11-04 11:11:34892 Source<Profile>(profile_),
[email protected]d11c8e92009-10-20 23:26:40893 Details<Extension>(extension));
[email protected]ae09ca62009-08-21 19:46:46894 break;
895 default:
[email protected]d11c8e92009-10-20 23:26:40896 NOTREACHED();
[email protected]ae09ca62009-08-21 19:46:46897 break;
[email protected]811f3432009-07-25 19:38:21898 }
[email protected]e72e8eb82009-06-18 17:21:51899 }
[email protected]aab98a52009-12-02 03:22:35900
[email protected]1e8c93f2010-02-08 22:58:31901 extension->set_being_upgraded(false);
902
[email protected]aab98a52009-12-02 03:22:35903 UpdateActiveExtensionsInCrashReporter();
904}
905
906void ExtensionsService::UpdateActiveExtensionsInCrashReporter() {
[email protected]c8865962009-12-16 07:47:39907 std::set<std::string> extension_ids;
[email protected]aab98a52009-12-02 03:22:35908 for (size_t i = 0; i < extensions_.size(); ++i) {
[email protected]3ba0fd32010-06-19 05:39:10909 if (!extensions_[i]->is_theme())
[email protected]c8865962009-12-16 07:47:39910 extension_ids.insert(extensions_[i]->id());
[email protected]aab98a52009-12-02 03:22:35911 }
912
913 child_process_logging::SetActiveExtensions(extension_ids);
[email protected]6014d672008-12-05 00:38:25914}
915
[email protected]2a409532009-08-28 19:39:44916void ExtensionsService::OnExtensionInstalled(Extension* extension,
917 bool allow_privilege_increase) {
[email protected]4416c5a2010-06-26 01:28:57918 // Ensure extension is deleted unless we transfer ownership.
919 scoped_ptr<Extension> scoped_extension(extension);
920 Extension::State initial_state = Extension::DISABLED;
921 bool initial_enable_incognito = false;
[email protected]aa142702010-03-26 01:26:33922 PendingExtensionMap::iterator it =
923 pending_extensions_.find(extension->id());
[email protected]4416c5a2010-06-26 01:28:57924 if (it != pending_extensions_.end()) {
925 // Set initial state from pending extension data.
926 if (it->second.is_theme != extension->is_theme()) {
927 LOG(WARNING)
928 << "Not installing pending extension " << extension->id()
929 << " with is_theme = " << extension->is_theme()
930 << "; expected is_theme = " << it->second.is_theme;
931 // Delete the extension directory since we're not going to
932 // load it.
933 ChromeThread::PostTask(
934 ChromeThread::FILE, FROM_HERE,
935 NewRunnableFunction(&DeleteFileHelper, extension->path(), true));
936 return;
937 }
938 if (it->second.is_theme) {
939 DCHECK(it->second.enable_on_install);
940 initial_state = Extension::ENABLED;
941 DCHECK(!it->second.enable_incognito_on_install);
942 initial_enable_incognito = false;
943 } else {
944 initial_state =
945 it->second.enable_on_install ?
946 Extension::ENABLED : Extension::DISABLED;
947 initial_enable_incognito =
948 it->second.enable_incognito_on_install;
949 }
950
951 pending_extensions_.erase(it);
952 } else {
953 // Make sure we don't enable a disabled extension.
954 Extension::State existing_state =
955 extension_prefs_->GetExtensionState(extension->id());
956 initial_state =
957 (existing_state == Extension::DISABLED) ?
958 Extension::DISABLED : Extension::ENABLED;
959 initial_enable_incognito = false;
[email protected]aa142702010-03-26 01:26:33960 }
961
[email protected]4416c5a2010-06-26 01:28:57962 extension_prefs_->OnExtensionInstalled(
963 extension, initial_state, initial_enable_incognito);
[email protected]25b34332009-06-05 21:53:19964
[email protected]4a190632009-05-09 01:07:42965 // If the extension is a theme, tell the profile (and therefore ThemeProvider)
966 // to apply it.
[email protected]3ba0fd32010-06-19 05:39:10967 if (extension->is_theme()) {
[email protected]9ceb07342009-07-26 04:09:23968 NotificationService::current()->Notify(
969 NotificationType::THEME_INSTALLED,
[email protected]24e7a9d2009-11-04 11:11:34970 Source<Profile>(profile_),
[email protected]9ceb07342009-07-26 04:09:23971 Details<Extension>(extension));
[email protected]9197f3b2009-06-02 00:49:27972 } else {
973 NotificationService::current()->Notify(
974 NotificationType::EXTENSION_INSTALLED,
[email protected]24e7a9d2009-11-04 11:11:34975 Source<Profile>(profile_),
[email protected]9197f3b2009-06-02 00:49:27976 Details<Extension>(extension));
[email protected]4a190632009-05-09 01:07:42977 }
[email protected]7577a5c52009-07-30 06:21:58978
[email protected]6d2e60bd2010-06-03 22:37:39979 if (profile_->GetTemplateURLModel())
[email protected]56ad3792010-05-28 17:45:33980 profile_->GetTemplateURLModel()->RegisterExtensionKeyword(extension);
[email protected]4416c5a2010-06-26 01:28:57981
982 // Transfer ownership of |extension| to OnExtensionLoaded.
983 OnExtensionLoaded(scoped_extension.release(), allow_privilege_increase);
[email protected]4a190632009-05-09 01:07:42984}
985
[email protected]0c6da502009-08-14 22:32:39986Extension* ExtensionsService::GetExtensionByIdInternal(const std::string& id,
987 bool include_enabled,
988 bool include_disabled) {
[email protected]e957fe52009-06-23 16:51:05989 std::string lowercase_id = StringToLowerASCII(id);
[email protected]0c6da502009-08-14 22:32:39990 if (include_enabled) {
991 for (ExtensionList::const_iterator iter = extensions_.begin();
992 iter != extensions_.end(); ++iter) {
993 if ((*iter)->id() == lowercase_id)
994 return *iter;
995 }
996 }
997 if (include_disabled) {
998 for (ExtensionList::const_iterator iter = disabled_extensions_.begin();
999 iter != disabled_extensions_.end(); ++iter) {
1000 if ((*iter)->id() == lowercase_id)
1001 return *iter;
1002 }
[email protected]ce5c4502009-05-06 16:46:111003 }
1004 return NULL;
1005}
1006
[email protected]9f1087e2009-06-15 17:29:321007Extension* ExtensionsService::GetExtensionByURL(const GURL& url) {
[email protected]a888b29e62010-04-01 13:38:571008 return url.scheme() != chrome::kExtensionScheme ? NULL :
1009 GetExtensionById(url.host(), false);
1010}
1011
1012Extension* ExtensionsService::GetExtensionByWebExtent(const GURL& url) {
1013 for (size_t i = 0; i < extensions_.size(); ++i) {
1014 if (extensions_[i]->web_extent().ContainsURL(url))
1015 return extensions_[i];
1016 }
1017 return NULL;
[email protected]9f1087e2009-06-15 17:29:321018}
1019
[email protected]6d2e60bd2010-06-03 22:37:391020Extension* ExtensionsService::GetExtensionByOverlappingWebExtent(
[email protected]9f72aa02010-06-25 10:01:051021 const ExtensionExtent& extent) {
1022 // TODO(aa): Make this work for the new extents. http://crbug.com/47445.
[email protected]6d2e60bd2010-06-03 22:37:391023 return NULL;
1024}
1025
[email protected]a1257b12009-06-12 02:51:341026void ExtensionsService::ClearProvidersForTesting() {
[email protected]95d29192009-10-30 01:49:061027 ChromeThread::PostTask(
1028 ChromeThread::FILE, FROM_HERE,
1029 NewRunnableMethod(
1030 backend_.get(), &ExtensionsServiceBackend::ClearProvidersForTesting));
[email protected]a1257b12009-06-12 02:51:341031}
1032
1033void ExtensionsService::SetProviderForTesting(
1034 Extension::Location location, ExternalExtensionProvider* test_provider) {
[email protected]95d29192009-10-30 01:49:061035 ChromeThread::PostTask(
1036 ChromeThread::FILE, FROM_HERE,
1037 NewRunnableMethod(
1038 backend_.get(), &ExtensionsServiceBackend::SetProviderForTesting,
1039 location, test_provider));
[email protected]a1257b12009-06-12 02:51:341040}
1041
[email protected]7577a5c52009-07-30 06:21:581042void ExtensionsService::OnExternalExtensionFound(const std::string& id,
1043 const std::string& version,
1044 const FilePath& path,
1045 Extension::Location location) {
1046 // Before even bothering to unpack, check and see if we already have this
[email protected]4c967932009-07-31 01:15:491047 // version. This is important because these extensions are going to get
[email protected]7577a5c52009-07-30 06:21:581048 // installed on every startup.
[email protected]61b411612009-11-10 23:17:411049 Extension* existing = GetExtensionById(id, true);
[email protected]a3a63ff82009-08-04 06:44:111050 scoped_ptr<Version> other(Version::GetVersionFromString(version));
[email protected]7577a5c52009-07-30 06:21:581051 if (existing) {
[email protected]a3a63ff82009-08-04 06:44:111052 switch (existing->version()->CompareTo(*other)) {
[email protected]7577a5c52009-07-30 06:21:581053 case -1: // existing version is older, we should upgrade
1054 break;
1055 case 0: // existing version is same, do nothing
1056 return;
1057 case 1: // existing version is newer, uh-oh
1058 LOG(WARNING) << "Found external version of extension " << id
1059 << "that is older than current version. Current version "
1060 << "is: " << existing->VersionString() << ". New version "
1061 << "is: " << version << ". Keeping current version.";
1062 return;
1063 }
1064 }
1065
[email protected]6dfbbf82010-03-12 23:09:161066 scoped_refptr<CrxInstaller> installer(
1067 new CrxInstaller(install_directory_,
1068 this, // frontend
1069 NULL)); // no client (silent install)
1070 installer->set_install_source(location);
1071 installer->set_expected_id(id);
1072 installer->set_allow_privilege_increase(true);
1073 installer->InstallCrx(path);
[email protected]7577a5c52009-07-30 06:21:581074}
1075
[email protected]d11c8e92009-10-20 23:26:401076void ExtensionsService::ReportExtensionLoadError(
1077 const FilePath& extension_path,
1078 const std::string &error,
1079 NotificationType type,
1080 bool be_noisy) {
1081 NotificationService* service = NotificationService::current();
1082 service->Notify(type,
[email protected]24e7a9d2009-11-04 11:11:341083 Source<Profile>(profile_),
[email protected]d11c8e92009-10-20 23:26:401084 Details<const std::string>(&error));
1085
1086 // TODO(port): note that this isn't guaranteed to work properly on Linux.
[email protected]99efb7b12009-12-18 02:39:161087 std::string path_str = WideToUTF8(extension_path.ToWStringHack());
[email protected]d11c8e92009-10-20 23:26:401088 std::string message = StringPrintf("Could not load extension from '%s'. %s",
1089 path_str.c_str(), error.c_str());
1090 ExtensionErrorReporter::GetInstance()->ReportError(message, be_noisy);
1091}
1092
[email protected]4814b512009-11-07 00:12:291093void ExtensionsService::Observe(NotificationType type,
1094 const NotificationSource& source,
1095 const NotificationDetails& details) {
1096 switch (type.value) {
1097 case NotificationType::EXTENSION_HOST_DID_STOP_LOADING: {
1098 ExtensionHost* host = Details<ExtensionHost>(details).ptr();
1099 OrphanedDevTools::iterator iter =
1100 orphaned_dev_tools_.find(host->extension()->id());
1101 if (iter == orphaned_dev_tools_.end())
1102 return;
1103
1104 DevToolsManager::GetInstance()->AttachClientHost(
1105 iter->second, host->render_view_host());
1106 orphaned_dev_tools_.erase(iter);
1107 break;
1108 }
1109
[email protected]a4ed6282009-12-14 20:51:161110 case NotificationType::EXTENSION_PROCESS_TERMINATED: {
[email protected]31f77262009-12-02 20:48:531111 DCHECK_EQ(profile_, Source<Profile>(source).ptr());
[email protected]a4ed6282009-12-14 20:51:161112
[email protected]31f77262009-12-02 20:48:531113 // Unload the entire extension. We want it to be in a consistent state:
1114 // either fully working or not loaded at all, but never half-crashed.
[email protected]597cceb2010-03-22 16:27:011115 UnloadExtension(Details<ExtensionHost>(details).ptr()->extension()->id());
[email protected]31f77262009-12-02 20:48:531116 break;
1117 }
1118
[email protected]4814b512009-11-07 00:12:291119 default:
1120 NOTREACHED() << "Unexpected notification type.";
1121 }
1122}
1123
1124
[email protected]6014d672008-12-05 00:38:251125// ExtensionsServicesBackend
1126
[email protected]894bb502009-05-21 22:39:571127ExtensionsServiceBackend::ExtensionsServiceBackend(
[email protected]95d29192009-10-30 01:49:061128 const FilePath& install_directory)
[email protected]0c7bc4b2009-05-30 01:47:081129 : frontend_(NULL),
1130 install_directory_(install_directory),
[email protected]95d29192009-10-30 01:49:061131 alert_on_error_(false) {
[email protected]7577a5c52009-07-30 06:21:581132 // TODO(aa): This ends up doing blocking IO on the UI thread because it reads
1133 // pref data in the ctor and that is called on the UI thread. Would be better
1134 // to re-read data each time we list external extensions, anyway.
[email protected]a1257b12009-06-12 02:51:341135 external_extension_providers_[Extension::EXTERNAL_PREF] =
[email protected]da50530a2009-06-15 17:43:011136 linked_ptr<ExternalExtensionProvider>(
[email protected]27b985d2009-06-25 17:53:151137 new ExternalPrefExtensionProvider());
[email protected]a1257b12009-06-12 02:51:341138#if defined(OS_WIN)
1139 external_extension_providers_[Extension::EXTERNAL_REGISTRY] =
[email protected]da50530a2009-06-15 17:43:011140 linked_ptr<ExternalExtensionProvider>(
1141 new ExternalRegistryExtensionProvider());
[email protected]a1257b12009-06-12 02:51:341142#endif
1143}
1144
1145ExtensionsServiceBackend::~ExtensionsServiceBackend() {
[email protected]894bb502009-05-21 22:39:571146}
1147
[email protected]b0beaa662009-02-26 00:04:151148void ExtensionsServiceBackend::LoadSingleExtension(
[email protected]894bb502009-05-21 22:39:571149 const FilePath& path_in, scoped_refptr<ExtensionsService> frontend) {
[email protected]b0beaa662009-02-26 00:04:151150 frontend_ = frontend;
1151
1152 // Explicit UI loads are always noisy.
1153 alert_on_error_ = true;
1154
[email protected]cc5da332009-03-04 08:02:511155 FilePath extension_path = path_in;
[email protected]f36fa4fb2009-06-19 18:23:501156 file_util::AbsolutePath(&extension_path);
[email protected]bf24d2c2009-02-24 23:07:451157
1158 LOG(INFO) << "Loading single extension from " <<
[email protected]99efb7b12009-12-18 02:39:161159 extension_path.BaseName().value();
[email protected]bf24d2c2009-02-24 23:07:451160
[email protected]ab6f2b22009-07-28 23:28:371161 std::string error;
1162 Extension* extension = extension_file_util::LoadExtension(
1163 extension_path,
1164 false, // Don't require id
1165 &error);
1166
1167 if (!extension) {
1168 ReportExtensionLoadError(extension_path, error);
1169 return;
[email protected]0877fd92009-02-03 16:34:061170 }
[email protected]ab6f2b22009-07-28 23:28:371171
1172 extension->set_location(Extension::LOAD);
[email protected]e8c729a2010-03-09 19:55:191173
1174 // Report this as an installed extension so that it gets remembered in the
1175 // prefs.
1176 ChromeThread::PostTask(
1177 ChromeThread::UI, FROM_HERE,
1178 NewRunnableMethod(frontend_, &ExtensionsService::OnExtensionInstalled,
1179 extension, true));
[email protected]0877fd92009-02-03 16:34:061180}
1181
[email protected]6014d672008-12-05 00:38:251182void ExtensionsServiceBackend::ReportExtensionLoadError(
[email protected]cc5da332009-03-04 08:02:511183 const FilePath& extension_path, const std::string &error) {
[email protected]95d29192009-10-30 01:49:061184 ChromeThread::PostTask(
1185 ChromeThread::UI, FROM_HERE,
1186 NewRunnableMethod(
1187 frontend_,
[email protected]d11c8e92009-10-20 23:26:401188 &ExtensionsService::ReportExtensionLoadError, extension_path,
1189 error, NotificationType::EXTENSION_INSTALL_ERROR, alert_on_error_));
[email protected]6014d672008-12-05 00:38:251190}
1191
[email protected]a1257b12009-06-12 02:51:341192bool ExtensionsServiceBackend::LookupExternalExtension(
1193 const std::string& id, Version** version, Extension::Location* location) {
1194 scoped_ptr<Version> extension_version;
1195 for (ProviderMap::const_iterator i = external_extension_providers_.begin();
1196 i != external_extension_providers_.end(); ++i) {
[email protected]da50530a2009-06-15 17:43:011197 const ExternalExtensionProvider* provider = i->second.get();
[email protected]a1257b12009-06-12 02:51:341198 extension_version.reset(provider->RegisteredVersion(id, location));
1199 if (extension_version.get()) {
1200 if (version)
1201 *version = extension_version.release();
1202 return true;
1203 }
1204 }
1205 return false;
1206}
1207
[email protected]b0beaa662009-02-26 00:04:151208// Some extensions will autoupdate themselves externally from Chrome. These
1209// are typically part of some larger client application package. To support
[email protected]25b34332009-06-05 21:53:191210// these, the extension will register its location in the the preferences file
1211// (and also, on Windows, in the registry) and this code will periodically
[email protected]b0beaa662009-02-26 00:04:151212// check that location for a .crx file, which it will then install locally if
1213// a new version is available.
1214void ExtensionsServiceBackend::CheckForExternalUpdates(
[email protected]894bb502009-05-21 22:39:571215 std::set<std::string> ids_to_ignore,
1216 scoped_refptr<ExtensionsService> frontend) {
[email protected]b0beaa662009-02-26 00:04:151217 // Note that this installation is intentionally silent (since it didn't
1218 // go through the front-end). Extensions that are registered in this
1219 // way are effectively considered 'pre-bundled', and so implicitly
1220 // trusted. In general, if something has HKLM or filesystem access,
1221 // they could install an extension manually themselves anyway.
1222 alert_on_error_ = false;
1223 frontend_ = frontend;
[email protected]b0beaa662009-02-26 00:04:151224
[email protected]a1257b12009-06-12 02:51:341225 // Ask each external extension provider to give us a call back for each
1226 // extension they know about. See OnExternalExtensionFound.
1227 for (ProviderMap::const_iterator i = external_extension_providers_.begin();
1228 i != external_extension_providers_.end(); ++i) {
[email protected]da50530a2009-06-15 17:43:011229 ExternalExtensionProvider* provider = i->second.get();
[email protected]a1257b12009-06-12 02:51:341230 provider->VisitRegisteredExtension(this, ids_to_ignore);
[email protected]25b34332009-06-05 21:53:191231 }
[email protected]b0beaa662009-02-26 00:04:151232}
1233
[email protected]ae09ca62009-08-21 19:46:461234void ExtensionsServiceBackend::CheckExternalUninstall(
1235 scoped_refptr<ExtensionsService> frontend, const std::string& id,
1236 Extension::Location location) {
[email protected]a1257b12009-06-12 02:51:341237 // Check if the providers know about this extension.
1238 ProviderMap::const_iterator i = external_extension_providers_.find(location);
[email protected]ae09ca62009-08-21 19:46:461239 if (i == external_extension_providers_.end()) {
1240 NOTREACHED() << "CheckExternalUninstall called for non-external extension "
1241 << location;
1242 return;
[email protected]b0beaa662009-02-26 00:04:151243 }
[email protected]25b34332009-06-05 21:53:191244
[email protected]ae09ca62009-08-21 19:46:461245 scoped_ptr<Version> version;
1246 version.reset(i->second->RegisteredVersion(id, NULL));
1247 if (version.get())
1248 return; // Yup, known extension, don't uninstall.
1249
1250 // This is an external extension that we don't have registered. Uninstall.
[email protected]95d29192009-10-30 01:49:061251 ChromeThread::PostTask(
1252 ChromeThread::UI, FROM_HERE,
1253 NewRunnableMethod(
1254 frontend.get(), &ExtensionsService::UninstallExtension, id, true));
[email protected]b0beaa662009-02-26 00:04:151255}
1256
[email protected]a1257b12009-06-12 02:51:341257void ExtensionsServiceBackend::ClearProvidersForTesting() {
1258 external_extension_providers_.clear();
1259}
1260
1261void ExtensionsServiceBackend::SetProviderForTesting(
1262 Extension::Location location,
1263 ExternalExtensionProvider* test_provider) {
1264 DCHECK(test_provider);
[email protected]da50530a2009-06-15 17:43:011265 external_extension_providers_[location] =
1266 linked_ptr<ExternalExtensionProvider>(test_provider);
[email protected]a1257b12009-06-12 02:51:341267}
1268
1269void ExtensionsServiceBackend::OnExternalExtensionFound(
[email protected]7577a5c52009-07-30 06:21:581270 const std::string& id, const Version* version, const FilePath& path,
1271 Extension::Location location) {
[email protected]95d29192009-10-30 01:49:061272 ChromeThread::PostTask(
1273 ChromeThread::UI, FROM_HERE,
1274 NewRunnableMethod(
1275 frontend_, &ExtensionsService::OnExternalExtensionFound, id,
1276 version->GetString(), path, location));
[email protected]cc655912009-01-29 23:19:191277}
[email protected]c6d474f82009-12-16 21:11:061278
[email protected]2111b1a2010-03-12 18:12:441279void ExtensionsServiceBackend::ReloadExtensionManifests(
[email protected]c6d474f82009-12-16 21:11:061280 ExtensionPrefs::ExtensionsInfo* extensions_to_reload,
1281 base::TimeTicks start_time,
1282 scoped_refptr<ExtensionsService> frontend) {
1283 frontend_ = frontend;
1284
1285 for (size_t i = 0; i < extensions_to_reload->size(); ++i) {
1286 ExtensionInfo* info = extensions_to_reload->at(i).get();
[email protected]2111b1a2010-03-12 18:12:441287 if (!ShouldReloadExtensionManifest(*info))
[email protected]c6d474f82009-12-16 21:11:061288 continue;
1289
1290 // We need to reload original manifest in order to localize properly.
1291 std::string error;
1292 scoped_ptr<Extension> extension(extension_file_util::LoadExtension(
1293 info->extension_path, false, &error));
1294
1295 if (extension.get())
1296 extensions_to_reload->at(i)->extension_manifest.reset(
1297 static_cast<DictionaryValue*>(
1298 extension->manifest_value()->DeepCopy()));
1299 }
1300
1301 // Finish installing on UI thread.
1302 ChromeThread::PostTask(
1303 ChromeThread::UI, FROM_HERE,
1304 NewRunnableMethod(
1305 frontend_,
1306 &ExtensionsService::ContinueLoadAllExtensions,
1307 extensions_to_reload,
1308 start_time,
1309 true));
1310}