blob: 98681de771ffa917dfc48d22c9a3c741b271ff2a [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]654512b2010-09-01 02:09:427#include <algorithm>
8
[email protected]24b538a2010-02-27 01:22:449#include "base/basictypes.h"
[email protected]e2eb43112009-05-29 21:19:5410#include "base/command_line.h"
[email protected]6014d672008-12-05 00:38:2511#include "base/file_util.h"
[email protected]835d7c82010-10-14 04:38:3812#include "base/metrics/histogram.h"
[email protected]cd500f72010-06-25 23:44:3213#include "base/stl_util-inl.h"
[email protected]24b538a2010-02-27 01:22:4414#include "base/string16.h"
[email protected]e83326f2010-07-31 17:29:2515#include "base/string_number_conversions.h"
[email protected]6014d672008-12-05 00:38:2516#include "base/string_util.h"
[email protected]18d4b6c2010-09-21 03:21:0417#include "base/stringprintf.h"
[email protected]cc2c3432009-11-06 17:24:3618#include "base/time.h"
[email protected]ce7f62e32010-08-10 23:43:5919#include "base/utf_string_conversions.h"
[email protected]cc655912009-01-29 23:19:1920#include "base/values.h"
[email protected]aa142702010-03-26 01:26:3321#include "base/version.h"
[email protected]15730c42009-09-03 00:03:2022#include "chrome/browser/browser_process.h"
[email protected]ed7e6dd2010-10-12 02:02:4523#include "chrome/browser/browser_thread.h"
[email protected]4814b512009-11-07 00:12:2924#include "chrome/browser/debugger/devtools_manager.h"
[email protected]7577a5c52009-07-30 06:21:5825#include "chrome/browser/extensions/crx_installer.h"
[email protected]ec5b50d2010-10-09 16:35:1826#include "chrome/browser/extensions/default_apps.h"
[email protected]5cbe1e22010-01-30 01:18:5627#include "chrome/browser/extensions/extension_accessibility_api.h"
[email protected]840b0db2009-11-20 03:00:3828#include "chrome/browser/extensions/extension_bookmarks_module.h"
[email protected]b68d5ed2009-04-16 02:41:2829#include "chrome/browser/extensions/extension_browser_event_router.h"
[email protected]2c5e1e12010-06-10 13:14:4430#include "chrome/browser/extensions/extension_cookies_api.h"
[email protected]c10da4b02010-03-25 14:38:3231#include "chrome/browser/extensions/extension_data_deleter.h"
[email protected]86c008e82009-08-28 20:26:0532#include "chrome/browser/extensions/extension_dom_ui.h"
[email protected]14a000d2010-04-29 21:44:2433#include "chrome/browser/extensions/extension_error_reporter.h"
[email protected]de768a832009-10-30 05:25:0134#include "chrome/browser/extensions/extension_history_api.h"
[email protected]b1748b1d82009-11-30 20:32:5635#include "chrome/browser/extensions/extension_host.h"
[email protected]7596ce72010-08-30 05:10:4636#include "chrome/browser/extensions/extension_management_api.h"
[email protected]4814b512009-11-07 00:12:2937#include "chrome/browser/extensions/extension_process_manager.h"
[email protected]8a661f82010-10-19 21:47:1138#include "chrome/browser/extensions/extension_processes_api.h"
[email protected]93fd78f42009-07-10 16:43:1739#include "chrome/browser/extensions/extension_updater.h"
[email protected]784688a62010-09-13 07:06:5240#include "chrome/browser/extensions/extension_webnavigation_api.h"
[email protected]a1257b12009-06-12 02:51:3441#include "chrome/browser/extensions/external_extension_provider.h"
42#include "chrome/browser/extensions/external_pref_extension_provider.h"
[email protected]56ad3792010-05-28 17:45:3343#include "chrome/browser/net/chrome_url_request_context.h"
[email protected]37858e52010-08-26 00:22:0244#include "chrome/browser/prefs/pref_service.h"
[email protected]81e63782009-02-27 19:35:0945#include "chrome/browser/profile.h"
[email protected]56ad3792010-05-28 17:45:3346#include "chrome/browser/search_engines/template_url_model.h"
[email protected]2a3e22b12010-08-13 04:55:1747#include "chrome/browser/sync/glue/extension_sync_traits.h"
[email protected]11edd1e2010-07-21 00:14:5048#include "chrome/browser/sync/glue/extension_util.h"
[email protected]aab98a52009-12-02 03:22:3549#include "chrome/common/child_process_logging.h"
[email protected]e2eb43112009-05-29 21:19:5450#include "chrome/common/chrome_switches.h"
[email protected]5b1a0e22009-05-26 19:00:5851#include "chrome/common/extensions/extension.h"
[email protected]d7b36dc2009-10-29 21:47:4052#include "chrome/common/extensions/extension_constants.h"
[email protected]05c82182010-06-24 17:49:0853#include "chrome/common/extensions/extension_error_utils.h"
[email protected]7c927b62010-02-24 09:54:1354#include "chrome/common/extensions/extension_file_util.h"
[email protected]c6d474f82009-12-16 21:11:0655#include "chrome/common/extensions/extension_l10n_util.h"
[email protected]82891262008-12-24 00:21:2656#include "chrome/common/notification_service.h"
[email protected]4814b512009-11-07 00:12:2957#include "chrome/common/notification_type.h"
[email protected]1952c7d2010-03-04 23:48:3458#include "chrome/common/json_value_serializer.h"
[email protected]25b34332009-06-05 21:53:1959#include "chrome/common/pref_names.h"
[email protected]a57209872009-05-04 22:53:1460#include "chrome/common/url_constants.h"
[email protected]c10da4b02010-03-25 14:38:3261#include "googleurl/src/gurl.h"
[email protected]1debbbb62010-10-06 17:23:4462#include "net/base/registry_controlled_domain.h"
[email protected]24b538a2010-02-27 01:22:4463#include "webkit/database/database_tracker.h"
64#include "webkit/database/database_util.h"
[email protected]c64631652009-04-29 22:24:3165
[email protected]79db6232009-02-13 20:51:2066#if defined(OS_WIN)
[email protected]a1257b12009-06-12 02:51:3467#include "chrome/browser/extensions/external_registry_extension_provider_win.h"
[email protected]79db6232009-02-13 20:51:2068#endif
[email protected]6014d672008-12-05 00:38:2569
[email protected]5ef47ec2010-01-28 05:58:0570using base::Time;
71
[email protected]c6d474f82009-12-16 21:11:0672namespace errors = extension_manifest_errors;
73
[email protected]b6ab96d2009-08-20 18:58:1974namespace {
75
[email protected]29d0d4ac2010-09-08 21:10:3176#if defined(OS_LINUX)
77static const int kOmniboxIconPaddingLeft = 2;
78static const int kOmniboxIconPaddingRight = 2;
79#elif defined(OS_MACOSX)
80static const int kOmniboxIconPaddingLeft = 0;
81static const int kOmniboxIconPaddingRight = 2;
82#else
83static const int kOmniboxIconPaddingLeft = 0;
84static const int kOmniboxIconPaddingRight = 0;
85#endif
86
[email protected]c2c263c2010-08-13 21:59:4887bool ShouldReloadExtensionManifest(const ExtensionInfo& info) {
[email protected]2111b1a2010-03-12 18:12:4488 // Always reload LOAD extension manifests, because they can change on disk
89 // independent of the manifest in our prefs.
90 if (info.extension_location == Extension::LOAD)
91 return true;
92
93 // Otherwise, reload the manifest it needs to be relocalized.
94 return extension_l10n_util::ShouldRelocalizeManifest(info);
95}
96
[email protected]9adb9692010-10-29 23:14:0297void GetExplicitOriginsInExtent(const Extension* extension,
[email protected]c2c263c2010-08-13 21:59:4898 std::vector<GURL>* origins) {
99 typedef std::vector<URLPattern> PatternList;
100 std::set<GURL> set;
101 const PatternList& patterns = extension->web_extent().patterns();
102 for (PatternList::const_iterator pattern = patterns.begin();
103 pattern != patterns.end(); ++pattern) {
104 if (pattern->match_subdomains() || pattern->match_all_urls())
105 continue;
[email protected]654512b2010-09-01 02:09:42106 // Wildcard URL schemes won't parse into a valid GURL, so explicit schemes
107 // must be used.
108 PatternList explicit_patterns = pattern->ConvertToExplicitSchemes();
109 for (PatternList::const_iterator explicit_p = explicit_patterns.begin();
110 explicit_p != explicit_patterns.end(); ++explicit_p) {
111 GURL origin = GURL(explicit_p->GetAsString()).GetOrigin();
112 if (origin.is_valid()) {
113 set.insert(origin);
114 } else {
115 NOTREACHED();
116 }
117 }
[email protected]c2c263c2010-08-13 21:59:48118 }
119
120 for (std::set<GURL>::const_iterator unique = set.begin();
121 unique != set.end(); ++unique) {
122 origins->push_back(*unique);
123 }
124}
125
[email protected]c6d474f82009-12-16 21:11:06126} // namespace
[email protected]b6ab96d2009-08-20 18:58:19127
[email protected]8ef78fd2010-08-19 17:14:32128PendingExtensionInfo::PendingExtensionInfo(
129 const GURL& update_url,
130 PendingExtensionInfo::ExpectedCrxType expected_crx_type,
131 bool is_from_sync,
132 bool install_silently,
133 bool enable_on_install,
[email protected]ec5b50d2010-10-09 16:35:18134 bool enable_incognito_on_install,
135 Extension::Location location)
[email protected]aa142702010-03-26 01:26:33136 : update_url(update_url),
[email protected]8ef78fd2010-08-19 17:14:32137 expected_crx_type(expected_crx_type),
138 is_from_sync(is_from_sync),
[email protected]4416c5a2010-06-26 01:28:57139 install_silently(install_silently),
140 enable_on_install(enable_on_install),
[email protected]ec5b50d2010-10-09 16:35:18141 enable_incognito_on_install(enable_incognito_on_install),
142 install_source(location) {}
[email protected]aa142702010-03-26 01:26:33143
144PendingExtensionInfo::PendingExtensionInfo()
145 : update_url(),
[email protected]8ef78fd2010-08-19 17:14:32146 expected_crx_type(PendingExtensionInfo::UNKNOWN),
147 is_from_sync(true),
[email protected]4416c5a2010-06-26 01:28:57148 install_silently(false),
149 enable_on_install(false),
[email protected]ec5b50d2010-10-09 16:35:18150 enable_incognito_on_install(false),
151 install_source(Extension::INVALID) {}
[email protected]aa142702010-03-26 01:26:33152
[email protected]25b34332009-06-05 21:53:19153// ExtensionsService.
[email protected]6014d672008-12-05 00:38:25154
[email protected]cc655912009-01-29 23:19:19155const char* ExtensionsService::kInstallDirectoryName = "Extensions";
156const char* ExtensionsService::kCurrentVersionFileName = "Current Version";
[email protected]494c06e2009-07-25 01:06:42157
[email protected]7a4c6852010-09-16 03:44:22158// Implements IO for the ExtensionsService.
159
160class ExtensionsServiceBackend
161 : public base::RefCountedThreadSafe<ExtensionsServiceBackend>,
162 public ExternalExtensionProvider::Visitor {
163 public:
[email protected]1f830eb2010-09-28 08:25:14164 // |install_directory| is a path where to look for extensions to load.
165 // |load_external_extensions| indicates whether or not backend should load
166 // external extensions listed in JSON file and Windows registry.
167 ExtensionsServiceBackend(const FilePath& install_directory,
168 bool load_external_extensions);
[email protected]7a4c6852010-09-16 03:44:22169
170 // Loads a single extension from |path| where |path| is the top directory of
171 // a specific extension where its manifest file lives.
172 // Errors are reported through ExtensionErrorReporter. On success,
173 // OnExtensionLoaded() is called.
174 // TODO(erikkay): It might be useful to be able to load a packed extension
175 // (presumably into memory) without installing it.
176 void LoadSingleExtension(const FilePath &path,
177 scoped_refptr<ExtensionsService> frontend);
178
179 // Check externally updated extensions for updates and install if necessary.
180 // Errors are reported through ExtensionErrorReporter. Succcess is not
181 // reported.
182 void CheckForExternalUpdates(std::set<std::string> ids_to_ignore,
183 scoped_refptr<ExtensionsService> frontend);
184
185 // For the extension in |version_path| with |id|, check to see if it's an
186 // externally managed extension. If so, tell the frontend to uninstall it.
187 void CheckExternalUninstall(scoped_refptr<ExtensionsService> frontend,
[email protected]0a60a2e2010-10-25 16:15:21188 const std::string& id);
[email protected]7a4c6852010-09-16 03:44:22189
190 // Clear all ExternalExtensionProviders.
191 void ClearProvidersForTesting();
192
[email protected]0a60a2e2010-10-25 16:15:21193 // Adds an ExternalExtensionProvider for the service to use during testing.
194 // Takes ownership of |test_provider|.
195 void AddProviderForTesting(ExternalExtensionProvider* test_provider);
[email protected]7a4c6852010-09-16 03:44:22196
197 // ExternalExtensionProvider::Visitor implementation.
198 virtual void OnExternalExtensionFileFound(const std::string& id,
199 const Version* version,
200 const FilePath& path,
201 Extension::Location location);
202
[email protected]a424d84c2010-09-24 09:31:15203 virtual void OnExternalExtensionUpdateUrlFound(const std::string& id,
204 const GURL& update_url);
[email protected]7a4c6852010-09-16 03:44:22205
206 // Reloads the given extensions from their manifests on disk (instead of what
207 // we have cached in the prefs).
208 void ReloadExtensionManifests(
209 ExtensionPrefs::ExtensionsInfo* extensions_to_reload,
210 base::TimeTicks start_time,
211 scoped_refptr<ExtensionsService> frontend);
212
213 private:
214 friend class base::RefCountedThreadSafe<ExtensionsServiceBackend>;
215
216 virtual ~ExtensionsServiceBackend();
217
218 // Finish installing the extension in |crx_path| after it has been unpacked to
219 // |unpacked_path|. If |expected_id| is not empty, it's verified against the
220 // extension's manifest before installation. If |silent| is true, there will
221 // be no install confirmation dialog. |from_gallery| indicates whether the
222 // crx was installed from our gallery, which results in different UI.
223 //
224 // Note: We take ownership of |extension|.
225 void OnExtensionUnpacked(const FilePath& crx_path,
226 const FilePath& unpacked_path,
[email protected]9adb9692010-10-29 23:14:02227 const Extension* extension,
[email protected]7a4c6852010-09-16 03:44:22228 const std::string expected_id);
229
230 // Notify the frontend that there was an error loading an extension.
231 void ReportExtensionLoadError(const FilePath& extension_path,
232 const std::string& error);
233
[email protected]7a4c6852010-09-16 03:44:22234 // This is a naked pointer which is set by each entry point.
235 // The entry point is responsible for ensuring lifetime.
236 ExtensionsService* frontend_;
237
238 // The top-level extensions directory being installed to.
239 FilePath install_directory_;
240
241 // Whether errors result in noisy alerts.
242 bool alert_on_error_;
243
[email protected]0a60a2e2010-10-25 16:15:21244 // A collection of external extension providers. Each provider reads
245 // a source of external extension information. Examples include the
246 // windows registry and external_extensions.json.
247 typedef std::vector<linked_ptr<ExternalExtensionProvider> >
248 ProviderCollection;
249 ProviderCollection external_extension_providers_;
[email protected]7a4c6852010-09-16 03:44:22250
251 // Set to true by OnExternalExtensionUpdateUrlFound() when an external
252 // extension URL is found. Used in CheckForExternalUpdates() to see
253 // if an update check is needed to install pending extensions.
254 bool external_extension_added_;
255
256 DISALLOW_COPY_AND_ASSIGN(ExtensionsServiceBackend);
257};
258
259ExtensionsServiceBackend::ExtensionsServiceBackend(
[email protected]1f830eb2010-09-28 08:25:14260 const FilePath& install_directory,
261 bool load_external_extensions)
[email protected]7a4c6852010-09-16 03:44:22262 : frontend_(NULL),
263 install_directory_(install_directory),
264 alert_on_error_(false),
265 external_extension_added_(false) {
[email protected]1f830eb2010-09-28 08:25:14266 if (!load_external_extensions)
267 return;
268
[email protected]7a4c6852010-09-16 03:44:22269 // TODO(aa): This ends up doing blocking IO on the UI thread because it reads
270 // pref data in the ctor and that is called on the UI thread. Would be better
271 // to re-read data each time we list external extensions, anyway.
[email protected]0a60a2e2010-10-25 16:15:21272 external_extension_providers_.push_back(
[email protected]7a4c6852010-09-16 03:44:22273 linked_ptr<ExternalExtensionProvider>(
[email protected]0a60a2e2010-10-25 16:15:21274 new ExternalPrefExtensionProvider()));
[email protected]7a4c6852010-09-16 03:44:22275#if defined(OS_WIN)
[email protected]0a60a2e2010-10-25 16:15:21276 external_extension_providers_.push_back(
[email protected]7a4c6852010-09-16 03:44:22277 linked_ptr<ExternalExtensionProvider>(
[email protected]0a60a2e2010-10-25 16:15:21278 new ExternalRegistryExtensionProvider()));
[email protected]7a4c6852010-09-16 03:44:22279#endif
280}
281
282ExtensionsServiceBackend::~ExtensionsServiceBackend() {
283}
284
285void ExtensionsServiceBackend::LoadSingleExtension(
286 const FilePath& path_in, scoped_refptr<ExtensionsService> frontend) {
[email protected]a8af9fdb2010-10-28 21:52:20287 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
288
[email protected]7a4c6852010-09-16 03:44:22289 frontend_ = frontend;
290
291 // Explicit UI loads are always noisy.
292 alert_on_error_ = true;
293
294 FilePath extension_path = path_in;
295 file_util::AbsolutePath(&extension_path);
296
[email protected]7a4c6852010-09-16 03:44:22297 std::string error;
[email protected]ad8e04a2010-11-01 04:16:27298 scoped_refptr<const Extension> extension(extension_file_util::LoadExtension(
[email protected]7a4c6852010-09-16 03:44:22299 extension_path,
[email protected]92888082010-10-18 19:24:57300 Extension::LOAD,
[email protected]7a4c6852010-09-16 03:44:22301 false, // Don't require id
[email protected]ad8e04a2010-11-01 04:16:27302 &error));
[email protected]7a4c6852010-09-16 03:44:22303
304 if (!extension) {
305 ReportExtensionLoadError(extension_path, error);
306 return;
307 }
308
[email protected]7a4c6852010-09-16 03:44:22309 // Report this as an installed extension so that it gets remembered in the
310 // prefs.
[email protected]ca4b5fa32010-10-09 12:42:18311 BrowserThread::PostTask(
312 BrowserThread::UI, FROM_HERE,
[email protected]7a4c6852010-09-16 03:44:22313 NewRunnableMethod(frontend_, &ExtensionsService::OnExtensionInstalled,
314 extension, true));
315}
316
317void ExtensionsServiceBackend::ReportExtensionLoadError(
318 const FilePath& extension_path, const std::string &error) {
[email protected]a8af9fdb2010-10-28 21:52:20319 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
[email protected]ca4b5fa32010-10-09 12:42:18320 BrowserThread::PostTask(
321 BrowserThread::UI, FROM_HERE,
[email protected]7a4c6852010-09-16 03:44:22322 NewRunnableMethod(
323 frontend_,
324 &ExtensionsService::ReportExtensionLoadError, extension_path,
325 error, NotificationType::EXTENSION_INSTALL_ERROR, alert_on_error_));
326}
327
[email protected]7a4c6852010-09-16 03:44:22328// Some extensions will autoupdate themselves externally from Chrome. These
329// are typically part of some larger client application package. To support
330// these, the extension will register its location in the the preferences file
331// (and also, on Windows, in the registry) and this code will periodically
332// check that location for a .crx file, which it will then install locally if
333// a new version is available.
334void ExtensionsServiceBackend::CheckForExternalUpdates(
335 std::set<std::string> ids_to_ignore,
336 scoped_refptr<ExtensionsService> frontend) {
[email protected]a8af9fdb2010-10-28 21:52:20337 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
338
[email protected]7a4c6852010-09-16 03:44:22339 // Note that this installation is intentionally silent (since it didn't
340 // go through the front-end). Extensions that are registered in this
341 // way are effectively considered 'pre-bundled', and so implicitly
342 // trusted. In general, if something has HKLM or filesystem access,
343 // they could install an extension manually themselves anyway.
344 alert_on_error_ = false;
345 frontend_ = frontend;
346 external_extension_added_ = false;
347
348 // Ask each external extension provider to give us a call back for each
349 // extension they know about. See OnExternalExtension(File|UpdateUrl)Found.
[email protected]0a60a2e2010-10-25 16:15:21350 ProviderCollection::const_iterator i;
351 for (i = external_extension_providers_.begin();
[email protected]7a4c6852010-09-16 03:44:22352 i != external_extension_providers_.end(); ++i) {
[email protected]0a60a2e2010-10-25 16:15:21353 ExternalExtensionProvider* provider = i->get();
[email protected]7a4c6852010-09-16 03:44:22354 provider->VisitRegisteredExtension(this, ids_to_ignore);
355 }
356
357 if (external_extension_added_ && frontend->updater()) {
[email protected]ca4b5fa32010-10-09 12:42:18358 BrowserThread::PostTask(
359 BrowserThread::UI, FROM_HERE,
[email protected]7a4c6852010-09-16 03:44:22360 NewRunnableMethod(
361 frontend->updater(), &ExtensionUpdater::CheckNow));
362 }
363}
364
365void ExtensionsServiceBackend::CheckExternalUninstall(
[email protected]0a60a2e2010-10-25 16:15:21366 scoped_refptr<ExtensionsService> frontend, const std::string& id) {
[email protected]a8af9fdb2010-10-28 21:52:20367 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
368
[email protected]7a4c6852010-09-16 03:44:22369 // Check if the providers know about this extension.
[email protected]0a60a2e2010-10-25 16:15:21370 ProviderCollection::const_iterator i;
371 for (i = external_extension_providers_.begin();
372 i != external_extension_providers_.end(); ++i) {
373 if (i->get()->HasExtension(id))
374 return; // Yup, known extension, don't uninstall.
[email protected]7a4c6852010-09-16 03:44:22375 }
376
[email protected]7a4c6852010-09-16 03:44:22377 // This is an external extension that we don't have registered. Uninstall.
[email protected]ca4b5fa32010-10-09 12:42:18378 BrowserThread::PostTask(
379 BrowserThread::UI, FROM_HERE,
[email protected]7a4c6852010-09-16 03:44:22380 NewRunnableMethod(
381 frontend.get(), &ExtensionsService::UninstallExtension, id, true));
382}
383
384void ExtensionsServiceBackend::ClearProvidersForTesting() {
385 external_extension_providers_.clear();
386}
387
[email protected]0a60a2e2010-10-25 16:15:21388void ExtensionsServiceBackend::AddProviderForTesting(
[email protected]7a4c6852010-09-16 03:44:22389 ExternalExtensionProvider* test_provider) {
390 DCHECK(test_provider);
[email protected]0a60a2e2010-10-25 16:15:21391 external_extension_providers_.push_back(
392 linked_ptr<ExternalExtensionProvider>(test_provider));
[email protected]7a4c6852010-09-16 03:44:22393}
394
395void ExtensionsServiceBackend::OnExternalExtensionFileFound(
396 const std::string& id, const Version* version, const FilePath& path,
397 Extension::Location location) {
[email protected]a8af9fdb2010-10-28 21:52:20398 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
399
[email protected]7a4c6852010-09-16 03:44:22400 DCHECK(version);
[email protected]ca4b5fa32010-10-09 12:42:18401 BrowserThread::PostTask(
402 BrowserThread::UI, FROM_HERE,
[email protected]7a4c6852010-09-16 03:44:22403 NewRunnableMethod(
404 frontend_, &ExtensionsService::OnExternalExtensionFileFound, id,
405 version->GetString(), path, location));
406}
407
408void ExtensionsServiceBackend::OnExternalExtensionUpdateUrlFound(
409 const std::string& id,
[email protected]a424d84c2010-09-24 09:31:15410 const GURL& update_url) {
[email protected]a8af9fdb2010-10-28 21:52:20411 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
412
[email protected]7a4c6852010-09-16 03:44:22413 if (frontend_->GetExtensionById(id, true)) {
414 // Already installed. Do not change the update URL that the extension set.
415 return;
416 }
417
[email protected]a8af9fdb2010-10-28 21:52:20418 BrowserThread::PostTask(
419 BrowserThread::UI, FROM_HERE,
420 NewRunnableMethod(
421 frontend_,
422 &ExtensionsService::AddPendingExtensionFromExternalUpdateUrl,
423 id, update_url));
[email protected]7a4c6852010-09-16 03:44:22424 external_extension_added_ |= true;
425}
426
427void ExtensionsServiceBackend::ReloadExtensionManifests(
428 ExtensionPrefs::ExtensionsInfo* extensions_to_reload,
429 base::TimeTicks start_time,
430 scoped_refptr<ExtensionsService> frontend) {
[email protected]a8af9fdb2010-10-28 21:52:20431 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
432
[email protected]7a4c6852010-09-16 03:44:22433 frontend_ = frontend;
434
435 for (size_t i = 0; i < extensions_to_reload->size(); ++i) {
436 ExtensionInfo* info = extensions_to_reload->at(i).get();
437 if (!ShouldReloadExtensionManifest(*info))
438 continue;
439
440 // We need to reload original manifest in order to localize properly.
441 std::string error;
[email protected]9adb9692010-10-29 23:14:02442 scoped_refptr<const Extension> extension(extension_file_util::LoadExtension(
[email protected]92888082010-10-18 19:24:57443 info->extension_path, info->extension_location, false, &error));
[email protected]7a4c6852010-09-16 03:44:22444
445 if (extension.get())
446 extensions_to_reload->at(i)->extension_manifest.reset(
447 static_cast<DictionaryValue*>(
448 extension->manifest_value()->DeepCopy()));
449 }
450
451 // Finish installing on UI thread.
[email protected]ca4b5fa32010-10-09 12:42:18452 BrowserThread::PostTask(
453 BrowserThread::UI, FROM_HERE,
[email protected]7a4c6852010-09-16 03:44:22454 NewRunnableMethod(
455 frontend_,
456 &ExtensionsService::ContinueLoadAllExtensions,
457 extensions_to_reload,
458 start_time,
459 true));
460}
461
[email protected]334e04a2010-06-24 23:34:44462bool ExtensionsService::IsDownloadFromGallery(const GURL& download_url,
463 const GURL& referrer_url) {
[email protected]d3071992010-10-08 15:24:07464 // Special-case the themes mini-gallery.
465 // TODO(erikkay) When that gallery goes away, remove this code.
466 if (IsDownloadFromMiniGallery(download_url) &&
467 StartsWithASCII(referrer_url.spec(),
468 extension_urls::kMiniGalleryBrowsePrefix, false)) {
[email protected]334e04a2010-06-24 23:34:44469 return true;
[email protected]1debbbb62010-10-06 17:23:44470 }
[email protected]473ff6e2010-05-12 15:31:55471
[email protected]9adb9692010-10-29 23:14:02472 const Extension* download_extension = GetExtensionByWebExtent(download_url);
473 const Extension* referrer_extension = GetExtensionByWebExtent(referrer_url);
474 const Extension* webstore_app = GetWebStoreApp();
[email protected]d3071992010-10-08 15:24:07475
476 bool referrer_valid = (referrer_extension == webstore_app);
477 bool download_valid = (download_extension == webstore_app);
478
479 // If the command-line gallery URL is set, then be a bit more lenient.
480 GURL store_url =
481 GURL(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
482 switches::kAppsGalleryURL));
483 if (!store_url.is_empty()) {
484 std::string store_tld =
485 net::RegistryControlledDomainService::GetDomainAndRegistry(store_url);
486 if (!referrer_valid) {
487 std::string referrer_tld =
488 net::RegistryControlledDomainService::GetDomainAndRegistry(
489 referrer_url);
490 // The referrer gets stripped when transitioning from https to http,
491 // or when hitting an unknown test cert and that commonly happens in
492 // testing environments. Given this, we allow an empty referrer when
493 // the command-line flag is set.
494 // Otherwise, the TLD must match the TLD of the command-line url.
495 referrer_valid = referrer_url.is_empty() || (referrer_tld == store_tld);
496 }
497
498 if (!download_valid) {
499 std::string download_tld =
500 net::RegistryControlledDomainService::GetDomainAndRegistry(
501 GURL(download_url));
502
503 // Otherwise, the TLD must match the TLD of the command-line url.
504 download_valid = (download_tld == store_tld);
505 }
506 }
507
508 return (referrer_valid && download_valid);
[email protected]b7c2f252009-12-08 00:47:23509}
510
[email protected]ac025282009-12-16 19:16:38511bool ExtensionsService::IsDownloadFromMiniGallery(const GURL& download_url) {
512 return StartsWithASCII(download_url.spec(),
513 extension_urls::kMiniGalleryDownloadPrefix,
514 false); // case_sensitive
515}
516
[email protected]6aeac8342010-10-01 20:21:18517// static
518bool ExtensionsService::UninstallExtensionHelper(
519 ExtensionsService* extensions_service,
520 const std::string& extension_id) {
521 DCHECK(extensions_service);
522
523 // We can't call UninstallExtension with an invalid extension ID, so check it
524 // first.
525 if (extensions_service->GetExtensionById(extension_id, true)) {
526 extensions_service->UninstallExtension(extension_id, false);
527 } else {
528 LOG(WARNING) << "Attempted uninstallation of non-existent extension with "
[email protected]a8af9fdb2010-10-28 21:52:20529 << "id: " << extension_id;
[email protected]6aeac8342010-10-01 20:21:18530 return false;
531 }
532
533 return true;
534}
535
[email protected]81e63782009-02-27 19:35:09536ExtensionsService::ExtensionsService(Profile* profile,
[email protected]36a784c2009-06-23 06:21:08537 const CommandLine* command_line,
[email protected]a9b00ac2009-06-25 21:03:23538 const FilePath& install_directory,
[email protected]93fd78f42009-07-10 16:43:17539 bool autoupdate_enabled)
[email protected]6ef635e42009-07-26 06:16:12540 : profile_(profile),
[email protected]2fb7dc982010-09-29 12:24:28541 extension_prefs_(new ExtensionPrefs(profile->GetPrefs(),
542 install_directory)),
[email protected]a9b00ac2009-06-25 21:03:23543 install_directory_(install_directory),
[email protected]6d60703b2009-08-29 01:29:23544 extensions_enabled_(true),
[email protected]e81dba32009-06-19 20:19:13545 show_extensions_prompts_(true),
[email protected]e0360f2c2009-12-07 22:34:31546 ready_(false),
[email protected]ec5b50d2010-10-09 16:35:18547 ALLOW_THIS_IN_INITIALIZER_LIST(toolbar_model_(this)),
[email protected]b3d62312b12010-10-14 21:10:18548 default_apps_(profile->GetPrefs()),
549 event_routers_initialized_(false) {
[email protected]a8af9fdb2010-10-28 21:52:20550 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
551
[email protected]36a784c2009-06-23 06:21:08552 // Figure out if extension installation should be enabled.
[email protected]6d60703b2009-08-29 01:29:23553 if (command_line->HasSwitch(switches::kDisableExtensions)) {
554 extensions_enabled_ = false;
555 } else if (profile->GetPrefs()->GetBoolean(prefs::kDisableExtensions)) {
556 extensions_enabled_ = false;
[email protected]6b75ec32009-08-14 06:37:18557 }
[email protected]36a784c2009-06-23 06:21:08558
[email protected]a4ed6282009-12-14 20:51:16559 registrar_.Add(this, NotificationType::EXTENSION_PROCESS_TERMINATED,
[email protected]bc535ee52010-08-31 18:40:32560 NotificationService::AllSources());
[email protected]2fb7dc982010-09-29 12:24:28561 pref_change_registrar_.Init(profile->GetPrefs());
562 pref_change_registrar_.Add(prefs::kExtensionInstallAllowList, this);
563 pref_change_registrar_.Add(prefs::kExtensionInstallDenyList, this);
[email protected]4814b512009-11-07 00:12:29564
[email protected]93fd78f42009-07-10 16:43:17565 // Set up the ExtensionUpdater
566 if (autoupdate_enabled) {
567 int update_frequency = kDefaultUpdateFrequencySeconds;
568 if (command_line->HasSwitch(switches::kExtensionsUpdateFrequency)) {
[email protected]e83326f2010-07-31 17:29:25569 base::StringToInt(command_line->GetSwitchValueASCII(
570 switches::kExtensionsUpdateFrequency),
571 &update_frequency);
[email protected]93fd78f42009-07-10 16:43:17572 }
[email protected]2fb7dc982010-09-29 12:24:28573 updater_ = new ExtensionUpdater(this,
574 profile->GetPrefs(),
575 update_frequency);
[email protected]93fd78f42009-07-10 16:43:17576 }
577
[email protected]1f830eb2010-09-28 08:25:14578 backend_ = new ExtensionsServiceBackend(install_directory_,
579 extensions_enabled_);
[email protected]b671760b2010-07-15 21:13:47580
[email protected]aa96d3a2010-08-21 08:45:25581 // Use monochrome icons for Omnibox icons.
[email protected]29d0d4ac2010-09-08 21:10:31582 omnibox_popup_icon_manager_.set_monochrome(true);
[email protected]b671760b2010-07-15 21:13:47583 omnibox_icon_manager_.set_monochrome(true);
[email protected]29d0d4ac2010-09-08 21:10:31584 omnibox_icon_manager_.set_padding(gfx::Insets(0, kOmniboxIconPaddingLeft,
585 0, kOmniboxIconPaddingRight));
[email protected]6014d672008-12-05 00:38:25586}
587
588ExtensionsService::~ExtensionsService() {
[email protected]2fb7dc982010-09-29 12:24:28589 DCHECK(!profile_); // Profile should have told us it's going away.
[email protected]9f1087e2009-06-15 17:29:32590 UnloadAllExtensions();
[email protected]93fd78f42009-07-10 16:43:17591 if (updater_.get()) {
592 updater_->Stop();
593 }
[email protected]6014d672008-12-05 00:38:25594}
595
[email protected]c5ae74ab2010-04-15 18:14:37596void ExtensionsService::InitEventRouters() {
[email protected]b3d62312b12010-10-14 21:10:18597 if (event_routers_initialized_)
598 return;
599
[email protected]c5ae74ab2010-04-15 18:14:37600 ExtensionHistoryEventRouter::GetInstance()->ObserveProfile(profile_);
601 ExtensionAccessibilityEventRouter::GetInstance()->ObserveProfile(profile_);
[email protected]56ee0152010-06-16 01:54:42602 ExtensionBrowserEventRouter::GetInstance()->Init(profile_);
[email protected]c5ae74ab2010-04-15 18:14:37603 ExtensionBookmarkEventRouter::GetSingleton()->Observe(
604 profile_->GetBookmarkModel());
[email protected]2c5e1e12010-06-10 13:14:44605 ExtensionCookiesEventRouter::GetInstance()->Init();
[email protected]7596ce72010-08-30 05:10:46606 ExtensionManagementEventRouter::GetInstance()->Init();
[email protected]8a661f82010-10-19 21:47:11607 ExtensionProcessesEventRouter::GetInstance()->ObserveProfile(profile_);
[email protected]784688a62010-09-13 07:06:52608 ExtensionWebNavigationEventRouter::GetInstance()->Init();
[email protected]b3d62312b12010-10-14 21:10:18609 event_routers_initialized_ = true;
[email protected]c5ae74ab2010-04-15 18:14:37610}
611
[email protected]9f1087e2009-06-15 17:29:32612void ExtensionsService::Init() {
[email protected]a8af9fdb2010-10-28 21:52:20613 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
614
[email protected]c6e4a3412009-06-24 15:45:29615 DCHECK(!ready_);
[email protected]93fd78f42009-07-10 16:43:17616 DCHECK_EQ(extensions_.size(), 0u);
[email protected]9f1087e2009-06-15 17:29:32617
[email protected]95dd38f2009-10-20 20:09:15618 // Hack: we need to ensure the ResourceDispatcherHost is ready before we load
619 // the first extension, because its members listen for loaded notifications.
620 g_browser_process->resource_dispatcher_host();
621
[email protected]9f1087e2009-06-15 17:29:32622 LoadAllExtensions();
[email protected]894bb502009-05-21 22:39:57623
[email protected]9f1087e2009-06-15 17:29:32624 // TODO(erikkay) this should probably be deferred to a future point
625 // rather than running immediately at startup.
[email protected]93fd78f42009-07-10 16:43:17626 CheckForExternalUpdates();
[email protected]894bb502009-05-21 22:39:57627
[email protected]9f1087e2009-06-15 17:29:32628 // TODO(erikkay) this should probably be deferred as well.
629 GarbageCollectExtensions();
[email protected]6014d672008-12-05 00:38:25630}
631
[email protected]3cf4f0992009-02-03 23:00:30632void ExtensionsService::InstallExtension(const FilePath& extension_path) {
[email protected]6dfbbf82010-03-12 23:09:16633 scoped_refptr<CrxInstaller> installer(
634 new CrxInstaller(install_directory_,
635 this, // frontend
636 NULL)); // no client (silent install)
637 installer->set_allow_privilege_increase(true);
638 installer->InstallCrx(extension_path);
[email protected]3cf4f0992009-02-03 23:00:30639}
640
[email protected]aa142702010-03-26 01:26:33641namespace {
642 // TODO(akalin): Put this somewhere where both crx_installer.cc and
643 // this file can use it.
644 void DeleteFileHelper(const FilePath& path, bool recursive) {
[email protected]ca4b5fa32010-10-09 12:42:18645 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
[email protected]aa142702010-03-26 01:26:33646 file_util::Delete(path, recursive);
647 }
648} // namespace
649
[email protected]e957fe52009-06-23 16:51:05650void ExtensionsService::UpdateExtension(const std::string& id,
[email protected]5c8516202010-03-18 21:43:34651 const FilePath& extension_path,
652 const GURL& download_url) {
[email protected]a8af9fdb2010-10-28 21:52:20653 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
654
[email protected]aa142702010-03-26 01:26:33655 PendingExtensionMap::const_iterator it = pending_extensions_.find(id);
[email protected]8ef78fd2010-08-19 17:14:32656 bool is_pending_extension = (it != pending_extensions_.end());
657
658 if (!is_pending_extension &&
[email protected]aa142702010-03-26 01:26:33659 !GetExtensionByIdInternal(id, true, true)) {
660 LOG(WARNING) << "Will not update extension " << id
661 << " because it is not installed or pending";
662 // Delete extension_path since we're not creating a CrxInstaller
663 // that would do it for us.
[email protected]ca4b5fa32010-10-09 12:42:18664 BrowserThread::PostTask(
665 BrowserThread::FILE, FROM_HERE,
[email protected]aa142702010-03-26 01:26:33666 NewRunnableFunction(&DeleteFileHelper, extension_path, false));
[email protected]4c967932009-07-31 01:15:49667 return;
[email protected]e957fe52009-06-23 16:51:05668 }
669
[email protected]aa142702010-03-26 01:26:33670 // We want a silent install only for non-pending extensions and
671 // pending extensions that have install_silently set.
672 ExtensionInstallUI* client =
[email protected]8ef78fd2010-08-19 17:14:32673 (!is_pending_extension || it->second.install_silently) ?
[email protected]aa142702010-03-26 01:26:33674 NULL : new ExtensionInstallUI(profile_);
675
[email protected]6dfbbf82010-03-12 23:09:16676 scoped_refptr<CrxInstaller> installer(
677 new CrxInstaller(install_directory_,
678 this, // frontend
[email protected]aa142702010-03-26 01:26:33679 client));
[email protected]6dfbbf82010-03-12 23:09:16680 installer->set_expected_id(id);
[email protected]ec5b50d2010-10-09 16:35:18681 if (is_pending_extension)
682 installer->set_install_source(it->second.install_source);
[email protected]6dfbbf82010-03-12 23:09:16683 installer->set_delete_source(true);
[email protected]5c8516202010-03-18 21:43:34684 installer->set_original_url(download_url);
[email protected]6dfbbf82010-03-12 23:09:16685 installer->InstallCrx(extension_path);
[email protected]e957fe52009-06-23 16:51:05686}
687
[email protected]8ef78fd2010-08-19 17:14:32688void ExtensionsService::AddPendingExtensionFromSync(
[email protected]aa142702010-03-26 01:26:33689 const std::string& id, const GURL& update_url,
[email protected]8ef78fd2010-08-19 17:14:32690 PendingExtensionInfo::ExpectedCrxType expected_crx_type,
691 bool install_silently, bool enable_on_install,
692 bool enable_incognito_on_install) {
[email protected]aa142702010-03-26 01:26:33693 if (GetExtensionByIdInternal(id, true, true)) {
[email protected]efee9f262010-03-29 21:26:25694 LOG(DFATAL) << "Trying to add pending extension " << id
695 << " which already exists";
[email protected]aa142702010-03-26 01:26:33696 return;
697 }
[email protected]ec5b50d2010-10-09 16:35:18698
699 AddPendingExtensionInternal(id, update_url, expected_crx_type, true,
700 install_silently, enable_on_install,
701 enable_incognito_on_install,
702 Extension::INTERNAL);
[email protected]aa142702010-03-26 01:26:33703}
704
[email protected]8ef78fd2010-08-19 17:14:32705void ExtensionsService::AddPendingExtensionFromExternalUpdateUrl(
[email protected]a424d84c2010-09-24 09:31:15706 const std::string& id, const GURL& update_url) {
[email protected]8ef78fd2010-08-19 17:14:32707 // Add the extension to this list of extensions to update.
[email protected]8ef78fd2010-08-19 17:14:32708 const PendingExtensionInfo::ExpectedCrxType kExpectedCrxType =
709 PendingExtensionInfo::UNKNOWN;
710 const bool kIsFromSync = false;
711 const bool kInstallSilently = true;
712 const bool kEnableOnInstall = true;
[email protected]a424d84c2010-09-24 09:31:15713 const bool kEnableIncognitoOnInstall = false;
[email protected]8ef78fd2010-08-19 17:14:32714
715 if (GetExtensionByIdInternal(id, true, true)) {
716 LOG(DFATAL) << "Trying to add extension " << id
717 << " by external update, but it is already installed.";
718 return;
719 }
720
721 AddPendingExtensionInternal(id, update_url, kExpectedCrxType, kIsFromSync,
722 kInstallSilently, kEnableOnInstall,
[email protected]ec5b50d2010-10-09 16:35:18723 kEnableIncognitoOnInstall,
724 Extension::EXTERNAL_PREF_DOWNLOAD);
725}
726
727void ExtensionsService::AddPendingExtensionFromDefaultAppList(
728 const std::string& id) {
729 // Add the extension to this list of extensions to update.
730 const PendingExtensionInfo::ExpectedCrxType kExpectedCrxType =
731 PendingExtensionInfo::APP;
732 const bool kIsFromSync = false;
733 const bool kInstallSilently = true;
734 const bool kEnableOnInstall = true;
735 const bool kEnableIncognitoOnInstall = true;
736
737 // This can legitimately happen if the user manually installed one of the
738 // default apps before this code ran.
739 if (GetExtensionByIdInternal(id, true, true))
740 return;
741
742 AddPendingExtensionInternal(id, GURL(), kExpectedCrxType, kIsFromSync,
743 kInstallSilently, kEnableOnInstall,
744 kEnableIncognitoOnInstall,
745 Extension::INTERNAL);
[email protected]8ef78fd2010-08-19 17:14:32746}
747
[email protected]aa142702010-03-26 01:26:33748void ExtensionsService::AddPendingExtensionInternal(
749 const std::string& id, const GURL& update_url,
[email protected]8ef78fd2010-08-19 17:14:32750 PendingExtensionInfo::ExpectedCrxType expected_crx_type,
751 bool is_from_sync, bool install_silently,
[email protected]ec5b50d2010-10-09 16:35:18752 bool enable_on_install, bool enable_incognito_on_install,
753 Extension::Location install_source) {
[email protected]a8af9fdb2010-10-28 21:52:20754 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
755
[email protected]1afaf2a52010-11-02 19:29:17756 // If a non-sync update is pending, a sync request should not
757 // overwrite it. This is important for external extensions.
758 // If an external extension download is pending, and the user has
759 // the extension in their sync profile, the install should set the
760 // type to be external. An external extension should not be
761 // rejected if it fails the safty checks for a syncable extension.
762 // TODO(skerner): Work out other potential overlapping conditions.
763 // (crbug/61000)
764 PendingExtensionMap::iterator it = pending_extensions_.find(id);
765 if (it != pending_extensions_.end()) {
766 VLOG(1) << "Extension id " << id
767 << " was entered for update more than once."
768 << " old is_from_sync = " << it->second.is_from_sync
769 << " new is_from_sync = " << is_from_sync;
770 if (!it->second.is_from_sync && is_from_sync)
771 return;
772 }
773
774
[email protected]aa142702010-03-26 01:26:33775 pending_extensions_[id] =
[email protected]8ef78fd2010-08-19 17:14:32776 PendingExtensionInfo(update_url, expected_crx_type, is_from_sync,
777 install_silently, enable_on_install,
[email protected]ec5b50d2010-10-09 16:35:18778 enable_incognito_on_install, install_source);
[email protected]aa142702010-03-26 01:26:33779}
780
[email protected]9cddd4702009-07-27 22:09:40781void ExtensionsService::ReloadExtension(const std::string& extension_id) {
[email protected]a8af9fdb2010-10-28 21:52:20782 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]b65272f2009-08-31 15:47:06783 FilePath path;
[email protected]9adb9692010-10-29 23:14:02784 const Extension* current_extension = GetExtensionById(extension_id, false);
[email protected]9cddd4702009-07-27 22:09:40785
[email protected]f17dbd42010-08-16 23:21:10786 // Disable the extension if it's loaded. It might not be loaded if it crashed.
[email protected]b65272f2009-08-31 15:47:06787 if (current_extension) {
[email protected]4814b512009-11-07 00:12:29788 // If the extension has an inspector open for its background page, detach
789 // the inspector and hang onto a cookie for it, so that we can reattach
790 // later.
791 ExtensionProcessManager* manager = profile_->GetExtensionProcessManager();
792 ExtensionHost* host = manager->GetBackgroundHostForExtension(
793 current_extension);
794 if (host) {
795 // Look for an open inspector for the background page.
796 int devtools_cookie = DevToolsManager::GetInstance()->DetachClientHost(
797 host->render_view_host());
798 if (devtools_cookie >= 0)
799 orphaned_dev_tools_[extension_id] = devtools_cookie;
800 }
801
[email protected]b65272f2009-08-31 15:47:06802 path = current_extension->path();
[email protected]f17dbd42010-08-16 23:21:10803 DisableExtension(extension_id);
804 disabled_extension_paths_[extension_id] = path;
[email protected]1eb175082010-02-10 09:26:16805 } else {
806 path = unloaded_extension_paths_[extension_id];
[email protected]b65272f2009-08-31 15:47:06807 }
808
[email protected]e6090e42010-03-23 22:44:08809 // Check the installed extensions to see if what we're reloading was already
810 // installed.
811 scoped_ptr<ExtensionInfo> installed_extension(
812 extension_prefs_->GetInstalledExtensionInfo(extension_id));
813 if (installed_extension.get() &&
814 installed_extension->extension_manifest.get()) {
815 LoadInstalledExtension(*installed_extension, false);
816 } else {
817 // We should always be able to remember the extension's path. If it's not in
818 // the map, someone failed to update |unloaded_extension_paths_|.
819 CHECK(!path.empty());
820 LoadExtension(path);
821 }
[email protected]9cddd4702009-07-27 22:09:40822}
823
[email protected]27b985d2009-06-25 17:53:15824void ExtensionsService::UninstallExtension(const std::string& extension_id,
825 bool external_uninstall) {
[email protected]a8af9fdb2010-10-28 21:52:20826 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
827
[email protected]9adb9692010-10-29 23:14:02828 const Extension* extension =
829 GetExtensionByIdInternal(extension_id, true, true);
[email protected]631cf822009-05-15 07:01:25830
[email protected]e7afe2452010-08-22 16:19:13831 // Callers should not send us nonexistent extensions.
[email protected]e72e8eb82009-06-18 17:21:51832 DCHECK(extension);
[email protected]9f1087e2009-06-15 17:29:32833
[email protected]831aa212010-03-26 13:55:19834 // Get hold of information we need after unloading, since the extension
835 // pointer will be invalid then.
836 GURL extension_url(extension->url());
837 Extension::Location location(extension->location());
[email protected]211030342010-09-30 18:41:06838 UninstalledExtensionInfo uninstalled_extension_info(*extension);
[email protected]831aa212010-03-26 13:55:19839
[email protected]9b217652010-10-08 22:04:23840 UMA_HISTOGRAM_ENUMERATION("Extensions.UninstallType",
841 extension->GetHistogramType(), 100);
842
[email protected]831aa212010-03-26 13:55:19843 // Also copy the extension identifier since the reference might have been
844 // obtained via Extension::id().
845 std::string extension_id_copy(extension_id);
846
[email protected]56ad3792010-05-28 17:45:33847 if (profile_->GetTemplateURLModel())
848 profile_->GetTemplateURLModel()->UnregisterExtensionKeyword(extension);
849
[email protected]831aa212010-03-26 13:55:19850 // Unload before doing more cleanup to ensure that nothing is hanging on to
851 // any of these resources.
852 UnloadExtension(extension_id);
853
854 extension_prefs_->OnExtensionUninstalled(extension_id_copy, location,
855 external_uninstall);
[email protected]9f1087e2009-06-15 17:29:32856
857 // Tell the backend to start deleting installed extensions on the file thread.
[email protected]831aa212010-03-26 13:55:19858 if (Extension::LOAD != location) {
[email protected]ca4b5fa32010-10-09 12:42:18859 BrowserThread::PostTask(
860 BrowserThread::FILE, FROM_HERE,
[email protected]95d29192009-10-30 01:49:06861 NewRunnableFunction(
[email protected]ca3dbf52010-05-19 22:27:06862 &extension_file_util::UninstallExtension,
863 install_directory_,
864 extension_id_copy));
[email protected]9f1087e2009-06-15 17:29:32865 }
866
[email protected]c10da4b02010-03-25 14:38:32867 ClearExtensionData(extension_url);
[email protected]211030342010-09-30 18:41:06868
869 // Notify interested parties that we've uninstalled this extension.
870 NotificationService::current()->Notify(
871 NotificationType::EXTENSION_UNINSTALLED,
872 Source<Profile>(profile_),
873 Details<UninstalledExtensionInfo>(&uninstalled_extension_info));
[email protected]c10da4b02010-03-25 14:38:32874}
875
876void ExtensionsService::ClearExtensionData(const GURL& extension_url) {
877 scoped_refptr<ExtensionDataDeleter> deleter(
878 new ExtensionDataDeleter(profile_, extension_url));
879 deleter->StartDeleting();
[email protected]9f1087e2009-06-15 17:29:32880}
881
[email protected]0c6da502009-08-14 22:32:39882void ExtensionsService::EnableExtension(const std::string& extension_id) {
[email protected]a8af9fdb2010-10-28 21:52:20883 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
884
[email protected]9adb9692010-10-29 23:14:02885 const Extension* extension =
886 GetExtensionByIdInternal(extension_id, false, true);
[email protected]0c6da502009-08-14 22:32:39887 if (!extension) {
[email protected]0c6da502009-08-14 22:32:39888 return;
889 }
890
[email protected]e8c729a2010-03-09 19:55:19891 extension_prefs_->SetExtensionState(extension, Extension::ENABLED);
[email protected]1784e83a2009-09-08 21:01:52892
[email protected]0c6da502009-08-14 22:32:39893 // Move it over to the enabled list.
[email protected]00cd9c42010-11-02 20:15:57894 extensions_.push_back(make_scoped_refptr(extension));
[email protected]0c6da502009-08-14 22:32:39895 ExtensionList::iterator iter = std::find(disabled_extensions_.begin(),
896 disabled_extensions_.end(),
897 extension);
898 disabled_extensions_.erase(iter);
899
[email protected]86c008e82009-08-28 20:26:05900 ExtensionDOMUI::RegisterChromeURLOverrides(profile_,
901 extension->GetChromeURLOverrides());
902
[email protected]62d30f42009-10-01 22:36:06903 NotifyExtensionLoaded(extension);
[email protected]aab98a52009-12-02 03:22:35904 UpdateActiveExtensionsInCrashReporter();
[email protected]0c6da502009-08-14 22:32:39905}
906
[email protected]1784e83a2009-09-08 21:01:52907void ExtensionsService::DisableExtension(const std::string& extension_id) {
[email protected]a8af9fdb2010-10-28 21:52:20908 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
909
[email protected]9adb9692010-10-29 23:14:02910 const Extension* extension =
911 GetExtensionByIdInternal(extension_id, true, false);
[email protected]b2ba9962009-12-10 20:10:15912 // The extension may have been disabled already.
913 if (!extension)
[email protected]1784e83a2009-09-08 21:01:52914 return;
[email protected]1784e83a2009-09-08 21:01:52915
[email protected]e8c729a2010-03-09 19:55:19916 extension_prefs_->SetExtensionState(extension, Extension::DISABLED);
[email protected]1784e83a2009-09-08 21:01:52917
918 // Move it over to the disabled list.
[email protected]00cd9c42010-11-02 20:15:57919 disabled_extensions_.push_back(make_scoped_refptr(extension));
[email protected]1784e83a2009-09-08 21:01:52920 ExtensionList::iterator iter = std::find(extensions_.begin(),
921 extensions_.end(),
922 extension);
923 extensions_.erase(iter);
924
925 ExtensionDOMUI::UnregisterChromeURLOverrides(profile_,
926 extension->GetChromeURLOverrides());
927
[email protected]62d30f42009-10-01 22:36:06928 NotifyExtensionUnloaded(extension);
[email protected]aab98a52009-12-02 03:22:35929 UpdateActiveExtensionsInCrashReporter();
[email protected]1784e83a2009-09-08 21:01:52930}
931
[email protected]9f1087e2009-06-15 17:29:32932void ExtensionsService::LoadExtension(const FilePath& extension_path) {
[email protected]ca4b5fa32010-10-09 12:42:18933 BrowserThread::PostTask(
934 BrowserThread::FILE, FROM_HERE,
[email protected]95d29192009-10-30 01:49:06935 NewRunnableMethod(
936 backend_.get(),
937 &ExtensionsServiceBackend::LoadSingleExtension,
938 extension_path, scoped_refptr<ExtensionsService>(this)));
[email protected]9f1087e2009-06-15 17:29:32939}
940
[email protected]1952c7d2010-03-04 23:48:34941void ExtensionsService::LoadComponentExtensions() {
942 for (RegisteredComponentExtensions::iterator it =
943 component_extension_manifests_.begin();
944 it != component_extension_manifests_.end(); ++it) {
945 JSONStringValueSerializer serializer(it->manifest);
[email protected]ba399672010-04-06 15:42:39946 scoped_ptr<Value> manifest(serializer.Deserialize(NULL, NULL));
[email protected]999731f2010-03-22 19:13:53947 if (!manifest.get()) {
[email protected]a94d57d2010-09-13 22:53:00948 DLOG(ERROR) << "Failed to parse manifest for extension";
[email protected]999731f2010-03-22 19:13:53949 continue;
950 }
[email protected]1952c7d2010-03-04 23:48:34951
[email protected]1952c7d2010-03-04 23:48:34952 std::string error;
[email protected]9adb9692010-10-29 23:14:02953 scoped_refptr<const Extension> extension(Extension::Create(
[email protected]66e4eb32010-10-27 20:37:41954 it->root_directory,
955 Extension::COMPONENT,
956 *static_cast<DictionaryValue*>(manifest.get()),
957 true, // require key
958 &error));
959 if (!extension.get()) {
[email protected]4fdbc1492010-07-01 01:20:59960 NOTREACHED() << error;
[email protected]1952c7d2010-03-04 23:48:34961 return;
962 }
963
[email protected]66e4eb32010-10-27 20:37:41964 OnExtensionLoaded(extension, false); // Don't allow privilege increase.
[email protected]1952c7d2010-03-04 23:48:34965 }
966}
967
[email protected]9f1087e2009-06-15 17:29:32968void ExtensionsService::LoadAllExtensions() {
[email protected]cc2c3432009-11-06 17:24:36969 base::TimeTicks start_time = base::TimeTicks::Now();
970
[email protected]1952c7d2010-03-04 23:48:34971 // Load any component extensions.
972 LoadComponentExtensions();
973
[email protected]e72e8eb82009-06-18 17:21:51974 // Load the previously installed extensions.
[email protected]c6d474f82009-12-16 21:11:06975 scoped_ptr<ExtensionPrefs::ExtensionsInfo> info(
[email protected]e6090e42010-03-23 22:44:08976 extension_prefs_->GetInstalledExtensionsInfo());
[email protected]c6d474f82009-12-16 21:11:06977
978 // If any extensions need localization, we bounce them all to the file thread
979 // for re-reading and localization.
980 for (size_t i = 0; i < info->size(); ++i) {
[email protected]2111b1a2010-03-12 18:12:44981 if (ShouldReloadExtensionManifest(*info->at(i))) {
[email protected]ca4b5fa32010-10-09 12:42:18982 BrowserThread::PostTask(
983 BrowserThread::FILE, FROM_HERE, NewRunnableMethod(
[email protected]c6d474f82009-12-16 21:11:06984 backend_.get(),
[email protected]2111b1a2010-03-12 18:12:44985 &ExtensionsServiceBackend::ReloadExtensionManifests,
[email protected]c6d474f82009-12-16 21:11:06986 info.release(), // Callee takes ownership of the memory.
987 start_time,
988 scoped_refptr<ExtensionsService>(this)));
989 return;
990 }
991 }
992
993 // Don't update prefs.
994 // Callee takes ownership of the memory.
995 ContinueLoadAllExtensions(info.release(), start_time, false);
996}
997
998void ExtensionsService::ContinueLoadAllExtensions(
999 ExtensionPrefs::ExtensionsInfo* extensions_info,
1000 base::TimeTicks start_time,
1001 bool write_to_prefs) {
1002 scoped_ptr<ExtensionPrefs::ExtensionsInfo> info(extensions_info);
1003
1004 for (size_t i = 0; i < info->size(); ++i) {
1005 LoadInstalledExtension(*info->at(i), write_to_prefs);
1006 }
1007
[email protected]ae09ca62009-08-21 19:46:461008 OnLoadedInstalledExtensions();
[email protected]cc2c3432009-11-06 17:24:361009
1010 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAll", extensions_.size());
1011 UMA_HISTOGRAM_COUNTS_100("Extensions.Disabled", disabled_extensions_.size());
1012
[email protected]1952c7d2010-03-04 23:48:341013 UMA_HISTOGRAM_TIMES("Extensions.LoadAllTime",
1014 base::TimeTicks::Now() - start_time);
[email protected]cc2c3432009-11-06 17:24:361015
[email protected]9b217652010-10-08 22:04:231016 int app_count = 0;
1017 int hosted_app_count = 0;
1018 int packaged_app_count = 0;
[email protected]1952c7d2010-03-04 23:48:341019 int user_script_count = 0;
1020 int extension_count = 0;
1021 int theme_count = 0;
1022 int external_count = 0;
1023 int page_action_count = 0;
1024 int browser_action_count = 0;
1025 ExtensionList::iterator ex;
1026 for (ex = extensions_.begin(); ex != extensions_.end(); ++ex) {
[email protected]9b217652010-10-08 22:04:231027 Extension::Location location = (*ex)->location();
1028 Extension::HistogramType type = (*ex)->GetHistogramType();
1029 if ((*ex)->is_app()) {
1030 UMA_HISTOGRAM_ENUMERATION("Extensions.AppLocation",
1031 location, 100);
1032 } else if (type == Extension::TYPE_EXTENSION) {
1033 UMA_HISTOGRAM_ENUMERATION("Extensions.ExtensionLocation",
1034 location, 100);
1035 }
1036
[email protected]1952c7d2010-03-04 23:48:341037 // Don't count component extensions, since they are only extensions as an
1038 // implementation detail.
[email protected]9b217652010-10-08 22:04:231039 if (location == Extension::COMPONENT)
[email protected]1952c7d2010-03-04 23:48:341040 continue;
1041
[email protected]e8c729a2010-03-09 19:55:191042 // Don't count unpacked extensions, since they're a developer-specific
1043 // feature.
[email protected]9b217652010-10-08 22:04:231044 if (location == Extension::LOAD)
[email protected]e8c729a2010-03-09 19:55:191045 continue;
1046
[email protected]9b217652010-10-08 22:04:231047 // Using an enumeration shows us the total installed ratio across all users.
1048 // Using the totals per user at each startup tells us the distribution of
1049 // usage for each user (e.g. 40% of users have at least one app installed).
1050 UMA_HISTOGRAM_ENUMERATION("Extensions.LoadType", type, 100);
1051 switch (type) {
1052 case Extension::TYPE_THEME:
1053 theme_count++;
1054 break;
1055 case Extension::TYPE_USER_SCRIPT:
1056 user_script_count++;
1057 break;
1058 case Extension::TYPE_HOSTED_APP:
1059 app_count++;
1060 hosted_app_count++;
1061 break;
1062 case Extension::TYPE_PACKAGED_APP:
1063 app_count++;
1064 packaged_app_count++;
1065 break;
1066 case Extension::TYPE_EXTENSION:
1067 default:
1068 extension_count++;
1069 break;
[email protected]cc2c3432009-11-06 17:24:361070 }
[email protected]9b217652010-10-08 22:04:231071 if (Extension::IsExternalLocation(location))
[email protected]1952c7d2010-03-04 23:48:341072 external_count++;
[email protected]9b217652010-10-08 22:04:231073 if ((*ex)->page_action() != NULL)
[email protected]1952c7d2010-03-04 23:48:341074 page_action_count++;
[email protected]9b217652010-10-08 22:04:231075 if ((*ex)->browser_action() != NULL)
[email protected]1952c7d2010-03-04 23:48:341076 browser_action_count++;
[email protected]cc2c3432009-11-06 17:24:361077 }
[email protected]9b217652010-10-08 22:04:231078 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadApp", app_count);
1079 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadHostedApp", hosted_app_count);
1080 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPackagedApp", packaged_app_count);
[email protected]1952c7d2010-03-04 23:48:341081 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtension", extension_count);
1082 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadUserScript", user_script_count);
1083 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadTheme", theme_count);
1084 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExternal", external_count);
1085 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPageAction", page_action_count);
1086 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadBrowserAction",
1087 browser_action_count);
[email protected]ae09ca62009-08-21 19:46:461088}
1089
[email protected]c6d474f82009-12-16 21:11:061090void ExtensionsService::LoadInstalledExtension(const ExtensionInfo& info,
1091 bool write_to_prefs) {
[email protected]ae09ca62009-08-21 19:46:461092 std::string error;
[email protected]9adb9692010-10-29 23:14:021093 scoped_refptr<const Extension> extension(NULL);
[email protected]306a2bd2010-08-11 14:56:361094 if (!extension_prefs_->IsExtensionAllowedByPolicy(info.extension_id)) {
1095 error = errors::kDisabledByPolicy;
1096 } else if (info.extension_manifest.get()) {
[email protected]e8c729a2010-03-09 19:55:191097 bool require_key = info.extension_location != Extension::LOAD;
[email protected]66e4eb32010-10-27 20:37:411098 extension = Extension::Create(
1099 info.extension_path, info.extension_location, *info.extension_manifest,
1100 require_key, &error);
[email protected]ae09ca62009-08-21 19:46:461101 } else {
[email protected]c6d474f82009-12-16 21:11:061102 error = errors::kManifestUnreadable;
[email protected]ae09ca62009-08-21 19:46:461103 }
1104
1105 if (!extension) {
[email protected]c6d474f82009-12-16 21:11:061106 ReportExtensionLoadError(info.extension_path,
[email protected]d11c8e92009-10-20 23:26:401107 error,
1108 NotificationType::EXTENSION_INSTALL_ERROR,
1109 false);
[email protected]ae09ca62009-08-21 19:46:461110 return;
1111 }
1112
[email protected]c6d474f82009-12-16 21:11:061113 if (write_to_prefs)
1114 extension_prefs_->UpdateManifest(extension);
1115
[email protected]2a409532009-08-28 19:39:441116 OnExtensionLoaded(extension, true);
[email protected]ae09ca62009-08-21 19:46:461117
[email protected]55196e92010-09-29 15:04:461118 if (Extension::IsExternalLocation(info.extension_location)) {
[email protected]ca4b5fa32010-10-09 12:42:181119 BrowserThread::PostTask(
1120 BrowserThread::FILE, FROM_HERE,
[email protected]95d29192009-10-30 01:49:061121 NewRunnableMethod(
[email protected]f17dbd42010-08-16 23:21:101122 backend_.get(),
1123 &ExtensionsServiceBackend::CheckExternalUninstall,
1124 scoped_refptr<ExtensionsService>(this),
[email protected]0a60a2e2010-10-25 16:15:211125 info.extension_id));
[email protected]ae09ca62009-08-21 19:46:461126 }
[email protected]9f1087e2009-06-15 17:29:321127}
1128
[email protected]9adb9692010-10-29 23:14:021129void ExtensionsService::NotifyExtensionLoaded(const Extension* extension) {
[email protected]57a777f72010-03-31 01:09:421130 // The ChromeURLRequestContexts need to be first to know that the extension
[email protected]62d30f42009-10-01 22:36:061131 // was loaded, otherwise a race can arise where a renderer that is created
1132 // for the extension may try to load an extension URL with an extension id
[email protected]57a777f72010-03-31 01:09:421133 // that the request context doesn't yet know about. The profile is responsible
1134 // for ensuring its URLRequestContexts appropriately discover the loaded
1135 // extension.
1136 if (profile_) {
1137 profile_->RegisterExtensionWithRequestContexts(extension);
[email protected]24b538a2010-02-27 01:22:441138
1139 // Check if this permission requires unlimited storage quota
[email protected]c2c263c2010-08-13 21:59:481140 if (extension->HasApiPermission(Extension::kUnlimitedStoragePermission))
1141 GrantUnlimitedStorage(extension);
[email protected]654512b2010-09-01 02:09:421142
1143 // If the extension is an app, protect its local storage from
1144 // "Clear browsing data."
1145 if (extension->is_app())
1146 GrantProtectedStorage(extension);
[email protected]62d30f42009-10-01 22:36:061147 }
1148
1149 NotificationService::current()->Notify(
1150 NotificationType::EXTENSION_LOADED,
[email protected]24e7a9d2009-11-04 11:11:341151 Source<Profile>(profile_),
[email protected]9adb9692010-10-29 23:14:021152 Details<const Extension>(extension));
[email protected]62d30f42009-10-01 22:36:061153}
1154
[email protected]9adb9692010-10-29 23:14:021155void ExtensionsService::NotifyExtensionUnloaded(const Extension* extension) {
[email protected]62d30f42009-10-01 22:36:061156 NotificationService::current()->Notify(
1157 NotificationType::EXTENSION_UNLOADED,
[email protected]24e7a9d2009-11-04 11:11:341158 Source<Profile>(profile_),
[email protected]9adb9692010-10-29 23:14:021159 Details<const Extension>(extension));
[email protected]62d30f42009-10-01 22:36:061160
[email protected]57a777f72010-03-31 01:09:421161 if (profile_) {
1162 profile_->UnregisterExtensionWithRequestContexts(extension);
1163
1164 // Check if this permission required unlimited storage quota, reset its
1165 // in-memory quota.
[email protected]c2c263c2010-08-13 21:59:481166 if (extension->HasApiPermission(Extension::kUnlimitedStoragePermission))
1167 RevokeUnlimitedStorage(extension);
[email protected]654512b2010-09-01 02:09:421168
1169 // If this is an app, then stop protecting its storage so it can be deleted.
1170 if (extension->is_app())
1171 RevokeProtectedStorage(extension);
1172 }
1173}
1174
[email protected]9adb9692010-10-29 23:14:021175void ExtensionsService::GrantProtectedStorage(const Extension* extension) {
[email protected]654512b2010-09-01 02:09:421176 DCHECK(extension->is_app()) << "Only Apps are allowed protected storage.";
1177 std::vector<GURL> origins;
1178 GetExplicitOriginsInExtent(extension, &origins);
1179 for (size_t i = 0; i < origins.size(); ++i)
1180 ++protected_storage_map_[origins[i]];
1181}
1182
[email protected]9adb9692010-10-29 23:14:021183void ExtensionsService::RevokeProtectedStorage(const Extension* extension) {
[email protected]654512b2010-09-01 02:09:421184 DCHECK(extension->is_app()) << "Attempting to revoke protected storage from "
1185 << " a non-app extension.";
1186 std::vector<GURL> origins;
1187 GetExplicitOriginsInExtent(extension, &origins);
1188 for (size_t i = 0; i < origins.size(); ++i) {
1189 const GURL& origin = origins[i];
1190 DCHECK(protected_storage_map_[origin] > 0);
1191 if (--protected_storage_map_[origin] <= 0)
1192 protected_storage_map_.erase(origin);
[email protected]c2c263c2010-08-13 21:59:481193 }
1194}
1195
[email protected]9adb9692010-10-29 23:14:021196void ExtensionsService::GrantUnlimitedStorage(const Extension* extension) {
[email protected]c2c263c2010-08-13 21:59:481197 DCHECK(extension->HasApiPermission(Extension::kUnlimitedStoragePermission));
1198 std::vector<GURL> origins;
1199 GetExplicitOriginsInExtent(extension, &origins);
1200 origins.push_back(extension->url());
1201
1202 for (size_t i = 0; i < origins.size(); ++i) {
1203 const GURL& origin = origins[i];
1204 if (++unlimited_storage_map_[origin] == 1) {
[email protected]57a777f72010-03-31 01:09:421205 string16 origin_identifier =
[email protected]c2c263c2010-08-13 21:59:481206 webkit_database::DatabaseUtil::GetOriginIdentifier(origin);
[email protected]ca4b5fa32010-10-09 12:42:181207 BrowserThread::PostTask(
1208 BrowserThread::FILE, FROM_HERE,
[email protected]c2c263c2010-08-13 21:59:481209 NewRunnableMethod(
1210 profile_->GetDatabaseTracker(),
1211 &webkit_database::DatabaseTracker::SetOriginQuotaInMemory,
1212 origin_identifier,
1213 kint64max));
[email protected]ca4b5fa32010-10-09 12:42:181214 BrowserThread::PostTask(
1215 BrowserThread::IO, FROM_HERE,
[email protected]c2c263c2010-08-13 21:59:481216 NewRunnableMethod(
1217 profile_->GetAppCacheService(),
1218 &ChromeAppCacheService::SetOriginQuotaInMemory,
1219 origin,
1220 kint64max));
[email protected]ca4b5fa32010-10-09 12:42:181221 BrowserThread::PostTask(
1222 BrowserThread::IO, FROM_HERE,
[email protected]70c6c042010-10-08 09:52:071223 NewRunnableMethod(
1224 profile_->GetFileSystemHostContext(),
1225 &FileSystemHostContext::SetOriginQuotaUnlimited,
1226 origin));
[email protected]c2c263c2010-08-13 21:59:481227 }
1228 }
1229}
1230
[email protected]9adb9692010-10-29 23:14:021231void ExtensionsService::RevokeUnlimitedStorage(const Extension* extension) {
[email protected]c2c263c2010-08-13 21:59:481232 DCHECK(extension->HasApiPermission(Extension::kUnlimitedStoragePermission));
1233 std::vector<GURL> origins;
1234 GetExplicitOriginsInExtent(extension, &origins);
1235 origins.push_back(extension->url());
1236
1237 for (size_t i = 0; i < origins.size(); ++i) {
1238 const GURL& origin = origins[i];
1239 DCHECK(unlimited_storage_map_[origin] > 0);
1240 if (--unlimited_storage_map_[origin] == 0) {
1241 unlimited_storage_map_.erase(origin);
1242 string16 origin_identifier =
1243 webkit_database::DatabaseUtil::GetOriginIdentifier(origin);
[email protected]ca4b5fa32010-10-09 12:42:181244 BrowserThread::PostTask(
1245 BrowserThread::FILE, FROM_HERE,
[email protected]be180c802009-10-23 06:33:311246 NewRunnableMethod(
[email protected]57a777f72010-03-31 01:09:421247 profile_->GetDatabaseTracker(),
1248 &webkit_database::DatabaseTracker::ResetOriginQuotaInMemory,
1249 origin_identifier));
[email protected]ca4b5fa32010-10-09 12:42:181250 BrowserThread::PostTask(
1251 BrowserThread::IO, FROM_HERE,
[email protected]c2c263c2010-08-13 21:59:481252 NewRunnableMethod(
1253 profile_->GetAppCacheService(),
1254 &ChromeAppCacheService::ResetOriginQuotaInMemory,
1255 origin));
[email protected]ca4b5fa32010-10-09 12:42:181256 BrowserThread::PostTask(
1257 BrowserThread::IO, FROM_HERE,
[email protected]70c6c042010-10-08 09:52:071258 NewRunnableMethod(
1259 profile_->GetFileSystemHostContext(),
1260 &FileSystemHostContext::ResetOriginQuotaUnlimited,
1261 origin));
[email protected]62d30f42009-10-01 22:36:061262 }
1263 }
1264}
1265
[email protected]6b75ec32009-08-14 06:37:181266void ExtensionsService::UpdateExtensionBlacklist(
1267 const std::vector<std::string>& blacklist) {
1268 // Use this set to indicate if an extension in the blacklist has been used.
1269 std::set<std::string> blacklist_set;
1270 for (unsigned int i = 0; i < blacklist.size(); ++i) {
1271 if (Extension::IdIsValid(blacklist[i])) {
1272 blacklist_set.insert(blacklist[i]);
1273 }
1274 }
1275 extension_prefs_->UpdateBlacklist(blacklist_set);
1276 std::vector<std::string> to_be_removed;
1277 // Loop current extensions, unload installed extensions.
1278 for (ExtensionList::const_iterator iter = extensions_.begin();
1279 iter != extensions_.end(); ++iter) {
[email protected]9adb9692010-10-29 23:14:021280 const Extension* extension = (*iter);
[email protected]6b75ec32009-08-14 06:37:181281 if (blacklist_set.find(extension->id()) != blacklist_set.end()) {
1282 to_be_removed.push_back(extension->id());
1283 }
1284 }
1285
1286 // UnloadExtension will change the extensions_ list. So, we should
1287 // call it outside the iterator loop.
1288 for (unsigned int i = 0; i < to_be_removed.size(); ++i) {
1289 UnloadExtension(to_be_removed[i]);
1290 }
1291}
1292
[email protected]aa96d3a2010-08-21 08:45:251293void ExtensionsService::DestroyingProfile() {
[email protected]2fb7dc982010-09-29 12:24:281294 pref_change_registrar_.RemoveAll();
[email protected]aa96d3a2010-08-21 08:45:251295 profile_ = NULL;
[email protected]2fb7dc982010-09-29 12:24:281296 toolbar_model_.DestroyingProfile();
[email protected]aa96d3a2010-08-21 08:45:251297}
1298
1299void ExtensionsService::CheckAdminBlacklist() {
1300 std::vector<std::string> to_be_removed;
1301 // Loop through extensions list, unload installed extensions.
1302 for (ExtensionList::const_iterator iter = extensions_.begin();
1303 iter != extensions_.end(); ++iter) {
[email protected]9adb9692010-10-29 23:14:021304 const Extension* extension = (*iter);
[email protected]aa96d3a2010-08-21 08:45:251305 if (!extension_prefs_->IsExtensionAllowedByPolicy(extension->id()))
1306 to_be_removed.push_back(extension->id());
1307 }
1308
1309 // UnloadExtension will change the extensions_ list. So, we should
1310 // call it outside the iterator loop.
1311 for (unsigned int i = 0; i < to_be_removed.size(); ++i)
1312 UnloadExtension(to_be_removed[i]);
1313}
1314
[email protected]cb0ce1e022010-03-10 19:54:411315bool ExtensionsService::IsIncognitoEnabled(const Extension* extension) {
1316 // If this is a component extension we always allow it to work in incognito
1317 // mode.
1318 if (extension->location() == Extension::COMPONENT)
1319 return true;
1320
1321 // Check the prefs.
1322 return extension_prefs_->IsIncognitoEnabled(extension->id());
[email protected]db7331a2010-02-25 22:10:501323}
[email protected]55a35692010-02-11 23:25:211324
[email protected]9adb9692010-10-29 23:14:021325void ExtensionsService::SetIsIncognitoEnabled(const Extension* extension,
[email protected]db7331a2010-02-25 22:10:501326 bool enabled) {
[email protected]cb0ce1e022010-03-10 19:54:411327 extension_prefs_->SetIsIncognitoEnabled(extension->id(), enabled);
[email protected]c1499f3d2010-03-05 00:33:241328
[email protected]568f33d2010-08-04 17:06:411329 // Broadcast unloaded and loaded events to update browser state. Only bother
1330 // if the extension is actually enabled, since there is no UI otherwise.
1331 bool is_enabled = std::find(extensions_.begin(), extensions_.end(),
1332 extension) != extensions_.end();
1333 if (is_enabled) {
1334 NotifyExtensionUnloaded(extension);
1335 NotifyExtensionLoaded(extension);
1336 }
[email protected]55a35692010-02-11 23:25:211337}
1338
[email protected]05c82182010-06-24 17:49:081339bool ExtensionsService::AllowFileAccess(const Extension* extension) {
1340 return (CommandLine::ForCurrentProcess()->HasSwitch(
[email protected]334e04a2010-06-24 23:34:441341 switches::kDisableExtensionsFileAccessCheck) ||
[email protected]05c82182010-06-24 17:49:081342 extension_prefs_->AllowFileAccess(extension->id()));
1343}
1344
[email protected]9adb9692010-10-29 23:14:021345void ExtensionsService::SetAllowFileAccess(const Extension* extension,
1346 bool allow) {
[email protected]05c82182010-06-24 17:49:081347 extension_prefs_->SetAllowFileAccess(extension->id(), allow);
1348 NotificationService::current()->Notify(
1349 NotificationType::EXTENSION_USER_SCRIPTS_UPDATED,
1350 Source<Profile>(profile_),
[email protected]9adb9692010-10-29 23:14:021351 Details<const Extension>(extension));
[email protected]05c82182010-06-24 17:49:081352}
1353
[email protected]93fd78f42009-07-10 16:43:171354void ExtensionsService::CheckForExternalUpdates() {
[email protected]9f1087e2009-06-15 17:29:321355 // This installs or updates externally provided extensions.
[email protected]7577a5c52009-07-30 06:21:581356 // TODO(aa): Why pass this list into the provider, why not just filter it
1357 // later?
[email protected]9f1087e2009-06-15 17:29:321358 std::set<std::string> killed_extensions;
[email protected]e72e8eb82009-06-18 17:21:511359 extension_prefs_->GetKilledExtensionIds(&killed_extensions);
[email protected]ca4b5fa32010-10-09 12:42:181360 BrowserThread::PostTask(
1361 BrowserThread::FILE, FROM_HERE,
[email protected]95d29192009-10-30 01:49:061362 NewRunnableMethod(
1363 backend_.get(), &ExtensionsServiceBackend::CheckForExternalUpdates,
1364 killed_extensions, scoped_refptr<ExtensionsService>(this)));
[email protected]9f1087e2009-06-15 17:29:321365}
1366
1367void ExtensionsService::UnloadExtension(const std::string& extension_id) {
[email protected]27e469a2010-01-11 20:35:091368 // Make sure the extension gets deleted after we return from this function.
[email protected]9adb9692010-10-29 23:14:021369 scoped_refptr<const Extension> extension(
[email protected]0c6da502009-08-14 22:32:391370 GetExtensionByIdInternal(extension_id, true, true));
[email protected]631cf822009-05-15 07:01:251371
[email protected]e7afe2452010-08-22 16:19:131372 // Callers should not send us nonexistent extensions.
[email protected]0c6da502009-08-14 22:32:391373 CHECK(extension.get());
1374
[email protected]1eb175082010-02-10 09:26:161375 // Keep information about the extension so that we can reload it later
1376 // even if it's not permanently installed.
1377 unloaded_extension_paths_[extension->id()] = extension->path();
1378
[email protected]f17dbd42010-08-16 23:21:101379 // Clean up if the extension is meant to be enabled after a reload.
1380 disabled_extension_paths_.erase(extension->id());
1381
[email protected]86c008e82009-08-28 20:26:051382 ExtensionDOMUI::UnregisterChromeURLOverrides(profile_,
1383 extension->GetChromeURLOverrides());
1384
[email protected]0c6da502009-08-14 22:32:391385 ExtensionList::iterator iter = std::find(disabled_extensions_.begin(),
1386 disabled_extensions_.end(),
1387 extension.get());
1388 if (iter != disabled_extensions_.end()) {
[email protected]0c6da502009-08-14 22:32:391389 disabled_extensions_.erase(iter);
[email protected]866930682009-08-18 22:53:471390 NotificationService::current()->Notify(
1391 NotificationType::EXTENSION_UNLOADED_DISABLED,
[email protected]24e7a9d2009-11-04 11:11:341392 Source<Profile>(profile_),
[email protected]9adb9692010-10-29 23:14:021393 Details<const Extension>(extension.get()));
[email protected]0c6da502009-08-14 22:32:391394 return;
1395 }
1396
1397 iter = std::find(extensions_.begin(), extensions_.end(), extension.get());
[email protected]894bb502009-05-21 22:39:571398
[email protected]631cf822009-05-15 07:01:251399 // Remove the extension from our list.
1400 extensions_.erase(iter);
1401
[email protected]62d30f42009-10-01 22:36:061402 NotifyExtensionUnloaded(extension.get());
[email protected]aab98a52009-12-02 03:22:351403 UpdateActiveExtensionsInCrashReporter();
[email protected]631cf822009-05-15 07:01:251404}
1405
[email protected]9f1087e2009-06-15 17:29:321406void ExtensionsService::UnloadAllExtensions() {
[email protected]9f1087e2009-06-15 17:29:321407 extensions_.clear();
[email protected]cd500f72010-06-25 23:44:321408 disabled_extensions_.clear();
1409
[email protected]c6e4a3412009-06-24 15:45:291410 // TODO(erikkay) should there be a notification for this? We can't use
1411 // EXTENSION_UNLOADED since that implies that the extension has been disabled
1412 // or uninstalled, and UnloadAll is just part of shutdown.
[email protected]9f1087e2009-06-15 17:29:321413}
1414
1415void ExtensionsService::ReloadExtensions() {
1416 UnloadAllExtensions();
1417 LoadAllExtensions();
1418}
1419
1420void ExtensionsService::GarbageCollectExtensions() {
[email protected]ba399672010-04-06 15:42:391421 if (extension_prefs_->pref_service()->read_only())
1422 return;
1423
[email protected]ca3dbf52010-05-19 22:27:061424 scoped_ptr<ExtensionPrefs::ExtensionsInfo> info(
1425 extension_prefs_->GetInstalledExtensionsInfo());
1426
1427 std::map<std::string, FilePath> extension_paths;
1428 for (size_t i = 0; i < info->size(); ++i)
1429 extension_paths[info->at(i)->extension_id] = info->at(i)->extension_path;
1430
[email protected]ca4b5fa32010-10-09 12:42:181431 BrowserThread::PostTask(
1432 BrowserThread::FILE, FROM_HERE,
[email protected]95d29192009-10-30 01:49:061433 NewRunnableFunction(
1434 &extension_file_util::GarbageCollectExtensions, install_directory_,
[email protected]ca3dbf52010-05-19 22:27:061435 extension_paths));
[email protected]3cf4f0992009-02-03 23:00:301436}
1437
[email protected]e72e8eb82009-06-18 17:21:511438void ExtensionsService::OnLoadedInstalledExtensions() {
[email protected]e81dba32009-06-19 20:19:131439 ready_ = true;
[email protected]93fd78f42009-07-10 16:43:171440 if (updater_.get()) {
1441 updater_->Start();
1442 }
[email protected]e72e8eb82009-06-18 17:21:511443 NotificationService::current()->Notify(
1444 NotificationType::EXTENSIONS_READY,
[email protected]24e7a9d2009-11-04 11:11:341445 Source<Profile>(profile_),
[email protected]e72e8eb82009-06-18 17:21:511446 NotificationService::NoDetails());
1447}
1448
[email protected]9adb9692010-10-29 23:14:021449void ExtensionsService::OnExtensionLoaded(const Extension* extension,
[email protected]2a409532009-08-28 19:39:441450 bool allow_privilege_increase) {
[email protected]ae09ca62009-08-21 19:46:461451 // Ensure extension is deleted unless we transfer ownership.
[email protected]9adb9692010-10-29 23:14:021452 scoped_refptr<const Extension> scoped_extension(extension);
[email protected]9f1087e2009-06-15 17:29:321453
[email protected]1eb175082010-02-10 09:26:161454 // The extension is now loaded, remove its data from unloaded extension map.
1455 unloaded_extension_paths_.erase(extension->id());
1456
[email protected]f17dbd42010-08-16 23:21:101457 // If the extension was disabled for a reload, then enable it.
1458 if (disabled_extension_paths_.erase(extension->id()) > 0)
1459 EnableExtension(extension->id());
1460
[email protected]ceefd3d2010-03-12 09:10:291461 // TODO(aa): Need to re-evaluate this branch. Does this still make sense now
1462 // that extensions are enabled by default?
[email protected]ae09ca62009-08-21 19:46:461463 if (extensions_enabled() ||
[email protected]3ba0fd32010-06-19 05:39:101464 extension->is_theme() ||
[email protected]ae09ca62009-08-21 19:46:461465 extension->location() == Extension::LOAD ||
[email protected]f0b97f12010-10-11 21:44:351466 extension->location() == Extension::COMPONENT ||
[email protected]ae09ca62009-08-21 19:46:461467 Extension::IsExternalLocation(extension->location())) {
[email protected]9adb9692010-10-29 23:14:021468 const Extension* old = GetExtensionByIdInternal(extension->id(),
1469 true, true);
[email protected]ae09ca62009-08-21 19:46:461470 if (old) {
[email protected]ca3dbf52010-05-19 22:27:061471 // CrxInstaller should have guaranteed that we aren't downgrading.
1472 CHECK(extension->version()->CompareTo(*(old->version())) >= 0);
[email protected]0c6da502009-08-14 22:32:391473
[email protected]ca3dbf52010-05-19 22:27:061474 bool allow_silent_upgrade =
1475 allow_privilege_increase || !Extension::IsPrivilegeIncrease(
1476 old, extension);
[email protected]1e8c93f2010-02-08 22:58:311477
[email protected]ca3dbf52010-05-19 22:27:061478 // Extensions get upgraded if silent upgrades are allowed, otherwise
1479 // they get disabled.
1480 if (allow_silent_upgrade) {
1481 old->set_being_upgraded(true);
1482 extension->set_being_upgraded(true);
1483 }
[email protected]0c6da502009-08-14 22:32:391484
[email protected]ca3dbf52010-05-19 22:27:061485 // To upgrade an extension in place, unload the old one and
1486 // then load the new one.
1487 UnloadExtension(old->id());
1488 old = NULL;
1489
1490 if (!allow_silent_upgrade) {
1491 // Extension has changed permissions significantly. Disable it. We
1492 // send a notification below.
1493 extension_prefs_->SetExtensionState(extension, Extension::DISABLED);
1494 extension_prefs_->SetDidExtensionEscalatePermissions(extension, true);
[email protected]0c6da502009-08-14 22:32:391495 }
[email protected]ba74f352009-06-11 18:54:451496 }
[email protected]86a274072009-06-11 02:06:451497
[email protected]ae09ca62009-08-21 19:46:461498 switch (extension_prefs_->GetExtensionState(extension->id())) {
1499 case Extension::ENABLED:
[email protected]66e4eb32010-10-27 20:37:411500 extensions_.push_back(scoped_extension);
[email protected]ae09ca62009-08-21 19:46:461501
[email protected]62d30f42009-10-01 22:36:061502 NotifyExtensionLoaded(extension);
[email protected]ae09ca62009-08-21 19:46:461503
[email protected]e8c729a2010-03-09 19:55:191504 ExtensionDOMUI::RegisterChromeURLOverrides(profile_,
1505 extension->GetChromeURLOverrides());
[email protected]ae09ca62009-08-21 19:46:461506 break;
1507 case Extension::DISABLED:
[email protected]66e4eb32010-10-27 20:37:411508 disabled_extensions_.push_back(scoped_extension);
[email protected]d11c8e92009-10-20 23:26:401509 NotificationService::current()->Notify(
1510 NotificationType::EXTENSION_UPDATE_DISABLED,
[email protected]24e7a9d2009-11-04 11:11:341511 Source<Profile>(profile_),
[email protected]9adb9692010-10-29 23:14:021512 Details<const Extension>(extension));
[email protected]ae09ca62009-08-21 19:46:461513 break;
1514 default:
[email protected]d11c8e92009-10-20 23:26:401515 NOTREACHED();
[email protected]ae09ca62009-08-21 19:46:461516 break;
[email protected]811f3432009-07-25 19:38:211517 }
[email protected]e72e8eb82009-06-18 17:21:511518 }
[email protected]aab98a52009-12-02 03:22:351519
[email protected]1e8c93f2010-02-08 22:58:311520 extension->set_being_upgraded(false);
1521
[email protected]aab98a52009-12-02 03:22:351522 UpdateActiveExtensionsInCrashReporter();
[email protected]0b004da2010-07-02 17:54:311523
1524 if (profile_->GetTemplateURLModel())
1525 profile_->GetTemplateURLModel()->RegisterExtensionKeyword(extension);
[email protected]b671760b2010-07-15 21:13:471526
1527 // Load the icon for omnibox-enabled extensions so it will be ready to display
1528 // in the URL bar.
[email protected]29d0d4ac2010-09-08 21:10:311529 if (!extension->omnibox_keyword().empty()) {
1530 omnibox_popup_icon_manager_.LoadIcon(extension);
[email protected]b671760b2010-07-15 21:13:471531 omnibox_icon_manager_.LoadIcon(extension);
[email protected]29d0d4ac2010-09-08 21:10:311532 }
[email protected]aab98a52009-12-02 03:22:351533}
1534
1535void ExtensionsService::UpdateActiveExtensionsInCrashReporter() {
[email protected]c8865962009-12-16 07:47:391536 std::set<std::string> extension_ids;
[email protected]aab98a52009-12-02 03:22:351537 for (size_t i = 0; i < extensions_.size(); ++i) {
[email protected]3ba0fd32010-06-19 05:39:101538 if (!extensions_[i]->is_theme())
[email protected]c8865962009-12-16 07:47:391539 extension_ids.insert(extensions_[i]->id());
[email protected]aab98a52009-12-02 03:22:351540 }
1541
1542 child_process_logging::SetActiveExtensions(extension_ids);
[email protected]6014d672008-12-05 00:38:251543}
1544
[email protected]9adb9692010-10-29 23:14:021545void ExtensionsService::OnExtensionInstalled(const Extension* extension,
[email protected]2a409532009-08-28 19:39:441546 bool allow_privilege_increase) {
[email protected]a8af9fdb2010-10-28 21:52:201547 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1548
[email protected]4416c5a2010-06-26 01:28:571549 // Ensure extension is deleted unless we transfer ownership.
[email protected]9adb9692010-10-29 23:14:021550 scoped_refptr<const Extension> scoped_extension(extension);
[email protected]4416c5a2010-06-26 01:28:571551 Extension::State initial_state = Extension::DISABLED;
1552 bool initial_enable_incognito = false;
[email protected]aa142702010-03-26 01:26:331553 PendingExtensionMap::iterator it =
1554 pending_extensions_.find(extension->id());
[email protected]4416c5a2010-06-26 01:28:571555 if (it != pending_extensions_.end()) {
[email protected]11edd1e2010-07-21 00:14:501556 PendingExtensionInfo pending_extension_info = it->second;
[email protected]8ef78fd2010-08-19 17:14:321557 PendingExtensionInfo::ExpectedCrxType expected_crx_type =
1558 pending_extension_info.expected_crx_type;
1559 bool is_from_sync = pending_extension_info.is_from_sync;
[email protected]11edd1e2010-07-21 00:14:501560 pending_extensions_.erase(it);
1561 it = pending_extensions_.end();
[email protected]8ef78fd2010-08-19 17:14:321562
[email protected]4416c5a2010-06-26 01:28:571563 // Set initial state from pending extension data.
[email protected]8ef78fd2010-08-19 17:14:321564 PendingExtensionInfo::ExpectedCrxType actual_crx_type =
[email protected]ec5b50d2010-10-09 16:35:181565 PendingExtensionInfo::EXTENSION;
1566 if (extension->is_app())
1567 actual_crx_type = PendingExtensionInfo::APP;
1568 else if (extension->is_theme())
1569 actual_crx_type = PendingExtensionInfo::THEME;
[email protected]8ef78fd2010-08-19 17:14:321570
1571 if (expected_crx_type != PendingExtensionInfo::UNKNOWN &&
1572 expected_crx_type != actual_crx_type) {
[email protected]4416c5a2010-06-26 01:28:571573 LOG(WARNING)
1574 << "Not installing pending extension " << extension->id()
[email protected]8ef78fd2010-08-19 17:14:321575 << " with is_theme = " << extension->is_theme();
[email protected]4416c5a2010-06-26 01:28:571576 // Delete the extension directory since we're not going to
1577 // load it.
[email protected]ca4b5fa32010-10-09 12:42:181578 BrowserThread::PostTask(
1579 BrowserThread::FILE, FROM_HERE,
[email protected]4416c5a2010-06-26 01:28:571580 NewRunnableFunction(&DeleteFileHelper, extension->path(), true));
1581 return;
1582 }
[email protected]8ef78fd2010-08-19 17:14:321583
1584 // If |extension| is not syncable, and was installed via sync, disallow
1585 // the instanation.
1586 //
1587 // Themes are always allowed. Because they contain no active code, they
1588 // are less of a risk than extensions.
1589 //
1590 // If |is_from_sync| is false, then the install was not initiated by sync,
1591 // and this check should pass. Extensions that were installed from an
1592 // update URL in external_extensions.json are an example. They are not
1593 // syncable, because the user did not make an explicit choice to install
1594 // them. However, they were installed through the update mechanism, so
1595 // control must pass into this function.
1596 //
1597 // TODO(akalin): When we do apps sync, we have to work with its
1598 // traits, too.
[email protected]2a3e22b12010-08-13 04:55:171599 const browser_sync::ExtensionSyncTraits extension_sync_traits =
1600 browser_sync::GetExtensionSyncTraits();
[email protected]06e33202010-08-16 23:45:151601 const browser_sync::ExtensionSyncTraits app_sync_traits =
1602 browser_sync::GetAppSyncTraits();
[email protected]2a3e22b12010-08-13 04:55:171603 // If an extension is a theme, we bypass the valid/syncable check
1604 // as themes are harmless.
[email protected]8ef78fd2010-08-19 17:14:321605 if (!extension->is_theme() && is_from_sync &&
[email protected]2a3e22b12010-08-13 04:55:171606 !browser_sync::IsExtensionValidAndSyncable(
[email protected]06e33202010-08-16 23:45:151607 *extension, extension_sync_traits.allowed_extension_types) &&
1608 !browser_sync::IsExtensionValidAndSyncable(
1609 *extension, app_sync_traits.allowed_extension_types)) {
[email protected]11edd1e2010-07-21 00:14:501610 // We're an extension installed via sync that is unsyncable,
1611 // i.e. we may have been syncable previously. We block these
1612 // installs. We'll have to update the clause above if we decide
1613 // to sync other extension-like things, like apps or user
1614 // scripts.
1615 //
1616 // Note that this creates a small window where a user who tries
1617 // to download/install an extension that is simultaneously
1618 // installed via sync (and blocked) will find his download
1619 // blocked.
1620 //
1621 // TODO(akalin): Remove this check once we've put in UI to
1622 // approve synced extensions.
1623 LOG(WARNING)
[email protected]2a3e22b12010-08-13 04:55:171624 << "Not installing invalid or unsyncable extension "
1625 << extension->id();
[email protected]11edd1e2010-07-21 00:14:501626 // Delete the extension directory since we're not going to
1627 // load it.
[email protected]ca4b5fa32010-10-09 12:42:181628 BrowserThread::PostTask(
1629 BrowserThread::FILE, FROM_HERE,
[email protected]11edd1e2010-07-21 00:14:501630 NewRunnableFunction(&DeleteFileHelper, extension->path(), true));
1631 return;
1632 }
[email protected]8ef78fd2010-08-19 17:14:321633 if (extension->is_theme()) {
[email protected]11edd1e2010-07-21 00:14:501634 DCHECK(pending_extension_info.enable_on_install);
[email protected]4416c5a2010-06-26 01:28:571635 initial_state = Extension::ENABLED;
[email protected]11edd1e2010-07-21 00:14:501636 DCHECK(!pending_extension_info.enable_incognito_on_install);
[email protected]4416c5a2010-06-26 01:28:571637 initial_enable_incognito = false;
1638 } else {
1639 initial_state =
[email protected]11edd1e2010-07-21 00:14:501640 pending_extension_info.enable_on_install ?
[email protected]4416c5a2010-06-26 01:28:571641 Extension::ENABLED : Extension::DISABLED;
1642 initial_enable_incognito =
[email protected]11edd1e2010-07-21 00:14:501643 pending_extension_info.enable_incognito_on_install;
[email protected]4416c5a2010-06-26 01:28:571644 }
[email protected]4416c5a2010-06-26 01:28:571645 } else {
[email protected]dbec3792010-08-10 00:08:451646 // Make sure we preserve enabled/disabled states.
[email protected]4416c5a2010-06-26 01:28:571647 Extension::State existing_state =
1648 extension_prefs_->GetExtensionState(extension->id());
1649 initial_state =
1650 (existing_state == Extension::DISABLED) ?
1651 Extension::DISABLED : Extension::ENABLED;
[email protected]dbec3792010-08-10 00:08:451652 initial_enable_incognito =
1653 extension_prefs_->IsIncognitoEnabled(extension->id());
[email protected]aa142702010-03-26 01:26:331654 }
1655
[email protected]9b217652010-10-08 22:04:231656 UMA_HISTOGRAM_ENUMERATION("Extensions.InstallType",
1657 extension->GetHistogramType(), 100);
[email protected]4416c5a2010-06-26 01:28:571658 extension_prefs_->OnExtensionInstalled(
1659 extension, initial_state, initial_enable_incognito);
[email protected]25b34332009-06-05 21:53:191660
[email protected]92a5b1d2010-07-20 00:42:001661 // Unpacked extensions start off with file access since they are a developer
1662 // feature.
1663 if (extension->location() == Extension::LOAD)
1664 extension_prefs_->SetAllowFileAccess(extension->id(), true);
1665
[email protected]4a190632009-05-09 01:07:421666 // If the extension is a theme, tell the profile (and therefore ThemeProvider)
1667 // to apply it.
[email protected]3ba0fd32010-06-19 05:39:101668 if (extension->is_theme()) {
[email protected]9ceb07342009-07-26 04:09:231669 NotificationService::current()->Notify(
1670 NotificationType::THEME_INSTALLED,
[email protected]24e7a9d2009-11-04 11:11:341671 Source<Profile>(profile_),
[email protected]9adb9692010-10-29 23:14:021672 Details<const Extension>(extension));
[email protected]9197f3b2009-06-02 00:49:271673 } else {
1674 NotificationService::current()->Notify(
1675 NotificationType::EXTENSION_INSTALLED,
[email protected]24e7a9d2009-11-04 11:11:341676 Source<Profile>(profile_),
[email protected]9adb9692010-10-29 23:14:021677 Details<const Extension>(extension));
[email protected]4a190632009-05-09 01:07:421678 }
[email protected]7577a5c52009-07-30 06:21:581679
[email protected]ec5b50d2010-10-09 16:35:181680 if (extension->is_app()) {
1681 ExtensionIdSet installed_ids = GetAppIds();
1682 installed_ids.insert(extension->id());
1683 default_apps_.DidInstallApp(installed_ids);
1684 }
1685
[email protected]4416c5a2010-06-26 01:28:571686 // Transfer ownership of |extension| to OnExtensionLoaded.
[email protected]66e4eb32010-10-27 20:37:411687 OnExtensionLoaded(scoped_extension, allow_privilege_increase);
[email protected]4a190632009-05-09 01:07:421688}
1689
[email protected]9adb9692010-10-29 23:14:021690const Extension* ExtensionsService::GetExtensionByIdInternal(
1691 const std::string& id, bool include_enabled, bool include_disabled) {
[email protected]e957fe52009-06-23 16:51:051692 std::string lowercase_id = StringToLowerASCII(id);
[email protected]0c6da502009-08-14 22:32:391693 if (include_enabled) {
1694 for (ExtensionList::const_iterator iter = extensions_.begin();
1695 iter != extensions_.end(); ++iter) {
1696 if ((*iter)->id() == lowercase_id)
1697 return *iter;
1698 }
1699 }
1700 if (include_disabled) {
1701 for (ExtensionList::const_iterator iter = disabled_extensions_.begin();
1702 iter != disabled_extensions_.end(); ++iter) {
1703 if ((*iter)->id() == lowercase_id)
1704 return *iter;
1705 }
[email protected]ce5c4502009-05-06 16:46:111706 }
1707 return NULL;
1708}
1709
[email protected]9adb9692010-10-29 23:14:021710const Extension* ExtensionsService::GetWebStoreApp() {
[email protected]d3071992010-10-08 15:24:071711 return GetExtensionById(extension_misc::kWebStoreAppId, false);
1712}
1713
[email protected]9adb9692010-10-29 23:14:021714const Extension* ExtensionsService::GetExtensionByURL(const GURL& url) {
[email protected]a888b29e62010-04-01 13:38:571715 return url.scheme() != chrome::kExtensionScheme ? NULL :
1716 GetExtensionById(url.host(), false);
1717}
1718
[email protected]9adb9692010-10-29 23:14:021719const Extension* ExtensionsService::GetExtensionByWebExtent(const GURL& url) {
[email protected]a888b29e62010-04-01 13:38:571720 for (size_t i = 0; i < extensions_.size(); ++i) {
1721 if (extensions_[i]->web_extent().ContainsURL(url))
1722 return extensions_[i];
1723 }
1724 return NULL;
[email protected]9f1087e2009-06-15 17:29:321725}
1726
[email protected]583d45c12010-08-31 02:48:121727bool ExtensionsService::ExtensionBindingsAllowed(const GURL& url) {
1728 // Allow bindings for all packaged extension.
1729 if (GetExtensionByURL(url))
1730 return true;
1731
1732 // Allow bindings for all component, hosted apps.
[email protected]9adb9692010-10-29 23:14:021733 const Extension* extension = GetExtensionByWebExtent(url);
[email protected]583d45c12010-08-31 02:48:121734 return (extension && extension->location() == Extension::COMPONENT);
1735}
1736
[email protected]9adb9692010-10-29 23:14:021737const Extension* ExtensionsService::GetExtensionByOverlappingWebExtent(
[email protected]9f72aa02010-06-25 10:01:051738 const ExtensionExtent& extent) {
[email protected]22c966c2010-06-26 06:35:021739 for (size_t i = 0; i < extensions_.size(); ++i) {
1740 if (extensions_[i]->web_extent().OverlapsWith(extent))
1741 return extensions_[i];
1742 }
1743
[email protected]6d2e60bd2010-06-03 22:37:391744 return NULL;
1745}
1746
[email protected]b671760b2010-07-15 21:13:471747const SkBitmap& ExtensionsService::GetOmniboxIcon(
1748 const std::string& extension_id) {
1749 return omnibox_icon_manager_.GetIcon(extension_id);
1750}
1751
[email protected]29d0d4ac2010-09-08 21:10:311752const SkBitmap& ExtensionsService::GetOmniboxPopupIcon(
1753 const std::string& extension_id) {
1754 return omnibox_popup_icon_manager_.GetIcon(extension_id);
1755}
1756
[email protected]a1257b12009-06-12 02:51:341757void ExtensionsService::ClearProvidersForTesting() {
[email protected]ca4b5fa32010-10-09 12:42:181758 BrowserThread::PostTask(
1759 BrowserThread::FILE, FROM_HERE,
[email protected]95d29192009-10-30 01:49:061760 NewRunnableMethod(
1761 backend_.get(), &ExtensionsServiceBackend::ClearProvidersForTesting));
[email protected]a1257b12009-06-12 02:51:341762}
1763
[email protected]0a60a2e2010-10-25 16:15:211764void ExtensionsService::AddProviderForTesting(
1765 ExternalExtensionProvider* test_provider) {
[email protected]ca4b5fa32010-10-09 12:42:181766 BrowserThread::PostTask(
1767 BrowserThread::FILE, FROM_HERE,
[email protected]95d29192009-10-30 01:49:061768 NewRunnableMethod(
[email protected]0a60a2e2010-10-25 16:15:211769 backend_.get(), &ExtensionsServiceBackend::AddProviderForTesting,
1770 test_provider));
[email protected]a1257b12009-06-12 02:51:341771}
1772
[email protected]8ef78fd2010-08-19 17:14:321773void ExtensionsService::OnExternalExtensionFileFound(
1774 const std::string& id,
1775 const std::string& version,
1776 const FilePath& path,
1777 Extension::Location location) {
[email protected]a8af9fdb2010-10-28 21:52:201778 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1779
[email protected]7577a5c52009-07-30 06:21:581780 // Before even bothering to unpack, check and see if we already have this
[email protected]4c967932009-07-31 01:15:491781 // version. This is important because these extensions are going to get
[email protected]7577a5c52009-07-30 06:21:581782 // installed on every startup.
[email protected]9adb9692010-10-29 23:14:021783 const Extension* existing = GetExtensionById(id, true);
[email protected]a3a63ff82009-08-04 06:44:111784 scoped_ptr<Version> other(Version::GetVersionFromString(version));
[email protected]7577a5c52009-07-30 06:21:581785 if (existing) {
[email protected]a3a63ff82009-08-04 06:44:111786 switch (existing->version()->CompareTo(*other)) {
[email protected]7577a5c52009-07-30 06:21:581787 case -1: // existing version is older, we should upgrade
1788 break;
1789 case 0: // existing version is same, do nothing
1790 return;
1791 case 1: // existing version is newer, uh-oh
1792 LOG(WARNING) << "Found external version of extension " << id
1793 << "that is older than current version. Current version "
1794 << "is: " << existing->VersionString() << ". New version "
1795 << "is: " << version << ". Keeping current version.";
1796 return;
1797 }
1798 }
1799
[email protected]6dfbbf82010-03-12 23:09:161800 scoped_refptr<CrxInstaller> installer(
1801 new CrxInstaller(install_directory_,
1802 this, // frontend
1803 NULL)); // no client (silent install)
1804 installer->set_install_source(location);
1805 installer->set_expected_id(id);
1806 installer->set_allow_privilege_increase(true);
1807 installer->InstallCrx(path);
[email protected]7577a5c52009-07-30 06:21:581808}
1809
[email protected]d11c8e92009-10-20 23:26:401810void ExtensionsService::ReportExtensionLoadError(
1811 const FilePath& extension_path,
1812 const std::string &error,
1813 NotificationType type,
1814 bool be_noisy) {
1815 NotificationService* service = NotificationService::current();
1816 service->Notify(type,
[email protected]24e7a9d2009-11-04 11:11:341817 Source<Profile>(profile_),
[email protected]d11c8e92009-10-20 23:26:401818 Details<const std::string>(&error));
1819
1820 // TODO(port): note that this isn't guaranteed to work properly on Linux.
[email protected]99efb7b12009-12-18 02:39:161821 std::string path_str = WideToUTF8(extension_path.ToWStringHack());
[email protected]18d4b6c2010-09-21 03:21:041822 std::string message = base::StringPrintf(
1823 "Could not load extension from '%s'. %s",
1824 path_str.c_str(), error.c_str());
[email protected]d11c8e92009-10-20 23:26:401825 ExtensionErrorReporter::GetInstance()->ReportError(message, be_noisy);
1826}
1827
[email protected]406027c02010-09-27 08:03:181828void ExtensionsService::DidCreateRenderViewForBackgroundPage(
1829 ExtensionHost* host) {
1830 OrphanedDevTools::iterator iter =
1831 orphaned_dev_tools_.find(host->extension()->id());
1832 if (iter == orphaned_dev_tools_.end())
1833 return;
1834
1835 DevToolsManager::GetInstance()->AttachClientHost(
1836 iter->second, host->render_view_host());
1837 orphaned_dev_tools_.erase(iter);
1838}
1839
[email protected]4814b512009-11-07 00:12:291840void ExtensionsService::Observe(NotificationType type,
1841 const NotificationSource& source,
1842 const NotificationDetails& details) {
1843 switch (type.value) {
[email protected]a4ed6282009-12-14 20:51:161844 case NotificationType::EXTENSION_PROCESS_TERMINATED: {
[email protected]bc535ee52010-08-31 18:40:321845 if (profile_ != Source<Profile>(source).ptr()->GetOriginalProfile())
1846 break;
[email protected]a4ed6282009-12-14 20:51:161847
[email protected]f128af42010-08-05 18:05:261848 ExtensionHost* host = Details<ExtensionHost>(details).ptr();
1849
1850 // TODO(rafaelw): Remove this check and ExtensionHost::recently_deleted().
1851 // This is only here to help track down crbug.com/49114.
1852 ExtensionHost::HostPointerList::iterator iter =
1853 ExtensionHost::recently_deleted()->begin();
1854 for (; iter != ExtensionHost::recently_deleted()->end(); iter++) {
1855 if (*iter == host) {
1856 CHECK(host->GetURL().spec().size() + 2 != 0);
1857 break;
1858 }
1859 }
1860 if (iter == ExtensionHost::recently_deleted()->end())
1861 CHECK(host->GetURL().spec().size() + 1 != 0);
1862
[email protected]31f77262009-12-02 20:48:531863 // Unload the entire extension. We want it to be in a consistent state:
1864 // either fully working or not loaded at all, but never half-crashed.
[email protected]bc535ee52010-08-31 18:40:321865 // We do it in a PostTask so that other handlers of this notification will
1866 // still have access to the Extension and ExtensionHost.
1867 MessageLoop::current()->PostTask(FROM_HERE,
1868 NewRunnableMethod(this, &ExtensionsService::UnloadExtension,
1869 host->extension()->id()));
[email protected]31f77262009-12-02 20:48:531870 break;
1871 }
1872
[email protected]aa96d3a2010-08-21 08:45:251873 case NotificationType::PREF_CHANGED: {
1874 std::string* pref_name = Details<std::string>(details).ptr();
1875 DCHECK(*pref_name == prefs::kExtensionInstallAllowList ||
1876 *pref_name == prefs::kExtensionInstallDenyList);
1877 CheckAdminBlacklist();
1878 break;
1879 }
1880
[email protected]4814b512009-11-07 00:12:291881 default:
1882 NOTREACHED() << "Unexpected notification type.";
1883 }
1884}
1885
[email protected]ec5b50d2010-10-09 16:35:181886bool ExtensionsService::HasApps() const {
1887 return !GetAppIds().empty();
1888}
[email protected]377011d2010-07-20 04:18:501889
[email protected]ec5b50d2010-10-09 16:35:181890ExtensionIdSet ExtensionsService::GetAppIds() const {
1891 ExtensionIdSet result;
[email protected]377011d2010-07-20 04:18:501892 for (ExtensionList::const_iterator it = extensions_.begin();
1893 it != extensions_.end(); ++it) {
[email protected]ec5b50d2010-10-09 16:35:181894 if ((*it)->is_app() && (*it)->location() != Extension::COMPONENT)
1895 result.insert((*it)->id());
[email protected]377011d2010-07-20 04:18:501896 }
1897
[email protected]ec5b50d2010-10-09 16:35:181898 return result;
[email protected]377011d2010-07-20 04:18:501899}