blob: 336e6585f476931526a4ea11879190ddf7e0b4d0 [file] [log] [blame]
[email protected]8e4560b62011-01-14 10:09:141// Copyright (c) 2011 The Chromium Authors. All rights reserved.
[email protected]6014d672008-12-05 00:38:252// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]eaa7dd182010-12-14 11:09:005#include "chrome/browser/extensions/extension_service.h"
[email protected]6014d672008-12-05 00:38:256
[email protected]654512b2010-09-01 02:09:427#include <algorithm>
[email protected]97d2f1d2011-01-15 00:41:088#include <set>
[email protected]654512b2010-09-01 02:09:429
[email protected]24b538a2010-02-27 01:22:4410#include "base/basictypes.h"
[email protected]e2eb43112009-05-29 21:19:5411#include "base/command_line.h"
[email protected]6014d672008-12-05 00:38:2512#include "base/file_util.h"
[email protected]14908b72011-04-20 06:54:3613#include "base/logging.h"
[email protected]835d7c82010-10-14 04:38:3814#include "base/metrics/histogram.h"
[email protected]cebc3dc2011-04-18 17:15:0015#include "base/path_service.h"
[email protected]7286e3fc2011-07-19 22:13:2416#include "base/stl_util.h"
[email protected]24b538a2010-02-27 01:22:4417#include "base/string16.h"
[email protected]e83326f2010-07-31 17:29:2518#include "base/string_number_conversions.h"
[email protected]6014d672008-12-05 00:38:2519#include "base/string_util.h"
[email protected]18d4b6c2010-09-21 03:21:0420#include "base/stringprintf.h"
[email protected]34b99632011-01-01 01:01:0621#include "base/threading/thread_restrictions.h"
[email protected]cc2c3432009-11-06 17:24:3622#include "base/time.h"
[email protected]ce7f62e32010-08-10 23:43:5923#include "base/utf_string_conversions.h"
[email protected]cc655912009-01-29 23:19:1924#include "base/values.h"
[email protected]aa142702010-03-26 01:26:3325#include "base/version.h"
[email protected]15730c42009-09-03 00:03:2026#include "chrome/browser/browser_process.h"
[email protected]18cc5a52011-04-15 16:03:3827#include "chrome/browser/extensions/apps_promo.h"
[email protected]e0785902011-05-19 23:34:1728#include "chrome/browser/extensions/crx_installer.h"
[email protected]5cbe1e22010-01-30 01:18:5629#include "chrome/browser/extensions/extension_accessibility_api.h"
[email protected]840b0db2009-11-20 03:00:3830#include "chrome/browser/extensions/extension_bookmarks_module.h"
[email protected]b68d5ed2009-04-16 02:41:2831#include "chrome/browser/extensions/extension_browser_event_router.h"
[email protected]2c5e1e12010-06-10 13:14:4432#include "chrome/browser/extensions/extension_cookies_api.h"
[email protected]c10da4b02010-03-25 14:38:3233#include "chrome/browser/extensions/extension_data_deleter.h"
[email protected]14a000d2010-04-29 21:44:2434#include "chrome/browser/extensions/extension_error_reporter.h"
[email protected]de768a832009-10-30 05:25:0135#include "chrome/browser/extensions/extension_history_api.h"
[email protected]b1748b1d82009-11-30 20:32:5636#include "chrome/browser/extensions/extension_host.h"
[email protected]5fb889382011-06-03 00:29:2037#include "chrome/browser/extensions/extension_install_ui.h"
[email protected]7596ce72010-08-30 05:10:4638#include "chrome/browser/extensions/extension_management_api.h"
[email protected]118de7892011-03-16 13:31:4039#include "chrome/browser/extensions/extension_preference_api.h"
[email protected]4814b512009-11-07 00:12:2940#include "chrome/browser/extensions/extension_process_manager.h"
[email protected]8a661f82010-10-19 21:47:1141#include "chrome/browser/extensions/extension_processes_api.h"
[email protected]19eb80152011-02-26 00:28:4342#include "chrome/browser/extensions/extension_special_storage_policy.h"
[email protected]90310d92011-04-17 07:35:0443#include "chrome/browser/extensions/extension_sync_data.h"
[email protected]93fd78f42009-07-10 16:43:1744#include "chrome/browser/extensions/extension_updater.h"
[email protected]8f9d4eb2011-02-05 01:39:1045#include "chrome/browser/extensions/extension_web_ui.h"
[email protected]784688a62010-09-13 07:06:5246#include "chrome/browser/extensions/extension_webnavigation_api.h"
[email protected]8e4560b62011-01-14 10:09:1447#include "chrome/browser/extensions/external_extension_provider_impl.h"
[email protected]42b795652011-02-22 23:32:3848#include "chrome/browser/extensions/external_extension_provider_interface.h"
[email protected]b2907fd2011-03-25 16:43:3749#include "chrome/browser/extensions/pending_extension_manager.h"
[email protected]56ad3792010-05-28 17:45:3350#include "chrome/browser/net/chrome_url_request_context.h"
[email protected]37858e52010-08-26 00:22:0251#include "chrome/browser/prefs/pref_service.h"
[email protected]8ecad5e2010-12-02 21:18:3352#include "chrome/browser/profiles/profile.h"
[email protected]8e5c89a2011-06-07 18:13:3353#include "chrome/browser/search_engines/template_url_service.h"
54#include "chrome/browser/search_engines/template_url_service_factory.h"
[email protected]18280372011-03-22 18:05:2255#include "chrome/browser/themes/theme_service.h"
[email protected]a0ea76c2011-03-23 17:36:4256#include "chrome/browser/themes/theme_service_factory.h"
[email protected]c8d407e2011-04-28 21:27:1757#include "chrome/browser/ui/webui/chrome_url_data_manager.h"
58#include "chrome/browser/ui/webui/favicon_source.h"
[email protected]7c5c6f3a2011-04-28 19:56:4959#include "chrome/browser/ui/webui/ntp/shown_sections_handler.h"
[email protected]aab98a52009-12-02 03:22:3560#include "chrome/common/child_process_logging.h"
[email protected]432115822011-07-10 15:52:2761#include "chrome/common/chrome_notification_types.h"
[email protected]cebc3dc2011-04-18 17:15:0062#include "chrome/common/chrome_paths.h"
[email protected]e2eb43112009-05-29 21:19:5463#include "chrome/common/chrome_switches.h"
[email protected]5b1a0e22009-05-26 19:00:5864#include "chrome/common/extensions/extension.h"
[email protected]d7b36dc2009-10-29 21:47:4065#include "chrome/common/extensions/extension_constants.h"
[email protected]05c82182010-06-24 17:49:0866#include "chrome/common/extensions/extension_error_utils.h"
[email protected]7c927b62010-02-24 09:54:1367#include "chrome/common/extensions/extension_file_util.h"
[email protected]c6d474f82009-12-16 21:11:0668#include "chrome/common/extensions/extension_l10n_util.h"
[email protected]77a6970c2011-04-23 16:58:5669#include "chrome/common/extensions/extension_messages.h"
[email protected]a315ba92010-11-16 14:12:2170#include "chrome/common/extensions/extension_resource.h"
[email protected]25b34332009-06-05 21:53:1971#include "chrome/common/pref_names.h"
[email protected]a57209872009-05-04 22:53:1472#include "chrome/common/url_constants.h"
[email protected]5f945a0e2011-03-01 17:47:5373#include "content/browser/browser_thread.h"
[email protected]b46442d7e2011-06-29 02:16:0674#include "content/browser/debugger/devtools_manager.h"
[email protected]2de307592011-04-05 21:16:5875#include "content/browser/plugin_process_host.h"
76#include "content/browser/plugin_service.h"
[email protected]77a6970c2011-04-23 16:58:5677#include "content/browser/renderer_host/render_process_host.h"
[email protected]432115822011-07-10 15:52:2778#include "content/common/content_notification_types.h"
[email protected]c3113022011-04-16 03:26:3079#include "content/common/json_value_serializer.h"
[email protected]b3841c502011-03-09 01:21:3180#include "content/common/notification_service.h"
[email protected]cebc3dc2011-04-18 17:15:0081#include "content/common/pepper_plugin_registry.h"
[email protected]c10da4b02010-03-25 14:38:3282#include "googleurl/src/gurl.h"
[email protected]1debbbb62010-10-06 17:23:4483#include "net/base/registry_controlled_domain.h"
[email protected]24b538a2010-02-27 01:22:4484#include "webkit/database/database_tracker.h"
85#include "webkit/database/database_util.h"
[email protected]2de307592011-04-05 21:16:5886#include "webkit/plugins/npapi/plugin_list.h"
[email protected]c64631652009-04-29 22:24:3187
[email protected]eed367e2011-04-12 03:43:3188#if defined(OS_CHROMEOS)
89#include "chrome/browser/chromeos/extensions/file_browser_event_router.h"
[email protected]be5bd5742011-07-14 07:21:0190#include "chrome/browser/chromeos/extensions/input_method_event_router.h"
[email protected]ce9802042011-05-27 10:11:4091#include "chrome/browser/chromeos/extensions/media_player_event_router.h"
[email protected]b777b332011-04-16 04:01:0892#include "webkit/fileapi/file_system_context.h"
93#include "webkit/fileapi/file_system_mount_point_provider.h"
94#include "webkit/fileapi/file_system_path_manager.h"
[email protected]eed367e2011-04-12 03:43:3195#endif
96
[email protected]27072cad2011-05-09 19:46:4097#if defined(OS_CHROMEOS) && defined(TOUCH_UI)
[email protected]c8d4e9462011-06-29 23:18:5798#include "chrome/browser/chromeos/input_method/input_method_manager.h"
[email protected]27072cad2011-05-09 19:46:4099#include "chrome/browser/extensions/extension_input_ui_api.h"
100#endif
101
[email protected]5ef47ec2010-01-28 05:58:05102using base::Time;
103
[email protected]c6d474f82009-12-16 21:11:06104namespace errors = extension_manifest_errors;
105
[email protected]b6ab96d2009-08-20 18:58:19106namespace {
107
[email protected]29d0d4ac2010-09-08 21:10:31108#if defined(OS_LINUX)
109static const int kOmniboxIconPaddingLeft = 2;
110static const int kOmniboxIconPaddingRight = 2;
111#elif defined(OS_MACOSX)
112static const int kOmniboxIconPaddingLeft = 0;
113static const int kOmniboxIconPaddingRight = 2;
114#else
115static const int kOmniboxIconPaddingLeft = 0;
116static const int kOmniboxIconPaddingRight = 0;
117#endif
118
[email protected]300c0ea2011-07-15 23:04:33119const char* kNaClPluginMimeType = "application/x-nacl";
120
[email protected]a315ba92010-11-16 14:12:21121// The following enumeration is used in histograms matching
122// Extensions.ManifestReload* . Values may be added, as long
123// as existing values are not changed.
124enum ManifestReloadReason {
125 NOT_NEEDED = 0, // Reload not needed.
126 UNPACKED_DIR, // Unpacked directory
127 NEEDS_RELOCALIZATION, // The local has changed since we read this extension.
128 NUM_MANIFEST_RELOAD_REASONS
129};
[email protected]2111b1a2010-03-12 18:12:44130
[email protected]a315ba92010-11-16 14:12:21131ManifestReloadReason ShouldReloadExtensionManifest(const ExtensionInfo& info) {
132 // Always reload manifests of unpacked extensions, because they can change
133 // on disk independent of the manifest in our prefs.
134 if (info.extension_location == Extension::LOAD)
135 return UNPACKED_DIR;
136
137 // Reload the manifest if it needs to be relocalized.
138 if (extension_l10n_util::ShouldRelocalizeManifest(info))
139 return NEEDS_RELOCALIZATION;
140
141 return NOT_NEEDED;
[email protected]2111b1a2010-03-12 18:12:44142}
143
[email protected]2de307592011-04-05 21:16:58144static void ForceShutdownPlugin(const FilePath& plugin_path) {
145 PluginProcessHost* plugin =
146 PluginService::GetInstance()->FindNpapiPluginProcess(plugin_path);
147 if (plugin)
148 plugin->ForceShutdown();
149}
150
[email protected]5fb889382011-06-03 00:29:20151// Manages an ExtensionInstallUI for a particular extension.
152class SimpleExtensionLoadPrompt : public ExtensionInstallUI::Delegate {
153 public:
154 SimpleExtensionLoadPrompt(Profile* profile,
155 base::WeakPtr<ExtensionService> extension_service,
156 const Extension* extension);
157 ~SimpleExtensionLoadPrompt();
158
159 void ShowPrompt();
160
161 // ExtensionInstallUI::Delegate
162 virtual void InstallUIProceed();
[email protected]d828fac2011-06-28 05:43:04163 virtual void InstallUIAbort(bool user_initiated);
[email protected]5fb889382011-06-03 00:29:20164
165 private:
166 base::WeakPtr<ExtensionService> extension_service_;
167 scoped_ptr<ExtensionInstallUI> install_ui_;
168 scoped_refptr<const Extension> extension_;
169};
170
171SimpleExtensionLoadPrompt::SimpleExtensionLoadPrompt(
172 Profile* profile,
173 base::WeakPtr<ExtensionService> extension_service,
174 const Extension* extension)
175 : extension_service_(extension_service),
176 install_ui_(new ExtensionInstallUI(profile)),
177 extension_(extension) {
178}
179
180SimpleExtensionLoadPrompt::~SimpleExtensionLoadPrompt() {
181}
182
183void SimpleExtensionLoadPrompt::ShowPrompt() {
184 install_ui_->ConfirmInstall(this, extension_);
185}
186
187void SimpleExtensionLoadPrompt::InstallUIProceed() {
188 if (extension_service_.get())
[email protected]8266d662011-07-12 21:53:26189 extension_service_->OnExtensionInstalled(
190 extension_, false); // Not from web store.
[email protected]5fb889382011-06-03 00:29:20191 delete this;
192}
193
[email protected]d828fac2011-06-28 05:43:04194void SimpleExtensionLoadPrompt::InstallUIAbort(bool user_initiated) {
[email protected]5fb889382011-06-03 00:29:20195 delete this;
196}
197
[email protected]c6d474f82009-12-16 21:11:06198} // namespace
[email protected]b6ab96d2009-08-20 18:58:19199
[email protected]ad63a792011-06-16 06:41:11200bool ExtensionService::ComponentExtensionInfo::Equals(
201 const ComponentExtensionInfo& other) const {
202 return other.manifest == manifest && other.root_directory == root_directory;
203}
204
[email protected]eaa7dd182010-12-14 11:09:00205ExtensionService::ExtensionRuntimeData::ExtensionRuntimeData()
[email protected]d7e9a862010-11-03 21:57:49206 : background_page_ready(false),
207 being_upgraded(false) {
208}
209
[email protected]eaa7dd182010-12-14 11:09:00210ExtensionService::ExtensionRuntimeData::~ExtensionRuntimeData() {
[email protected]d7e9a862010-11-03 21:57:49211}
212
[email protected]cebc3dc2011-04-18 17:15:00213ExtensionService::NaClModuleInfo::NaClModuleInfo() {
214}
215
216ExtensionService::NaClModuleInfo::~NaClModuleInfo() {
217}
218
[email protected]eaa7dd182010-12-14 11:09:00219// ExtensionService.
[email protected]6014d672008-12-05 00:38:25220
[email protected]eaa7dd182010-12-14 11:09:00221const char* ExtensionService::kInstallDirectoryName = "Extensions";
222const char* ExtensionService::kCurrentVersionFileName = "Current Version";
[email protected]494c06e2009-07-25 01:06:42223
[email protected]eaa7dd182010-12-14 11:09:00224// Implements IO for the ExtensionService.
[email protected]7a4c6852010-09-16 03:44:22225
[email protected]eaa7dd182010-12-14 11:09:00226class ExtensionServiceBackend
[email protected]8e4560b62011-01-14 10:09:14227 : public base::RefCountedThreadSafe<ExtensionServiceBackend> {
[email protected]7a4c6852010-09-16 03:44:22228 public:
[email protected]1f830eb2010-09-28 08:25:14229 // |install_directory| is a path where to look for extensions to load.
[email protected]14908b72011-04-20 06:54:36230 ExtensionServiceBackend(
231 base::WeakPtr<ExtensionService> frontend,
232 const FilePath& install_directory);
[email protected]7a4c6852010-09-16 03:44:22233
234 // Loads a single extension from |path| where |path| is the top directory of
[email protected]e49002a2011-07-13 03:40:44235 // a specific extension where its manifest file lives. If |prompt_for_plugins|
236 // is true and the extension contains plugins, we prompt the user before
237 // loading.
[email protected]7a4c6852010-09-16 03:44:22238 // Errors are reported through ExtensionErrorReporter. On success,
[email protected]49cd1572011-02-08 21:38:45239 // AddExtension() is called.
[email protected]7a4c6852010-09-16 03:44:22240 // TODO(erikkay): It might be useful to be able to load a packed extension
241 // (presumably into memory) without installing it.
[email protected]e49002a2011-07-13 03:40:44242 void LoadSingleExtension(const FilePath &path, bool prompt_for_plugins);
[email protected]7a4c6852010-09-16 03:44:22243
[email protected]7a4c6852010-09-16 03:44:22244 private:
[email protected]eaa7dd182010-12-14 11:09:00245 friend class base::RefCountedThreadSafe<ExtensionServiceBackend>;
[email protected]7a4c6852010-09-16 03:44:22246
[email protected]eaa7dd182010-12-14 11:09:00247 virtual ~ExtensionServiceBackend();
[email protected]7a4c6852010-09-16 03:44:22248
[email protected]d10f4602011-06-16 15:44:50249 // LoadSingleExtension needs to check the file access preference, which needs
250 // to happen back on the UI thread, so it posts CheckExtensionFileAccess on
251 // the UI thread. In turn, once that gets the pref, it goes back to the
252 // file thread with LoadSingleExtensionWithFileAccess.
[email protected]e49002a2011-07-13 03:40:44253 void CheckExtensionFileAccess(const FilePath& extension_path,
254 bool prompt_for_plugins);
[email protected]d10f4602011-06-16 15:44:50255 void LoadSingleExtensionWithFileAccess(
[email protected]e49002a2011-07-13 03:40:44256 const FilePath &path, bool allow_file_access, bool prompt_for_plugins);
[email protected]d10f4602011-06-16 15:44:50257
[email protected]7a4c6852010-09-16 03:44:22258 // Notify the frontend that there was an error loading an extension.
259 void ReportExtensionLoadError(const FilePath& extension_path,
260 const std::string& error);
261
[email protected]14908b72011-04-20 06:54:36262 // Notify the frontend that an extension was installed.
[email protected]e49002a2011-07-13 03:40:44263 void OnLoadSingleExtension(const scoped_refptr<const Extension>& extension,
264 bool prompt_for_plugins);
[email protected]14908b72011-04-20 06:54:36265
266 base::WeakPtr<ExtensionService> frontend_;
[email protected]7a4c6852010-09-16 03:44:22267
268 // The top-level extensions directory being installed to.
269 FilePath install_directory_;
270
[email protected]eaa7dd182010-12-14 11:09:00271 DISALLOW_COPY_AND_ASSIGN(ExtensionServiceBackend);
[email protected]7a4c6852010-09-16 03:44:22272};
273
[email protected]eaa7dd182010-12-14 11:09:00274ExtensionServiceBackend::ExtensionServiceBackend(
[email protected]14908b72011-04-20 06:54:36275 base::WeakPtr<ExtensionService> frontend,
[email protected]aebe23a32010-12-10 22:15:48276 const FilePath& install_directory)
[email protected]14908b72011-04-20 06:54:36277 : frontend_(frontend),
278 install_directory_(install_directory) {
279 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]7a4c6852010-09-16 03:44:22280}
281
[email protected]eaa7dd182010-12-14 11:09:00282ExtensionServiceBackend::~ExtensionServiceBackend() {
[email protected]14908b72011-04-20 06:54:36283 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
284 BrowserThread::CurrentlyOn(BrowserThread::FILE));
[email protected]7a4c6852010-09-16 03:44:22285}
286
[email protected]e49002a2011-07-13 03:40:44287void ExtensionServiceBackend::LoadSingleExtension(const FilePath& path_in,
288 bool prompt_for_plugins) {
[email protected]a29a517a2011-01-21 21:11:12289 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
[email protected]a8af9fdb2010-10-28 21:52:20290
[email protected]7a4c6852010-09-16 03:44:22291 FilePath extension_path = path_in;
292 file_util::AbsolutePath(&extension_path);
293
[email protected]e49002a2011-07-13 03:40:44294 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
295 NewRunnableMethod(this,
296 &ExtensionServiceBackend::CheckExtensionFileAccess,
297 extension_path, prompt_for_plugins));
[email protected]d10f4602011-06-16 15:44:50298}
299
300void ExtensionServiceBackend::CheckExtensionFileAccess(
[email protected]e49002a2011-07-13 03:40:44301 const FilePath& extension_path, bool prompt_for_plugins) {
[email protected]d10f4602011-06-16 15:44:50302 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
303 std::string id = Extension::GenerateIdForPath(extension_path);
304 // Unpacked extensions default to allowing file access, but if that has been
305 // overridden, don't reset the value.
306 bool allow_file_access =
[email protected]67d2d802011-07-21 02:54:28307 Extension::ShouldAlwaysAllowFileAccess(Extension::LOAD);
308 if (frontend_->extension_prefs()->HasAllowFileAccessSetting(id))
309 allow_file_access = frontend_->extension_prefs()->AllowFileAccess(id);
[email protected]d10f4602011-06-16 15:44:50310
[email protected]e49002a2011-07-13 03:40:44311 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
312 NewRunnableMethod(
313 this,
314 &ExtensionServiceBackend::LoadSingleExtensionWithFileAccess,
315 extension_path, allow_file_access, prompt_for_plugins));
[email protected]d10f4602011-06-16 15:44:50316}
317
[email protected]d10f4602011-06-16 15:44:50318void ExtensionServiceBackend::LoadSingleExtensionWithFileAccess(
[email protected]e49002a2011-07-13 03:40:44319 const FilePath& extension_path,
320 bool allow_file_access,
321 bool prompt_for_plugins) {
[email protected]d10f4602011-06-16 15:44:50322 CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
323 int flags = allow_file_access ?
[email protected]3aff9ad2011-04-01 20:26:48324 Extension::ALLOW_FILE_ACCESS : Extension::NO_FLAGS;
[email protected]83048a22011-03-29 00:14:13325 if (Extension::ShouldDoStrictErrorChecking(Extension::LOAD))
326 flags |= Extension::STRICT_ERROR_CHECKS;
[email protected]7a4c6852010-09-16 03:44:22327 std::string error;
[email protected]ad8e04a2010-11-01 04:16:27328 scoped_refptr<const Extension> extension(extension_file_util::LoadExtension(
[email protected]7a4c6852010-09-16 03:44:22329 extension_path,
[email protected]92888082010-10-18 19:24:57330 Extension::LOAD,
[email protected]83048a22011-03-29 00:14:13331 flags,
[email protected]ad8e04a2010-11-01 04:16:27332 &error));
[email protected]7a4c6852010-09-16 03:44:22333
334 if (!extension) {
[email protected]e49002a2011-07-13 03:40:44335 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
336 NewRunnableMethod(
337 this,
338 &ExtensionServiceBackend::ReportExtensionLoadError,
339 extension_path, error));
[email protected]7a4c6852010-09-16 03:44:22340 return;
341 }
342
[email protected]7a4c6852010-09-16 03:44:22343 // Report this as an installed extension so that it gets remembered in the
344 // prefs.
[email protected]e49002a2011-07-13 03:40:44345 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
346 NewRunnableMethod(
347 this,
348 &ExtensionServiceBackend::OnLoadSingleExtension,
349 extension, prompt_for_plugins));
[email protected]7a4c6852010-09-16 03:44:22350}
351
[email protected]eaa7dd182010-12-14 11:09:00352void ExtensionServiceBackend::ReportExtensionLoadError(
[email protected]7a4c6852010-09-16 03:44:22353 const FilePath& extension_path, const std::string &error) {
[email protected]14908b72011-04-20 06:54:36354 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
355 if (frontend_.get())
356 frontend_->ReportExtensionLoadError(
[email protected]432115822011-07-10 15:52:27357 extension_path, error, chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
[email protected]14908b72011-04-20 06:54:36358 true /* alert_on_error */);
359}
360
[email protected]5fb889382011-06-03 00:29:20361void ExtensionServiceBackend::OnLoadSingleExtension(
[email protected]e49002a2011-07-13 03:40:44362 const scoped_refptr<const Extension>& extension, bool prompt_for_plugins) {
[email protected]14908b72011-04-20 06:54:36363 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
364 if (frontend_.get())
[email protected]e49002a2011-07-13 03:40:44365 frontend_->OnLoadSingleExtension(extension, prompt_for_plugins);
[email protected]7a4c6852010-09-16 03:44:22366}
367
[email protected]8e4560b62011-01-14 10:09:14368void ExtensionService::CheckExternalUninstall(const std::string& id) {
[email protected]a29a517a2011-01-21 21:11:12369 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]a8af9fdb2010-10-28 21:52:20370
[email protected]7a4c6852010-09-16 03:44:22371 // Check if the providers know about this extension.
[email protected]0a60a2e2010-10-25 16:15:21372 ProviderCollection::const_iterator i;
373 for (i = external_extension_providers_.begin();
374 i != external_extension_providers_.end(); ++i) {
[email protected]8e4560b62011-01-14 10:09:14375 DCHECK(i->get()->IsReady());
[email protected]0a60a2e2010-10-25 16:15:21376 if (i->get()->HasExtension(id))
377 return; // Yup, known extension, don't uninstall.
[email protected]7a4c6852010-09-16 03:44:22378 }
379
[email protected]0f48fca2011-05-19 18:46:35380 // We get the list of external extensions to check from preferences.
381 // It is possible that an extension has preferences but is not loaded.
382 // For example, an extension that requires experimental permissions
383 // will not be loaded if the experimental command line flag is not used.
384 // In this case, do not uninstall.
385 const Extension* extension = GetInstalledExtension(id);
386 if (!extension) {
387 // We can't call UninstallExtension with an unloaded/invalid
388 // extension ID.
389 LOG(WARNING) << "Attempted uninstallation of unloaded/invalid extension "
390 << "with id: " << id;
391 return;
392 }
[email protected]d6ebc9792011-04-07 18:18:33393 UninstallExtension(id, true, NULL);
[email protected]7a4c6852010-09-16 03:44:22394}
395
[email protected]8e4560b62011-01-14 10:09:14396void ExtensionService::ClearProvidersForTesting() {
[email protected]7a4c6852010-09-16 03:44:22397 external_extension_providers_.clear();
398}
399
[email protected]8e4560b62011-01-14 10:09:14400void ExtensionService::AddProviderForTesting(
401 ExternalExtensionProviderInterface* test_provider) {
[email protected]a29a517a2011-01-21 21:11:12402 CHECK(test_provider);
[email protected]0a60a2e2010-10-25 16:15:21403 external_extension_providers_.push_back(
[email protected]8e4560b62011-01-14 10:09:14404 linked_ptr<ExternalExtensionProviderInterface>(test_provider));
[email protected]7a4c6852010-09-16 03:44:22405}
406
[email protected]8e4560b62011-01-14 10:09:14407void ExtensionService::OnExternalExtensionUpdateUrlFound(
[email protected]7a4c6852010-09-16 03:44:22408 const std::string& id,
[email protected]21a5a672010-11-04 10:47:42409 const GURL& update_url,
410 Extension::Location location) {
[email protected]ab22ba42011-01-14 16:36:38411 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
412 CHECK(Extension::IdIsValid(id));
[email protected]a8af9fdb2010-10-28 21:52:20413
[email protected]8e4560b62011-01-14 10:09:14414 if (GetExtensionById(id, true)) {
[email protected]7a4c6852010-09-16 03:44:22415 // Already installed. Do not change the update URL that the extension set.
416 return;
417 }
[email protected]b2907fd2011-03-25 16:43:37418 pending_extension_manager()->AddFromExternalUpdateUrl(
419 id, update_url, location);
[email protected]a29a517a2011-01-21 21:11:12420 external_extension_url_added_ |= true;
[email protected]7a4c6852010-09-16 03:44:22421}
422
[email protected]eaa7dd182010-12-14 11:09:00423bool ExtensionService::IsDownloadFromGallery(const GURL& download_url,
[email protected]a29a517a2011-01-21 21:11:12424 const GURL& referrer_url) {
[email protected]d3071992010-10-08 15:24:07425 // Special-case the themes mini-gallery.
426 // TODO(erikkay) When that gallery goes away, remove this code.
427 if (IsDownloadFromMiniGallery(download_url) &&
428 StartsWithASCII(referrer_url.spec(),
429 extension_urls::kMiniGalleryBrowsePrefix, false)) {
[email protected]334e04a2010-06-24 23:34:44430 return true;
[email protected]1debbbb62010-10-06 17:23:44431 }
[email protected]473ff6e2010-05-12 15:31:55432
[email protected]9adb9692010-10-29 23:14:02433 const Extension* download_extension = GetExtensionByWebExtent(download_url);
434 const Extension* referrer_extension = GetExtensionByWebExtent(referrer_url);
435 const Extension* webstore_app = GetWebStoreApp();
[email protected]d3071992010-10-08 15:24:07436
437 bool referrer_valid = (referrer_extension == webstore_app);
438 bool download_valid = (download_extension == webstore_app);
439
440 // If the command-line gallery URL is set, then be a bit more lenient.
441 GURL store_url =
442 GURL(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
443 switches::kAppsGalleryURL));
444 if (!store_url.is_empty()) {
445 std::string store_tld =
446 net::RegistryControlledDomainService::GetDomainAndRegistry(store_url);
447 if (!referrer_valid) {
448 std::string referrer_tld =
449 net::RegistryControlledDomainService::GetDomainAndRegistry(
450 referrer_url);
451 // The referrer gets stripped when transitioning from https to http,
452 // or when hitting an unknown test cert and that commonly happens in
453 // testing environments. Given this, we allow an empty referrer when
454 // the command-line flag is set.
455 // Otherwise, the TLD must match the TLD of the command-line url.
456 referrer_valid = referrer_url.is_empty() || (referrer_tld == store_tld);
457 }
458
459 if (!download_valid) {
460 std::string download_tld =
461 net::RegistryControlledDomainService::GetDomainAndRegistry(
[email protected]04866c42011-05-03 20:03:50462 download_url);
[email protected]d3071992010-10-08 15:24:07463
464 // Otherwise, the TLD must match the TLD of the command-line url.
465 download_valid = (download_tld == store_tld);
466 }
467 }
468
469 return (referrer_valid && download_valid);
[email protected]b7c2f252009-12-08 00:47:23470}
471
[email protected]eaa7dd182010-12-14 11:09:00472bool ExtensionService::IsDownloadFromMiniGallery(const GURL& download_url) {
[email protected]ac025282009-12-16 19:16:38473 return StartsWithASCII(download_url.spec(),
474 extension_urls::kMiniGalleryDownloadPrefix,
475 false); // case_sensitive
476}
477
[email protected]d9696672011-03-15 22:45:09478const Extension* ExtensionService::GetInstalledApp(const GURL& url) {
[email protected]ffb204f22010-12-05 23:20:27479 // Check for hosted app.
[email protected]d9696672011-03-15 22:45:09480 const Extension* app = GetExtensionByWebExtent(url);
481 if (app)
482 return app;
[email protected]ffb204f22010-12-05 23:20:27483
484 // Check for packaged app.
[email protected]d9696672011-03-15 22:45:09485 app = GetExtensionByURL(url);
486 if (app && app->is_app())
487 return app;
488
489 return NULL;
490}
491
492bool ExtensionService::IsInstalledApp(const GURL& url) {
493 return !!GetInstalledApp(url);
[email protected]ffb204f22010-12-05 23:20:27494}
495
[email protected]da5683db2011-04-23 17:12:21496void ExtensionService::SetInstalledAppForRenderer(int renderer_child_id,
497 const Extension* app) {
498 installed_app_hosts_[renderer_child_id] = app;
499}
500
501const Extension* ExtensionService::GetInstalledAppForRenderer(
502 int renderer_child_id) {
503 InstalledAppMap::iterator i = installed_app_hosts_.find(renderer_child_id);
504 if (i == installed_app_hosts_.end())
505 return NULL;
506 return i->second;
507}
508
[email protected]6aeac8342010-10-01 20:21:18509// static
[email protected]d6ebc9792011-04-07 18:18:33510// This function is used to implement the command-line switch
511// --uninstall-extension. The LOG statements within this function are used to
512// inform the user if the uninstall cannot be done.
[email protected]eaa7dd182010-12-14 11:09:00513bool ExtensionService::UninstallExtensionHelper(
514 ExtensionService* extensions_service,
[email protected]6aeac8342010-10-01 20:21:18515 const std::string& extension_id) {
[email protected]6aeac8342010-10-01 20:21:18516
[email protected]95da88c42011-03-31 10:07:33517 const Extension* extension =
[email protected]8001df22011-04-28 19:59:47518 extensions_service->GetInstalledExtension(extension_id);
[email protected]95da88c42011-03-31 10:07:33519
[email protected]d6ebc9792011-04-07 18:18:33520 // We can't call UninstallExtension with an invalid extension ID.
[email protected]95da88c42011-03-31 10:07:33521 if (!extension) {
[email protected]6aeac8342010-10-01 20:21:18522 LOG(WARNING) << "Attempted uninstallation of non-existent extension with "
[email protected]95da88c42011-03-31 10:07:33523 << "id: " << extension_id;
524 return false;
[email protected]6aeac8342010-10-01 20:21:18525 }
526
[email protected]d6ebc9792011-04-07 18:18:33527 // The following call to UninstallExtension will not allow an uninstall of a
528 // policy-controlled extension.
529 std::string error;
530 if (!extensions_service->UninstallExtension(extension_id, false, &error)) {
531 LOG(WARNING) << "Cannot uninstall extension with id " << extension_id
532 << ": " << error;
533 return false;
534 }
[email protected]95da88c42011-03-31 10:07:33535
[email protected]6aeac8342010-10-01 20:21:18536 return true;
537}
538
[email protected]eaa7dd182010-12-14 11:09:00539ExtensionService::ExtensionService(Profile* profile,
[email protected]f0841cd2011-01-19 15:07:24540 const CommandLine* command_line,
541 const FilePath& install_directory,
542 ExtensionPrefs* extension_prefs,
[email protected]0436b102011-04-15 18:30:03543 bool autoupdate_enabled,
544 bool extensions_enabled)
[email protected]14908b72011-04-20 06:54:36545 : weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
546 method_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
547 profile_(profile),
[email protected]73c47932010-12-06 18:13:43548 extension_prefs_(extension_prefs),
[email protected]14908b72011-04-20 06:54:36549 pending_extension_manager_(*ALLOW_THIS_IN_INITIALIZER_LIST(this)),
[email protected]a9b00ac2009-06-25 21:03:23550 install_directory_(install_directory),
[email protected]0436b102011-04-15 18:30:03551 extensions_enabled_(extensions_enabled),
[email protected]e81dba32009-06-19 20:19:13552 show_extensions_prompts_(true),
[email protected]3ecda252010-11-18 19:50:55553 ready_(false),
[email protected]14908b72011-04-20 06:54:36554 toolbar_model_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
[email protected]902fd7b2011-07-27 18:42:31555 permissions_manager_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
[email protected]18cc5a52011-04-15 16:03:38556 apps_promo_(profile->GetPrefs()),
[email protected]b3d62312b12010-10-14 21:10:18557 event_routers_initialized_(false) {
[email protected]a29a517a2011-01-21 21:11:12558 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]a8af9fdb2010-10-28 21:52:20559
[email protected]36a784c2009-06-23 06:21:08560 // Figure out if extension installation should be enabled.
[email protected]6d60703b2009-08-29 01:29:23561 if (command_line->HasSwitch(switches::kDisableExtensions)) {
562 extensions_enabled_ = false;
563 } else if (profile->GetPrefs()->GetBoolean(prefs::kDisableExtensions)) {
564 extensions_enabled_ = false;
[email protected]6b75ec32009-08-14 06:37:18565 }
[email protected]36a784c2009-06-23 06:21:08566
[email protected]432115822011-07-10 15:52:27567 registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED,
[email protected]bc535ee52010-08-31 18:40:32568 NotificationService::AllSources());
[email protected]432115822011-07-10 15:52:27569 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CREATED,
[email protected]77a6970c2011-04-23 16:58:56570 NotificationService::AllSources());
[email protected]432115822011-07-10 15:52:27571 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
[email protected]da5683db2011-04-23 17:12:21572 NotificationService::AllSources());
[email protected]2fb7dc982010-09-29 12:24:28573 pref_change_registrar_.Init(profile->GetPrefs());
574 pref_change_registrar_.Add(prefs::kExtensionInstallAllowList, this);
575 pref_change_registrar_.Add(prefs::kExtensionInstallDenyList, this);
[email protected]4814b512009-11-07 00:12:29576
[email protected]93fd78f42009-07-10 16:43:17577 // Set up the ExtensionUpdater
578 if (autoupdate_enabled) {
579 int update_frequency = kDefaultUpdateFrequencySeconds;
580 if (command_line->HasSwitch(switches::kExtensionsUpdateFrequency)) {
[email protected]e83326f2010-07-31 17:29:25581 base::StringToInt(command_line->GetSwitchValueASCII(
582 switches::kExtensionsUpdateFrequency),
583 &update_frequency);
[email protected]93fd78f42009-07-10 16:43:17584 }
[email protected]82b6e512011-04-12 20:33:27585 updater_.reset(new ExtensionUpdater(this,
586 extension_prefs,
587 profile->GetPrefs(),
588 profile,
589 update_frequency));
[email protected]93fd78f42009-07-10 16:43:17590 }
591
[email protected]14908b72011-04-20 06:54:36592 backend_ =
593 new ExtensionServiceBackend(weak_ptr_factory_.GetWeakPtr(),
594 install_directory_);
[email protected]8e4560b62011-01-14 10:09:14595
[email protected]0436b102011-04-15 18:30:03596 if (extensions_enabled_) {
[email protected]873531342011-03-09 12:16:05597 ExternalExtensionProviderImpl::CreateExternalProviders(
598 this, profile_, &external_extension_providers_);
599 }
[email protected]b671760b2010-07-15 21:13:47600
[email protected]aa96d3a2010-08-21 08:45:25601 // Use monochrome icons for Omnibox icons.
[email protected]29d0d4ac2010-09-08 21:10:31602 omnibox_popup_icon_manager_.set_monochrome(true);
[email protected]b671760b2010-07-15 21:13:47603 omnibox_icon_manager_.set_monochrome(true);
[email protected]29d0d4ac2010-09-08 21:10:31604 omnibox_icon_manager_.set_padding(gfx::Insets(0, kOmniboxIconPaddingLeft,
605 0, kOmniboxIconPaddingRight));
[email protected]cb0e50312011-05-09 15:03:07606
607 // How long is the path to the Extensions directory?
608 UMA_HISTOGRAM_CUSTOM_COUNTS("Extensions.ExtensionRootPathLength",
609 install_directory_.value().length(), 0, 500, 100);
[email protected]6014d672008-12-05 00:38:25610}
611
[email protected]eaa7dd182010-12-14 11:09:00612const ExtensionList* ExtensionService::extensions() const {
[email protected]ddb1e5a2010-12-13 20:10:45613 return &extensions_;
614}
615
[email protected]eaa7dd182010-12-14 11:09:00616const ExtensionList* ExtensionService::disabled_extensions() const {
[email protected]ddb1e5a2010-12-13 20:10:45617 return &disabled_extensions_;
618}
619
[email protected]bb7f40952011-01-13 00:21:20620const ExtensionList* ExtensionService::terminated_extensions() const {
621 return &terminated_extensions_;
622}
623
[email protected]b2907fd2011-03-25 16:43:37624PendingExtensionManager* ExtensionService::pending_extension_manager() {
625 return &pending_extension_manager_;
[email protected]ddb1e5a2010-12-13 20:10:45626}
627
[email protected]ad63a792011-06-16 06:41:11628void ExtensionService::UnregisterComponentExtension(
629 const ComponentExtensionInfo& info) {
630 RegisteredComponentExtensions new_component_extension_manifests;
631 for (RegisteredComponentExtensions::iterator it =
632 component_extension_manifests_.begin();
633 it != component_extension_manifests_.end(); ++it) {
634 if (!it->Equals(info))
635 new_component_extension_manifests.push_back(*it);
636 }
637 component_extension_manifests_.swap(new_component_extension_manifests);
638}
639
[email protected]eaa7dd182010-12-14 11:09:00640ExtensionService::~ExtensionService() {
[email protected]c8d407e2011-04-28 21:27:17641 // No need to unload extensions here because they are profile-scoped, and the
642 // profile is in the process of being deleted.
[email protected]94b4ffc2011-02-04 05:55:17643
[email protected]8e4560b62011-01-14 10:09:14644 ProviderCollection::const_iterator i;
645 for (i = external_extension_providers_.begin();
646 i != external_extension_providers_.end(); ++i) {
647 ExternalExtensionProviderInterface* provider = i->get();
648 provider->ServiceShutdown();
649 }
[email protected]6014d672008-12-05 00:38:25650}
651
[email protected]eaa7dd182010-12-14 11:09:00652void ExtensionService::InitEventRouters() {
[email protected]b3d62312b12010-10-14 21:10:18653 if (event_routers_initialized_)
654 return;
655
[email protected]f825df22011-06-28 17:36:10656 history_event_router_.reset(new ExtensionHistoryEventRouter());
657 history_event_router_->ObserveProfile(profile_);
[email protected]7da9a8232011-05-27 21:07:11658 ExtensionAccessibilityEventRouter::GetInstance()->ObserveProfile(profile_);
[email protected]97d2f1d2011-01-15 00:41:08659 browser_event_router_.reset(new ExtensionBrowserEventRouter(profile_));
660 browser_event_router_->Init();
[email protected]118de7892011-03-16 13:31:40661 preference_event_router_.reset(new ExtensionPreferenceEventRouter(profile_));
[email protected]f825df22011-06-28 17:36:10662 bookmark_event_router_.reset(new ExtensionBookmarkEventRouter(
663 profile_->GetBookmarkModel()));
664 bookmark_event_router_->Init();
665 cookies_event_router_.reset(new ExtensionCookiesEventRouter(profile_));
666 cookies_event_router_->Init();
667 management_event_router_.reset(new ExtensionManagementEventRouter(profile_));
668 management_event_router_->Init();
[email protected]7da9a8232011-05-27 21:07:11669 ExtensionProcessesEventRouter::GetInstance()->ObserveProfile(profile_);
[email protected]f825df22011-06-28 17:36:10670 web_navigation_event_router_.reset(
671 new ExtensionWebNavigationEventRouter(profile_));
672 web_navigation_event_router_->Init();
[email protected]27072cad2011-05-09 19:46:40673
[email protected]eed367e2011-04-12 03:43:31674#if defined(OS_CHROMEOS)
[email protected]b16fc2e2011-07-21 21:32:58675 file_browser_event_router_.reset(
676 new ExtensionFileBrowserEventRouter(profile_));
677 file_browser_event_router_->ObserveFileSystemEvents();
[email protected]be5bd5742011-07-14 07:21:01678 // Lazy initialization.
679 chromeos::ExtensionInputMethodEventRouter::GetInstance();
680
[email protected]c8bf09be2011-06-25 03:22:27681 ExtensionMediaPlayerEventRouter::GetInstance()->Init(profile_);
[email protected]eed367e2011-04-12 03:43:31682#endif
[email protected]27072cad2011-05-09 19:46:40683
684#if defined(OS_CHROMEOS) && defined(TOUCH_UI)
685 ExtensionInputUiEventRouter::GetInstance()->Init();
686#endif
687
[email protected]b3d62312b12010-10-14 21:10:18688 event_routers_initialized_ = true;
[email protected]c5ae74ab2010-04-15 18:14:37689}
690
[email protected]b2907fd2011-03-25 16:43:37691const Extension* ExtensionService::GetExtensionById(
692 const std::string& id, bool include_disabled) const {
[email protected]8001df22011-04-28 19:59:47693 return GetExtensionByIdInternal(id, true, include_disabled, false);
[email protected]78994ab02010-12-08 18:06:44694}
695
[email protected]eaa7dd182010-12-14 11:09:00696void ExtensionService::Init() {
[email protected]a29a517a2011-01-21 21:11:12697 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]a8af9fdb2010-10-28 21:52:20698
[email protected]fa6a9102010-11-22 15:38:50699 DCHECK(!ready_); // Can't redo init.
[email protected]93fd78f42009-07-10 16:43:17700 DCHECK_EQ(extensions_.size(), 0u);
[email protected]9f1087e2009-06-15 17:29:32701
[email protected]95dd38f2009-10-20 20:09:15702 // Hack: we need to ensure the ResourceDispatcherHost is ready before we load
703 // the first extension, because its members listen for loaded notifications.
704 g_browser_process->resource_dispatcher_host();
705
[email protected]9f1087e2009-06-15 17:29:32706 LoadAllExtensions();
[email protected]894bb502009-05-21 22:39:57707
[email protected]9f1087e2009-06-15 17:29:32708 // TODO(erikkay) this should probably be deferred to a future point
709 // rather than running immediately at startup.
[email protected]93fd78f42009-07-10 16:43:17710 CheckForExternalUpdates();
[email protected]894bb502009-05-21 22:39:57711
[email protected]9f1087e2009-06-15 17:29:32712 // TODO(erikkay) this should probably be deferred as well.
713 GarbageCollectExtensions();
[email protected]6014d672008-12-05 00:38:25714}
715
[email protected]420a0ec2011-06-01 01:07:03716bool ExtensionService::UpdateExtension(
717 const std::string& id,
718 const FilePath& extension_path,
719 const GURL& download_url,
720 CrxInstaller** out_crx_installer) {
[email protected]a29a517a2011-01-21 21:11:12721 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]a8af9fdb2010-10-28 21:52:20722
[email protected]b2907fd2011-03-25 16:43:37723 PendingExtensionInfo pending_extension_info;
724 bool is_pending_extension = pending_extension_manager_.GetById(
725 id, &pending_extension_info);
[email protected]8ef78fd2010-08-19 17:14:32726
[email protected]8001df22011-04-28 19:59:47727 const Extension* extension =
728 GetExtensionByIdInternal(id, true, true, false);
[email protected]5eb375e92010-11-26 07:50:41729 if (!is_pending_extension && !extension) {
[email protected]aa142702010-03-26 01:26:33730 LOG(WARNING) << "Will not update extension " << id
731 << " because it is not installed or pending";
732 // Delete extension_path since we're not creating a CrxInstaller
733 // that would do it for us.
[email protected]14908b72011-04-20 06:54:36734 if (!BrowserThread::PostTask(
735 BrowserThread::FILE, FROM_HERE,
736 NewRunnableFunction(
737 extension_file_util::DeleteFile, extension_path, false)))
738 NOTREACHED();
[email protected]420a0ec2011-06-01 01:07:03739
740 return false;
[email protected]e957fe52009-06-23 16:51:05741 }
742
[email protected]aa142702010-03-26 01:26:33743 // We want a silent install only for non-pending extensions and
744 // pending extensions that have install_silently set.
745 ExtensionInstallUI* client =
[email protected]b2907fd2011-03-25 16:43:37746 (!is_pending_extension || pending_extension_info.install_silently()) ?
[email protected]aa142702010-03-26 01:26:33747 NULL : new ExtensionInstallUI(profile_);
748
[email protected]14908b72011-04-20 06:54:36749 scoped_refptr<CrxInstaller> installer(MakeCrxInstaller(client));
[email protected]6dfbbf82010-03-12 23:09:16750 installer->set_expected_id(id);
[email protected]ec5b50d2010-10-09 16:35:18751 if (is_pending_extension)
[email protected]b2907fd2011-03-25 16:43:37752 installer->set_install_source(pending_extension_info.install_source());
[email protected]5eb375e92010-11-26 07:50:41753 else if (extension)
754 installer->set_install_source(extension->location());
[email protected]0d3e4a22011-06-23 19:02:52755 if (pending_extension_info.install_silently())
756 installer->set_allow_silent_install(true);
[email protected]6dfbbf82010-03-12 23:09:16757 installer->set_delete_source(true);
[email protected]5c8516202010-03-18 21:43:34758 installer->set_original_url(download_url);
[email protected]cb0e50312011-05-09 15:03:07759 installer->set_install_cause(extension_misc::INSTALL_CAUSE_UPDATE);
[email protected]6dfbbf82010-03-12 23:09:16760 installer->InstallCrx(extension_path);
[email protected]420a0ec2011-06-01 01:07:03761
762 if (out_crx_installer)
763 *out_crx_installer = installer;
764
765 return true;
[email protected]e957fe52009-06-23 16:51:05766}
767
[email protected]eaa7dd182010-12-14 11:09:00768void ExtensionService::ReloadExtension(const std::string& extension_id) {
[email protected]a29a517a2011-01-21 21:11:12769 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]b65272f2009-08-31 15:47:06770 FilePath path;
[email protected]9adb9692010-10-29 23:14:02771 const Extension* current_extension = GetExtensionById(extension_id, false);
[email protected]9cddd4702009-07-27 22:09:40772
[email protected]f17dbd42010-08-16 23:21:10773 // Disable the extension if it's loaded. It might not be loaded if it crashed.
[email protected]b65272f2009-08-31 15:47:06774 if (current_extension) {
[email protected]4814b512009-11-07 00:12:29775 // If the extension has an inspector open for its background page, detach
776 // the inspector and hang onto a cookie for it, so that we can reattach
777 // later.
778 ExtensionProcessManager* manager = profile_->GetExtensionProcessManager();
779 ExtensionHost* host = manager->GetBackgroundHostForExtension(
780 current_extension);
781 if (host) {
782 // Look for an open inspector for the background page.
783 int devtools_cookie = DevToolsManager::GetInstance()->DetachClientHost(
784 host->render_view_host());
785 if (devtools_cookie >= 0)
786 orphaned_dev_tools_[extension_id] = devtools_cookie;
787 }
788
[email protected]b65272f2009-08-31 15:47:06789 path = current_extension->path();
[email protected]f17dbd42010-08-16 23:21:10790 DisableExtension(extension_id);
791 disabled_extension_paths_[extension_id] = path;
[email protected]1eb175082010-02-10 09:26:16792 } else {
793 path = unloaded_extension_paths_[extension_id];
[email protected]b65272f2009-08-31 15:47:06794 }
795
[email protected]e6090e42010-03-23 22:44:08796 // Check the installed extensions to see if what we're reloading was already
797 // installed.
798 scoped_ptr<ExtensionInfo> installed_extension(
799 extension_prefs_->GetInstalledExtensionInfo(extension_id));
800 if (installed_extension.get() &&
801 installed_extension->extension_manifest.get()) {
802 LoadInstalledExtension(*installed_extension, false);
803 } else {
804 // We should always be able to remember the extension's path. If it's not in
805 // the map, someone failed to update |unloaded_extension_paths_|.
806 CHECK(!path.empty());
807 LoadExtension(path);
808 }
[email protected]9cddd4702009-07-27 22:09:40809}
810
[email protected]fa2416f2011-05-03 08:41:20811bool ExtensionService::UninstallExtension(
812 const std::string& extension_id_unsafe,
813 bool external_uninstall,
814 std::string* error) {
[email protected]a29a517a2011-01-21 21:11:12815 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]a8af9fdb2010-10-28 21:52:20816
[email protected]fa2416f2011-05-03 08:41:20817 // Copy the extension identifier since the reference might have been
818 // obtained via Extension::id() and the extension may be deleted in
819 // this function.
820 std::string extension_id(extension_id_unsafe);
821
[email protected]8001df22011-04-28 19:59:47822 const Extension* extension = GetInstalledExtension(extension_id);
[email protected]631cf822009-05-15 07:01:25823
[email protected]e7afe2452010-08-22 16:19:13824 // Callers should not send us nonexistent extensions.
[email protected]aebe23a32010-12-10 22:15:48825 CHECK(extension);
[email protected]9f1087e2009-06-15 17:29:32826
[email protected]831aa212010-03-26 13:55:19827 // Get hold of information we need after unloading, since the extension
828 // pointer will be invalid then.
829 GURL extension_url(extension->url());
830 Extension::Location location(extension->location());
[email protected]95da88c42011-03-31 10:07:33831
832 // Policy change which triggers an uninstall will always set
833 // |external_uninstall| to true so this is the only way to uninstall
834 // managed extensions.
[email protected]d6ebc9792011-04-07 18:18:33835 if (!Extension::UserMayDisable(location) && !external_uninstall) {
836 NotificationService::current()->Notify(
[email protected]432115822011-07-10 15:52:27837 chrome::NOTIFICATION_EXTENSION_UNINSTALL_NOT_ALLOWED,
[email protected]d6ebc9792011-04-07 18:18:33838 Source<Profile>(profile_),
839 Details<const Extension>(extension));
840 if (error != NULL) {
841 *error = errors::kCannotUninstallManagedExtension;
842 }
843 return false;
844 }
[email protected]95da88c42011-03-31 10:07:33845
[email protected]211030342010-09-30 18:41:06846 UninstalledExtensionInfo uninstalled_extension_info(*extension);
[email protected]831aa212010-03-26 13:55:19847
[email protected]9b217652010-10-08 22:04:23848 UMA_HISTOGRAM_ENUMERATION("Extensions.UninstallType",
[email protected]7fa19f82010-12-21 19:40:08849 extension->GetType(), 100);
[email protected]fe2dd7742011-04-19 22:52:49850 RecordPermissionMessagesHistogram(
851 extension, "Extensions.Permissions_Uninstall");
[email protected]9b217652010-10-08 22:04:23852
[email protected]8e5c89a2011-06-07 18:13:33853 TemplateURLService* url_service =
854 TemplateURLServiceFactory::GetForProfile(profile_);
855 if (url_service)
856 url_service->UnregisterExtensionKeyword(extension);
[email protected]56ad3792010-05-28 17:45:33857
[email protected]831aa212010-03-26 13:55:19858 // Unload before doing more cleanup to ensure that nothing is hanging on to
859 // any of these resources.
[email protected]a9f39a312010-12-23 22:14:27860 UnloadExtension(extension_id, UnloadedExtensionInfo::UNINSTALL);
[email protected]831aa212010-03-26 13:55:19861
[email protected]fa2416f2011-05-03 08:41:20862 extension_prefs_->OnExtensionUninstalled(extension_id, location,
[email protected]831aa212010-03-26 13:55:19863 external_uninstall);
[email protected]9f1087e2009-06-15 17:29:32864
865 // Tell the backend to start deleting installed extensions on the file thread.
[email protected]831aa212010-03-26 13:55:19866 if (Extension::LOAD != location) {
[email protected]14908b72011-04-20 06:54:36867 if (!BrowserThread::PostTask(
868 BrowserThread::FILE, FROM_HERE,
869 NewRunnableFunction(
870 &extension_file_util::UninstallExtension,
871 install_directory_,
[email protected]fa2416f2011-05-03 08:41:20872 extension_id)))
[email protected]14908b72011-04-20 06:54:36873 NOTREACHED();
[email protected]9f1087e2009-06-15 17:29:32874 }
875
[email protected]c10da4b02010-03-25 14:38:32876 ClearExtensionData(extension_url);
[email protected]0dfe05c2011-02-23 23:03:36877 UntrackTerminatedExtension(extension_id);
[email protected]211030342010-09-30 18:41:06878
879 // Notify interested parties that we've uninstalled this extension.
880 NotificationService::current()->Notify(
[email protected]432115822011-07-10 15:52:27881 chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
[email protected]211030342010-09-30 18:41:06882 Source<Profile>(profile_),
883 Details<UninstalledExtensionInfo>(&uninstalled_extension_info));
[email protected]d6ebc9792011-04-07 18:18:33884
885 return true;
[email protected]c10da4b02010-03-25 14:38:32886}
887
[email protected]eaa7dd182010-12-14 11:09:00888void ExtensionService::ClearExtensionData(const GURL& extension_url) {
[email protected]c10da4b02010-03-25 14:38:32889 scoped_refptr<ExtensionDataDeleter> deleter(
890 new ExtensionDataDeleter(profile_, extension_url));
891 deleter->StartDeleting();
[email protected]9f1087e2009-06-15 17:29:32892}
893
[email protected]c3cfb012011-04-06 22:07:35894bool ExtensionService::IsExtensionEnabled(
895 const std::string& extension_id) const {
[email protected]36429da2011-07-11 20:25:18896 const Extension* extension =
[email protected]ad83ca242011-07-29 01:32:25897 GetExtensionByIdInternal(extension_id, true, false, true);
[email protected]36429da2011-07-11 20:25:18898 if (extension)
899 return true;
900
[email protected]ad83ca242011-07-29 01:32:25901 extension =
902 GetExtensionByIdInternal(extension_id, false, true, false);
903 if (extension)
904 return false;
905
906 // If the extension hasn't been loaded yet, check the prefs for it. Assume
907 // enabled unless otherwise noted.
908 return !extension_prefs_->IsExtensionDisabled(extension_id) &&
909 !extension_prefs_->IsExternalExtensionUninstalled(extension_id);
[email protected]c3cfb012011-04-06 22:07:35910}
911
912bool ExtensionService::IsExternalExtensionUninstalled(
913 const std::string& extension_id) const {
914 return extension_prefs_->IsExternalExtensionUninstalled(extension_id);
915}
916
[email protected]eaa7dd182010-12-14 11:09:00917void ExtensionService::EnableExtension(const std::string& extension_id) {
[email protected]a29a517a2011-01-21 21:11:12918 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]a8af9fdb2010-10-28 21:52:20919
[email protected]06f92562011-04-29 19:27:31920 if (IsExtensionEnabled(extension_id))
[email protected]0c6da502009-08-14 22:32:39921 return;
[email protected]0c6da502009-08-14 22:32:39922
[email protected]b3317ad2011-04-28 23:46:00923 extension_prefs_->SetExtensionState(extension_id, Extension::ENABLED);
[email protected]1784e83a2009-09-08 21:01:52924
[email protected]06f92562011-04-29 19:27:31925 const Extension* extension =
926 GetExtensionByIdInternal(extension_id, false, true, false);
927 // This can happen if sync enables an extension that is not
928 // installed yet.
929 if (!extension)
930 return;
931
[email protected]0c6da502009-08-14 22:32:39932 // Move it over to the enabled list.
[email protected]00cd9c42010-11-02 20:15:57933 extensions_.push_back(make_scoped_refptr(extension));
[email protected]0c6da502009-08-14 22:32:39934 ExtensionList::iterator iter = std::find(disabled_extensions_.begin(),
935 disabled_extensions_.end(),
936 extension);
937 disabled_extensions_.erase(iter);
938
[email protected]f681c782010-11-19 11:19:39939 // Make sure any browser action contained within it is not hidden.
940 extension_prefs_->SetBrowserActionVisibility(extension, true);
941
[email protected]62d30f42009-10-01 22:36:06942 NotifyExtensionLoaded(extension);
[email protected]0c6da502009-08-14 22:32:39943}
944
[email protected]eaa7dd182010-12-14 11:09:00945void ExtensionService::DisableExtension(const std::string& extension_id) {
[email protected]a29a517a2011-01-21 21:11:12946 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]a8af9fdb2010-10-28 21:52:20947
[email protected]b2ba9962009-12-10 20:10:15948 // The extension may have been disabled already.
[email protected]06f92562011-04-29 19:27:31949 if (!IsExtensionEnabled(extension_id))
[email protected]1784e83a2009-09-08 21:01:52950 return;
[email protected]1784e83a2009-09-08 21:01:52951
[email protected]06f92562011-04-29 19:27:31952 const Extension* extension = GetInstalledExtension(extension_id);
953 // |extension| can be NULL if sync disables an extension that is not
954 // installed yet.
955 if (extension && !Extension::UserMayDisable(extension->location()))
[email protected]95da88c42011-03-31 10:07:33956 return;
957
[email protected]b3317ad2011-04-28 23:46:00958 extension_prefs_->SetExtensionState(extension_id, Extension::DISABLED);
[email protected]1784e83a2009-09-08 21:01:52959
[email protected]06f92562011-04-29 19:27:31960 extension = GetExtensionByIdInternal(extension_id, true, false, true);
961 if (!extension)
962 return;
963
[email protected]1784e83a2009-09-08 21:01:52964 // Move it over to the disabled list.
[email protected]00cd9c42010-11-02 20:15:57965 disabled_extensions_.push_back(make_scoped_refptr(extension));
[email protected]1784e83a2009-09-08 21:01:52966 ExtensionList::iterator iter = std::find(extensions_.begin(),
967 extensions_.end(),
968 extension);
[email protected]06f92562011-04-29 19:27:31969 if (iter != extensions_.end()) {
970 extensions_.erase(iter);
971 } else {
972 iter = std::find(terminated_extensions_.begin(),
973 terminated_extensions_.end(),
974 extension);
975 terminated_extensions_.erase(iter);
976 }
[email protected]1784e83a2009-09-08 21:01:52977
[email protected]a9f39a312010-12-23 22:14:27978 NotifyExtensionUnloaded(extension, UnloadedExtensionInfo::DISABLE);
[email protected]1784e83a2009-09-08 21:01:52979}
980
[email protected]eaa7dd182010-12-14 11:09:00981void ExtensionService::GrantPermissions(const Extension* extension) {
[email protected]8d888c12010-11-30 00:00:25982 CHECK(extension);
983
[email protected]902fd7b2011-07-27 18:42:31984 // We only maintain the granted permissions prefs for extensions that can't
985 // silently increase their permissions.
986 if (extension->CanSilentlyIncreasePermissions())
987 return;
[email protected]8d888c12010-11-30 00:00:25988
[email protected]8d888c12010-11-30 00:00:25989 extension_prefs_->AddGrantedPermissions(extension->id(),
[email protected]902fd7b2011-07-27 18:42:31990 extension->GetActivePermissions());
[email protected]8d888c12010-11-30 00:00:25991}
992
[email protected]eaa7dd182010-12-14 11:09:00993void ExtensionService::GrantPermissionsAndEnableExtension(
[email protected]8d888c12010-11-30 00:00:25994 const Extension* extension) {
995 CHECK(extension);
[email protected]fe2dd7742011-04-19 22:52:49996 RecordPermissionMessagesHistogram(
997 extension, "Extensions.Permissions_ReEnable");
[email protected]8d888c12010-11-30 00:00:25998 GrantPermissions(extension);
999 extension_prefs_->SetDidExtensionEscalatePermissions(extension, false);
1000 EnableExtension(extension->id());
1001}
1002
[email protected]902fd7b2011-07-27 18:42:311003void ExtensionService::UpdateActivePermissions(
1004 const Extension* extension,
1005 const ExtensionPermissionSet* permissions) {
1006 extension_prefs()->SetActivePermissions(extension->id(), permissions);
1007 extension->SetActivePermissions(permissions);
1008}
1009
[email protected]eaa7dd182010-12-14 11:09:001010void ExtensionService::LoadExtension(const FilePath& extension_path) {
[email protected]e49002a2011-07-13 03:40:441011 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
1012 NewRunnableMethod(backend_.get(),
1013 &ExtensionServiceBackend::LoadSingleExtension,
1014 extension_path, true));
1015}
1016
1017void ExtensionService::LoadExtensionFromCommandLine(
[email protected]67d2d802011-07-21 02:54:281018 const FilePath& path_in) {
1019
1020 // Load extensions from the command line synchronously to avoid a race
1021 // between extension loading and loading an URL from the command line.
1022 base::ThreadRestrictions::ScopedAllowIO allow_io;
1023
1024 FilePath extension_path = path_in;
1025 file_util::AbsolutePath(&extension_path);
1026
1027 std::string id = Extension::GenerateIdForPath(extension_path);
1028 bool allow_file_access =
1029 Extension::ShouldAlwaysAllowFileAccess(Extension::LOAD);
1030 if (extension_prefs()->HasAllowFileAccessSetting(id))
1031 allow_file_access = extension_prefs()->AllowFileAccess(id);
1032
1033 int flags = Extension::NO_FLAGS;
1034 if (allow_file_access)
1035 flags |= Extension::ALLOW_FILE_ACCESS;
1036 if (Extension::ShouldDoStrictErrorChecking(Extension::LOAD))
1037 flags |= Extension::STRICT_ERROR_CHECKS;
1038
1039 std::string error;
1040 scoped_refptr<const Extension> extension(extension_file_util::LoadExtension(
1041 extension_path,
1042 Extension::LOAD,
1043 flags,
1044 &error));
1045
1046 if (!extension) {
1047 ReportExtensionLoadError(
1048 extension_path,
1049 error,
1050 chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
1051 true);
1052 return;
1053 }
1054
1055 OnLoadSingleExtension(extension, false);
[email protected]9f1087e2009-06-15 17:29:321056}
1057
[email protected]eaa7dd182010-12-14 11:09:001058void ExtensionService::LoadComponentExtensions() {
[email protected]1952c7d2010-03-04 23:48:341059 for (RegisteredComponentExtensions::iterator it =
1060 component_extension_manifests_.begin();
1061 it != component_extension_manifests_.end(); ++it) {
[email protected]61b55b62011-03-24 09:03:101062 LoadComponentExtension(*it);
[email protected]1952c7d2010-03-04 23:48:341063 }
1064}
1065
[email protected]a964e112011-04-14 21:52:511066const Extension* ExtensionService::LoadComponentExtension(
[email protected]61b55b62011-03-24 09:03:101067 const ComponentExtensionInfo &info) {
1068 JSONStringValueSerializer serializer(info.manifest);
1069 scoped_ptr<Value> manifest(serializer.Deserialize(NULL, NULL));
1070 if (!manifest.get()) {
1071 DLOG(ERROR) << "Failed to parse manifest for extension";
[email protected]a964e112011-04-14 21:52:511072 return NULL;
[email protected]61b55b62011-03-24 09:03:101073 }
1074
[email protected]83048a22011-03-29 00:14:131075 int flags = Extension::REQUIRE_KEY;
1076 if (Extension::ShouldDoStrictErrorChecking(Extension::COMPONENT))
1077 flags |= Extension::STRICT_ERROR_CHECKS;
[email protected]61b55b62011-03-24 09:03:101078 std::string error;
1079 scoped_refptr<const Extension> extension(Extension::Create(
1080 info.root_directory,
1081 Extension::COMPONENT,
1082 *static_cast<DictionaryValue*>(manifest.get()),
[email protected]83048a22011-03-29 00:14:131083 flags,
[email protected]61b55b62011-03-24 09:03:101084 &error));
1085 if (!extension.get()) {
1086 NOTREACHED() << error;
[email protected]a964e112011-04-14 21:52:511087 return NULL;
[email protected]61b55b62011-03-24 09:03:101088 }
1089 AddExtension(extension);
[email protected]a964e112011-04-14 21:52:511090 return extension;
[email protected]61b55b62011-03-24 09:03:101091}
1092
[email protected]ad63a792011-06-16 06:41:111093void ExtensionService::UnloadComponentExtension(
1094 const ComponentExtensionInfo& info) {
1095 JSONStringValueSerializer serializer(info.manifest);
1096 scoped_ptr<Value> manifest(serializer.Deserialize(NULL, NULL));
1097 if (!manifest.get()) {
1098 DLOG(ERROR) << "Failed to parse manifest for extension";
1099 return;
1100 }
1101 std::string public_key;
1102 std::string public_key_bytes;
1103 std::string id;
1104 if (!static_cast<DictionaryValue*>(manifest.get())->
1105 GetString(extension_manifest_keys::kPublicKey, &public_key) ||
1106 !Extension::ParsePEMKeyBytes(public_key, &public_key_bytes) ||
1107 !Extension::GenerateId(public_key_bytes, &id)) {
1108 DLOG(ERROR) << "Failed to get extension id";
1109 return;
1110 }
1111 UnloadExtension(id, UnloadedExtensionInfo::DISABLE);
1112}
1113
[email protected]eaa7dd182010-12-14 11:09:001114void ExtensionService::LoadAllExtensions() {
[email protected]a29a517a2011-01-21 21:11:121115 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]a315ba92010-11-16 14:12:211116
[email protected]cc2c3432009-11-06 17:24:361117 base::TimeTicks start_time = base::TimeTicks::Now();
1118
[email protected]1952c7d2010-03-04 23:48:341119 // Load any component extensions.
1120 LoadComponentExtensions();
1121
[email protected]e72e8eb82009-06-18 17:21:511122 // Load the previously installed extensions.
[email protected]a315ba92010-11-16 14:12:211123 scoped_ptr<ExtensionPrefs::ExtensionsInfo> extensions_info(
[email protected]e6090e42010-03-23 22:44:081124 extension_prefs_->GetInstalledExtensionsInfo());
[email protected]c6d474f82009-12-16 21:11:061125
[email protected]a315ba92010-11-16 14:12:211126 std::vector<int> reload_reason_counts(NUM_MANIFEST_RELOAD_REASONS, 0);
1127 bool should_write_prefs = false;
1128
1129 for (size_t i = 0; i < extensions_info->size(); ++i) {
1130 ExtensionInfo* info = extensions_info->at(i).get();
1131
1132 ManifestReloadReason reload_reason = ShouldReloadExtensionManifest(*info);
1133 ++reload_reason_counts[reload_reason];
1134 UMA_HISTOGRAM_ENUMERATION("Extensions.ManifestReloadEnumValue",
1135 reload_reason, 100);
1136
1137 if (reload_reason != NOT_NEEDED) {
1138 // Reloading and extension reads files from disk. We do this on the
1139 // UI thread because reloads should be very rare, and the complexity
1140 // added by delaying the time when the extensions service knows about
1141 // all extensions is significant. See crbug.com/37548 for details.
1142 // |allow_io| disables tests that file operations run on the file
1143 // thread.
1144 base::ThreadRestrictions::ScopedAllowIO allow_io;
1145
[email protected]83048a22011-03-29 00:14:131146 int flags = Extension::NO_FLAGS;
1147 if (Extension::ShouldDoStrictErrorChecking(info->extension_location))
1148 flags |= Extension::STRICT_ERROR_CHECKS;
[email protected]3aff9ad2011-04-01 20:26:481149 if (extension_prefs_->AllowFileAccess(info->extension_id))
1150 flags |= Extension::ALLOW_FILE_ACCESS;
[email protected]620db1762011-07-15 21:57:341151 if (extension_prefs_->IsFromWebStore(info->extension_id))
1152 flags |= Extension::FROM_WEBSTORE;
[email protected]e805baf2011-07-26 18:23:051153 if (extension_prefs_->IsFromBookmark(info->extension_id))
1154 flags |= Extension::FROM_BOOKMARK;
[email protected]a315ba92010-11-16 14:12:211155 std::string error;
1156 scoped_refptr<const Extension> extension(
1157 extension_file_util::LoadExtension(
[email protected]542258c2011-03-04 21:25:311158 info->extension_path,
1159 info->extension_location,
[email protected]83048a22011-03-29 00:14:131160 flags,
[email protected]542258c2011-03-04 21:25:311161 &error));
[email protected]a315ba92010-11-16 14:12:211162
1163 if (extension.get()) {
1164 extensions_info->at(i)->extension_manifest.reset(
1165 static_cast<DictionaryValue*>(
1166 extension->manifest_value()->DeepCopy()));
1167 should_write_prefs = true;
1168 }
[email protected]c6d474f82009-12-16 21:11:061169 }
1170 }
1171
[email protected]a315ba92010-11-16 14:12:211172 for (size_t i = 0; i < extensions_info->size(); ++i) {
1173 LoadInstalledExtension(*extensions_info->at(i), should_write_prefs);
[email protected]c6d474f82009-12-16 21:11:061174 }
1175
[email protected]ae09ca62009-08-21 19:46:461176 OnLoadedInstalledExtensions();
[email protected]cc2c3432009-11-06 17:24:361177
[email protected]a315ba92010-11-16 14:12:211178 // The histograms Extensions.ManifestReload* allow us to validate
1179 // the assumption that reloading manifest is a rare event.
1180 UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadNotNeeded",
1181 reload_reason_counts[NOT_NEEDED]);
1182 UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadUnpackedDir",
1183 reload_reason_counts[UNPACKED_DIR]);
1184 UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadNeedsRelocalization",
1185 reload_reason_counts[NEEDS_RELOCALIZATION]);
1186
[email protected]cc2c3432009-11-06 17:24:361187 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAll", extensions_.size());
1188 UMA_HISTOGRAM_COUNTS_100("Extensions.Disabled", disabled_extensions_.size());
1189
[email protected]1952c7d2010-03-04 23:48:341190 UMA_HISTOGRAM_TIMES("Extensions.LoadAllTime",
1191 base::TimeTicks::Now() - start_time);
[email protected]cc2c3432009-11-06 17:24:361192
[email protected]d101c4a2011-07-22 22:51:361193 int app_user_count = 0;
1194 int app_external_count = 0;
[email protected]9b217652010-10-08 22:04:231195 int hosted_app_count = 0;
1196 int packaged_app_count = 0;
[email protected]1952c7d2010-03-04 23:48:341197 int user_script_count = 0;
[email protected]d101c4a2011-07-22 22:51:361198 int extension_user_count = 0;
1199 int extension_external_count = 0;
[email protected]1952c7d2010-03-04 23:48:341200 int theme_count = 0;
[email protected]1952c7d2010-03-04 23:48:341201 int page_action_count = 0;
1202 int browser_action_count = 0;
1203 ExtensionList::iterator ex;
1204 for (ex = extensions_.begin(); ex != extensions_.end(); ++ex) {
[email protected]9b217652010-10-08 22:04:231205 Extension::Location location = (*ex)->location();
[email protected]7fa19f82010-12-21 19:40:081206 Extension::Type type = (*ex)->GetType();
[email protected]9b217652010-10-08 22:04:231207 if ((*ex)->is_app()) {
1208 UMA_HISTOGRAM_ENUMERATION("Extensions.AppLocation",
1209 location, 100);
1210 } else if (type == Extension::TYPE_EXTENSION) {
1211 UMA_HISTOGRAM_ENUMERATION("Extensions.ExtensionLocation",
1212 location, 100);
1213 }
1214
[email protected]1952c7d2010-03-04 23:48:341215 // Don't count component extensions, since they are only extensions as an
1216 // implementation detail.
[email protected]9b217652010-10-08 22:04:231217 if (location == Extension::COMPONENT)
[email protected]1952c7d2010-03-04 23:48:341218 continue;
1219
[email protected]e8c729a2010-03-09 19:55:191220 // Don't count unpacked extensions, since they're a developer-specific
1221 // feature.
[email protected]9b217652010-10-08 22:04:231222 if (location == Extension::LOAD)
[email protected]e8c729a2010-03-09 19:55:191223 continue;
1224
[email protected]9b217652010-10-08 22:04:231225 // Using an enumeration shows us the total installed ratio across all users.
1226 // Using the totals per user at each startup tells us the distribution of
1227 // usage for each user (e.g. 40% of users have at least one app installed).
1228 UMA_HISTOGRAM_ENUMERATION("Extensions.LoadType", type, 100);
1229 switch (type) {
1230 case Extension::TYPE_THEME:
[email protected]a315ba92010-11-16 14:12:211231 ++theme_count;
[email protected]9b217652010-10-08 22:04:231232 break;
1233 case Extension::TYPE_USER_SCRIPT:
[email protected]a315ba92010-11-16 14:12:211234 ++user_script_count;
[email protected]9b217652010-10-08 22:04:231235 break;
1236 case Extension::TYPE_HOSTED_APP:
[email protected]a315ba92010-11-16 14:12:211237 ++hosted_app_count;
[email protected]d101c4a2011-07-22 22:51:361238 if (Extension::IsExternalLocation(location)) {
1239 ++app_external_count;
1240 } else {
1241 ++app_user_count;
1242 }
[email protected]9b217652010-10-08 22:04:231243 break;
1244 case Extension::TYPE_PACKAGED_APP:
[email protected]a315ba92010-11-16 14:12:211245 ++packaged_app_count;
[email protected]d101c4a2011-07-22 22:51:361246 if (Extension::IsExternalLocation(location)) {
1247 ++app_external_count;
1248 } else {
1249 ++app_user_count;
1250 }
[email protected]9b217652010-10-08 22:04:231251 break;
1252 case Extension::TYPE_EXTENSION:
1253 default:
[email protected]d101c4a2011-07-22 22:51:361254 if (Extension::IsExternalLocation(location)) {
1255 ++extension_external_count;
1256 } else {
1257 ++extension_user_count;
1258 }
[email protected]9b217652010-10-08 22:04:231259 break;
[email protected]cc2c3432009-11-06 17:24:361260 }
[email protected]9b217652010-10-08 22:04:231261 if ((*ex)->page_action() != NULL)
[email protected]a315ba92010-11-16 14:12:211262 ++page_action_count;
[email protected]9b217652010-10-08 22:04:231263 if ((*ex)->browser_action() != NULL)
[email protected]a315ba92010-11-16 14:12:211264 ++browser_action_count;
[email protected]fe2dd7742011-04-19 22:52:491265
1266 RecordPermissionMessagesHistogram(
1267 ex->get(), "Extensions.Permissions_Load");
[email protected]cc2c3432009-11-06 17:24:361268 }
[email protected]d101c4a2011-07-22 22:51:361269 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadApp",
1270 app_user_count + app_external_count);
1271 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAppUser", app_user_count);
1272 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAppExternal", app_external_count);
[email protected]9b217652010-10-08 22:04:231273 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadHostedApp", hosted_app_count);
1274 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPackagedApp", packaged_app_count);
[email protected]d101c4a2011-07-22 22:51:361275 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtension",
1276 extension_user_count + extension_external_count);
1277 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtensionUser",
1278 extension_user_count);
1279 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtensionExternal",
1280 extension_external_count);
[email protected]1952c7d2010-03-04 23:48:341281 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadUserScript", user_script_count);
1282 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadTheme", theme_count);
[email protected]1952c7d2010-03-04 23:48:341283 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPageAction", page_action_count);
1284 UMA_HISTOGRAM_COUNTS_100("Extensions.LoadBrowserAction",
1285 browser_action_count);
[email protected]ae09ca62009-08-21 19:46:461286}
1287
[email protected]fe2dd7742011-04-19 22:52:491288// static
1289void ExtensionService::RecordPermissionMessagesHistogram(
1290 const Extension* e, const char* histogram) {
1291 // Since this is called from multiple sources, and since the Histogram macros
1292 // use statics, we need to manually lookup the Histogram ourselves.
1293 base::Histogram* counter = base::LinearHistogram::FactoryGet(
1294 histogram,
1295 1,
[email protected]0d3e4a22011-06-23 19:02:521296 ExtensionPermissionMessage::kEnumBoundary,
1297 ExtensionPermissionMessage::kEnumBoundary + 1,
[email protected]fe2dd7742011-04-19 22:52:491298 base::Histogram::kUmaTargetedHistogramFlag);
1299
[email protected]0d3e4a22011-06-23 19:02:521300 ExtensionPermissionMessages permissions = e->GetPermissionMessages();
[email protected]fe2dd7742011-04-19 22:52:491301 if (permissions.empty()) {
[email protected]0d3e4a22011-06-23 19:02:521302 counter->Add(ExtensionPermissionMessage::kNone);
[email protected]fe2dd7742011-04-19 22:52:491303 } else {
[email protected]0d3e4a22011-06-23 19:02:521304 for (ExtensionPermissionMessages::iterator it = permissions.begin();
1305 it != permissions.end(); ++it)
1306 counter->Add(it->id());
[email protected]fe2dd7742011-04-19 22:52:491307 }
1308}
1309
[email protected]eaa7dd182010-12-14 11:09:001310void ExtensionService::LoadInstalledExtension(const ExtensionInfo& info,
[email protected]542258c2011-03-04 21:25:311311 bool write_to_prefs) {
[email protected]ae09ca62009-08-21 19:46:461312 std::string error;
[email protected]9adb9692010-10-29 23:14:021313 scoped_refptr<const Extension> extension(NULL);
[email protected]306a2bd2010-08-11 14:56:361314 if (!extension_prefs_->IsExtensionAllowedByPolicy(info.extension_id)) {
1315 error = errors::kDisabledByPolicy;
1316 } else if (info.extension_manifest.get()) {
[email protected]83048a22011-03-29 00:14:131317 int flags = Extension::NO_FLAGS;
1318 if (info.extension_location != Extension::LOAD)
1319 flags |= Extension::REQUIRE_KEY;
1320 if (Extension::ShouldDoStrictErrorChecking(info.extension_location))
1321 flags |= Extension::STRICT_ERROR_CHECKS;
[email protected]3aff9ad2011-04-01 20:26:481322 if (extension_prefs_->AllowFileAccess(info.extension_id))
1323 flags |= Extension::ALLOW_FILE_ACCESS;
[email protected]620db1762011-07-15 21:57:341324 if (extension_prefs_->IsFromWebStore(info.extension_id))
1325 flags |= Extension::FROM_WEBSTORE;
[email protected]e805baf2011-07-26 18:23:051326 if (extension_prefs_->IsFromBookmark(info.extension_id))
1327 flags |= Extension::FROM_BOOKMARK;
[email protected]66e4eb32010-10-27 20:37:411328 extension = Extension::Create(
[email protected]542258c2011-03-04 21:25:311329 info.extension_path,
1330 info.extension_location,
1331 *info.extension_manifest,
[email protected]83048a22011-03-29 00:14:131332 flags,
[email protected]542258c2011-03-04 21:25:311333 &error);
[email protected]ae09ca62009-08-21 19:46:461334 } else {
[email protected]c6d474f82009-12-16 21:11:061335 error = errors::kManifestUnreadable;
[email protected]ae09ca62009-08-21 19:46:461336 }
1337
1338 if (!extension) {
[email protected]c6d474f82009-12-16 21:11:061339 ReportExtensionLoadError(info.extension_path,
[email protected]d11c8e92009-10-20 23:26:401340 error,
[email protected]432115822011-07-10 15:52:271341 chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR,
[email protected]d11c8e92009-10-20 23:26:401342 false);
[email protected]ae09ca62009-08-21 19:46:461343 return;
1344 }
1345
[email protected]c6d474f82009-12-16 21:11:061346 if (write_to_prefs)
1347 extension_prefs_->UpdateManifest(extension);
1348
[email protected]49cd1572011-02-08 21:38:451349 AddExtension(extension);
[email protected]9f1087e2009-06-15 17:29:321350}
1351
[email protected]eaa7dd182010-12-14 11:09:001352void ExtensionService::NotifyExtensionLoaded(const Extension* extension) {
[email protected]57a777f72010-03-31 01:09:421353 // The ChromeURLRequestContexts need to be first to know that the extension
[email protected]62d30f42009-10-01 22:36:061354 // was loaded, otherwise a race can arise where a renderer that is created
1355 // for the extension may try to load an extension URL with an extension id
[email protected]57a777f72010-03-31 01:09:421356 // that the request context doesn't yet know about. The profile is responsible
1357 // for ensuring its URLRequestContexts appropriately discover the loaded
1358 // extension.
[email protected]c8d407e2011-04-28 21:27:171359 profile_->RegisterExtensionWithRequestContexts(extension);
[email protected]62d30f42009-10-01 22:36:061360
[email protected]c8d407e2011-04-28 21:27:171361 // Tell subsystems that use the EXTENSION_LOADED notification about the new
1362 // extension.
[email protected]62d30f42009-10-01 22:36:061363 NotificationService::current()->Notify(
[email protected]432115822011-07-10 15:52:271364 chrome::NOTIFICATION_EXTENSION_LOADED,
[email protected]24e7a9d2009-11-04 11:11:341365 Source<Profile>(profile_),
[email protected]9adb9692010-10-29 23:14:021366 Details<const Extension>(extension));
[email protected]2de307592011-04-05 21:16:581367
[email protected]c8d407e2011-04-28 21:27:171368 // Tell renderers about the new extension.
[email protected]77a6970c2011-04-23 16:58:561369 for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
1370 !i.IsAtEnd(); i.Advance()) {
[email protected]c8d407e2011-04-28 21:27:171371 RenderProcessHost* host = i.GetCurrentValue();
[email protected]9b62ecf2011-07-27 20:23:081372 Profile* host_profile =
1373 Profile::FromBrowserContext(host->browser_context());
1374 if (host_profile->GetOriginalProfile() == profile_->GetOriginalProfile()) {
[email protected]c8d407e2011-04-28 21:27:171375 host->Send(
[email protected]902fd7b2011-07-27 18:42:311376 new ExtensionMsg_Loaded(ExtensionMsg_Loaded_Params(
1377 extension, extension->GetActivePermissions())));
[email protected]c8d407e2011-04-28 21:27:171378 }
[email protected]77a6970c2011-04-23 16:58:561379 }
1380
[email protected]c8d407e2011-04-28 21:27:171381 // Tell a random-ass collection of other subsystems about the new extension.
1382 // TODO(aa): What should we do with all this goop? Can it move into the
1383 // relevant objects via EXTENSION_LOADED?
1384
1385 profile_->GetExtensionSpecialStoragePolicy()->
1386 GrantRightsForExtension(extension);
1387
1388 UpdateActiveExtensionsInCrashReporter();
1389
1390 ExtensionWebUI::RegisterChromeURLOverrides(
1391 profile_, extension->GetChromeURLOverrides());
1392
[email protected]8e5c89a2011-06-07 18:13:331393 TemplateURLService* url_service =
1394 TemplateURLServiceFactory::GetForProfile(profile_);
1395 if (url_service)
1396 url_service->RegisterExtensionKeyword(extension);
[email protected]c8d407e2011-04-28 21:27:171397
1398 // Load the icon for omnibox-enabled extensions so it will be ready to display
1399 // in the URL bar.
1400 if (!extension->omnibox_keyword().empty()) {
1401 omnibox_popup_icon_manager_.LoadIcon(extension);
1402 omnibox_icon_manager_.LoadIcon(extension);
1403 }
1404
1405 // If the extension has permission to load chrome://favicon/ resources we need
1406 // to make sure that the FaviconSource is registered with the
1407 // ChromeURLDataManager.
1408 if (extension->HasHostPermission(GURL(chrome::kChromeUIFaviconURL))) {
1409 FaviconSource* favicon_source = new FaviconSource(profile_,
1410 FaviconSource::FAVICON);
1411 profile_->GetChromeURLDataManager()->AddDataSource(favicon_source);
1412 }
1413
1414 // TODO(mpcomplete): This ends up affecting all profiles. See crbug.com/80757.
[email protected]2de307592011-04-05 21:16:581415 bool plugins_changed = false;
1416 for (size_t i = 0; i < extension->plugins().size(); ++i) {
1417 const Extension::PluginInfo& plugin = extension->plugins()[i];
1418 webkit::npapi::PluginList::Singleton()->RefreshPlugins();
1419 webkit::npapi::PluginList::Singleton()->AddExtraPluginPath(plugin.path);
1420 plugins_changed = true;
1421 if (!plugin.is_public) {
1422 PluginService::GetInstance()->RestrictPluginToUrl(
1423 plugin.path, extension->url());
1424 }
1425 }
[email protected]84396dbc2011-04-14 06:33:421426
1427 bool nacl_modules_changed = false;
1428 for (size_t i = 0; i < extension->nacl_modules().size(); ++i) {
1429 const Extension::NaClModuleInfo& module = extension->nacl_modules()[i];
[email protected]cebc3dc2011-04-18 17:15:001430 RegisterNaClModule(module.url, module.mime_type);
[email protected]84396dbc2011-04-14 06:33:421431 nacl_modules_changed = true;
1432 }
1433
[email protected]ed0ba002011-05-26 16:55:131434 if (nacl_modules_changed)
1435 UpdatePluginListWithNaClModules();
[email protected]84396dbc2011-04-14 06:33:421436
1437 if (plugins_changed || nacl_modules_changed)
[email protected]2de307592011-04-05 21:16:581438 PluginService::GetInstance()->PurgePluginListCache(false);
[email protected]b4d9d122011-06-17 01:58:541439
1440#if defined(OS_CHROMEOS) && defined(TOUCH_UI)
[email protected]c8d4e9462011-06-29 23:18:571441 chromeos::input_method::InputMethodManager* input_method_manager =
1442 chromeos::input_method::InputMethodManager::GetInstance();
[email protected]b4d9d122011-06-17 01:58:541443 for (std::vector<Extension::InputComponentInfo>::const_iterator component =
1444 extension->input_components().begin();
1445 component != extension->input_components().end();
1446 ++component) {
1447 if (component->type == Extension::INPUT_COMPONENT_TYPE_VIRTUAL_KEYBOARD &&
1448 !component->layouts.empty()) {
1449 const bool is_system =
1450 !Extension::IsExternalLocation(extension->location());
[email protected]c8d4e9462011-06-29 23:18:571451 input_method_manager->RegisterVirtualKeyboard(extension->url(),
[email protected]b4d9d122011-06-17 01:58:541452 component->layouts,
1453 is_system);
1454 }
1455 }
1456#endif
[email protected]62d30f42009-10-01 22:36:061457}
1458
[email protected]a9f39a312010-12-23 22:14:271459void ExtensionService::NotifyExtensionUnloaded(
1460 const Extension* extension, UnloadedExtensionInfo::Reason reason) {
1461 UnloadedExtensionInfo details(extension, reason);
[email protected]62d30f42009-10-01 22:36:061462 NotificationService::current()->Notify(
[email protected]432115822011-07-10 15:52:271463 chrome::NOTIFICATION_EXTENSION_UNLOADED,
[email protected]24e7a9d2009-11-04 11:11:341464 Source<Profile>(profile_),
[email protected]a9f39a312010-12-23 22:14:271465 Details<UnloadedExtensionInfo>(&details));
[email protected]62d30f42009-10-01 22:36:061466
[email protected]77a6970c2011-04-23 16:58:561467 for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
1468 !i.IsAtEnd(); i.Advance()) {
[email protected]c8d407e2011-04-28 21:27:171469 RenderProcessHost* host = i.GetCurrentValue();
[email protected]9b62ecf2011-07-27 20:23:081470 Profile* host_profile =
1471 Profile::FromBrowserContext(host->browser_context());
1472 if (host_profile->GetOriginalProfile() == profile_->GetOriginalProfile())
[email protected]c8d407e2011-04-28 21:27:171473 host->Send(new ExtensionMsg_Unloaded(extension->id()));
[email protected]77a6970c2011-04-23 16:58:561474 }
1475
[email protected]dd163fb02011-05-04 22:22:171476 profile_->UnregisterExtensionWithRequestContexts(extension->id(), reason);
[email protected]c8d407e2011-04-28 21:27:171477 profile_->GetExtensionSpecialStoragePolicy()->
1478 RevokeRightsForExtension(extension);
1479
1480 ExtensionWebUI::UnregisterChromeURLOverrides(
1481 profile_, extension->GetChromeURLOverrides());
1482
[email protected]b777b332011-04-16 04:01:081483#if defined(OS_CHROMEOS)
1484 // Revoke external file access to
[email protected]c8d407e2011-04-28 21:27:171485 if (profile_->GetFileSystemContext() &&
1486 profile_->GetFileSystemContext()->path_manager() &&
1487 profile_->GetFileSystemContext()->path_manager()->external_provider()) {
1488 profile_->GetFileSystemContext()->path_manager()->external_provider()->
1489 RevokeAccessForExtension(extension->id());
[email protected]62d30f42009-10-01 22:36:061490 }
[email protected]c8d407e2011-04-28 21:27:171491#endif
1492
1493 UpdateActiveExtensionsInCrashReporter();
[email protected]2de307592011-04-05 21:16:581494
1495 bool plugins_changed = false;
1496 for (size_t i = 0; i < extension->plugins().size(); ++i) {
1497 const Extension::PluginInfo& plugin = extension->plugins()[i];
[email protected]14908b72011-04-20 06:54:361498 if (!BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
1499 NewRunnableFunction(&ForceShutdownPlugin,
1500 plugin.path)))
1501 NOTREACHED();
[email protected]2de307592011-04-05 21:16:581502 webkit::npapi::PluginList::Singleton()->RefreshPlugins();
1503 webkit::npapi::PluginList::Singleton()->RemoveExtraPluginPath(
1504 plugin.path);
1505 plugins_changed = true;
1506 if (!plugin.is_public)
1507 PluginService::GetInstance()->RestrictPluginToUrl(plugin.path, GURL());
1508 }
[email protected]84396dbc2011-04-14 06:33:421509
1510 bool nacl_modules_changed = false;
1511 for (size_t i = 0; i < extension->nacl_modules().size(); ++i) {
1512 const Extension::NaClModuleInfo& module = extension->nacl_modules()[i];
[email protected]cebc3dc2011-04-18 17:15:001513 UnregisterNaClModule(module.url);
[email protected]84396dbc2011-04-14 06:33:421514 nacl_modules_changed = true;
1515 }
1516
[email protected]ed0ba002011-05-26 16:55:131517 if (nacl_modules_changed)
1518 UpdatePluginListWithNaClModules();
[email protected]84396dbc2011-04-14 06:33:421519
1520 if (plugins_changed || nacl_modules_changed)
[email protected]2de307592011-04-05 21:16:581521 PluginService::GetInstance()->PurgePluginListCache(false);
[email protected]62d30f42009-10-01 22:36:061522}
1523
[email protected]eaa7dd182010-12-14 11:09:001524void ExtensionService::UpdateExtensionBlacklist(
[email protected]6b75ec32009-08-14 06:37:181525 const std::vector<std::string>& blacklist) {
1526 // Use this set to indicate if an extension in the blacklist has been used.
1527 std::set<std::string> blacklist_set;
1528 for (unsigned int i = 0; i < blacklist.size(); ++i) {
1529 if (Extension::IdIsValid(blacklist[i])) {
1530 blacklist_set.insert(blacklist[i]);
1531 }
1532 }
1533 extension_prefs_->UpdateBlacklist(blacklist_set);
1534 std::vector<std::string> to_be_removed;
1535 // Loop current extensions, unload installed extensions.
1536 for (ExtensionList::const_iterator iter = extensions_.begin();
1537 iter != extensions_.end(); ++iter) {
[email protected]9adb9692010-10-29 23:14:021538 const Extension* extension = (*iter);
[email protected]6b75ec32009-08-14 06:37:181539 if (blacklist_set.find(extension->id()) != blacklist_set.end()) {
1540 to_be_removed.push_back(extension->id());
1541 }
1542 }
1543
1544 // UnloadExtension will change the extensions_ list. So, we should
1545 // call it outside the iterator loop.
1546 for (unsigned int i = 0; i < to_be_removed.size(); ++i) {
[email protected]a9f39a312010-12-23 22:14:271547 UnloadExtension(to_be_removed[i], UnloadedExtensionInfo::DISABLE);
[email protected]6b75ec32009-08-14 06:37:181548 }
1549}
1550
[email protected]0a071a32011-02-08 00:18:241551Profile* ExtensionService::profile() {
1552 return profile_;
1553}
1554
[email protected]eaa7dd182010-12-14 11:09:001555ExtensionPrefs* ExtensionService::extension_prefs() {
[email protected]ddb1e5a2010-12-13 20:10:451556 return extension_prefs_;
1557}
1558
[email protected]b790b072011-05-20 09:46:441559ExtensionContentSettingsStore*
1560 ExtensionService::GetExtensionContentSettingsStore() {
1561 return extension_prefs()->content_settings_store();
1562}
1563
[email protected]2859946f2011-04-04 18:18:061564ExtensionUpdater* ExtensionService::updater() {
1565 return updater_.get();
1566}
1567
[email protected]eaa7dd182010-12-14 11:09:001568void ExtensionService::CheckAdminBlacklist() {
[email protected]aa96d3a2010-08-21 08:45:251569 std::vector<std::string> to_be_removed;
1570 // Loop through extensions list, unload installed extensions.
1571 for (ExtensionList::const_iterator iter = extensions_.begin();
1572 iter != extensions_.end(); ++iter) {
[email protected]9adb9692010-10-29 23:14:021573 const Extension* extension = (*iter);
[email protected]aa96d3a2010-08-21 08:45:251574 if (!extension_prefs_->IsExtensionAllowedByPolicy(extension->id()))
1575 to_be_removed.push_back(extension->id());
1576 }
1577
1578 // UnloadExtension will change the extensions_ list. So, we should
1579 // call it outside the iterator loop.
1580 for (unsigned int i = 0; i < to_be_removed.size(); ++i)
[email protected]a9f39a312010-12-23 22:14:271581 UnloadExtension(to_be_removed[i], UnloadedExtensionInfo::DISABLE);
[email protected]aa96d3a2010-08-21 08:45:251582}
1583
[email protected]31206602011-04-13 23:07:321584void ExtensionService::CheckForUpdatesSoon() {
[email protected]c3cfb012011-04-06 22:07:351585 if (updater()) {
[email protected]31206602011-04-13 23:07:321586 updater()->CheckSoon();
[email protected]c3cfb012011-04-06 22:07:351587 } else {
[email protected]31206602011-04-13 23:07:321588 LOG(WARNING) << "CheckForUpdatesSoon() called with auto-update turned off";
[email protected]c3cfb012011-04-06 22:07:351589 }
1590}
1591
[email protected]b05fb9ff2011-04-23 00:07:561592ExtensionSyncData ExtensionService::GetSyncDataHelper(
1593 const Extension& extension) const {
1594 const std::string& id = extension.id();
1595 ExtensionSyncData data;
1596 data.id = id;
1597 data.uninstalled = false;
1598 data.enabled = IsExtensionEnabled(id);
1599 data.incognito_enabled = IsIncognitoEnabled(id);
1600 data.version = *extension.version();
1601 data.update_url = extension.update_url();
1602 data.name = extension.name();
1603 return data;
1604}
1605
1606bool ExtensionService::GetSyncData(
[email protected]85fc9202011-05-05 00:04:591607 const Extension& extension,
[email protected]b05fb9ff2011-04-23 00:07:561608 ExtensionFilter filter,
1609 ExtensionSyncData* extension_sync_data) const {
[email protected]85fc9202011-05-05 00:04:591610 if (!(*filter)(extension)) {
[email protected]b05fb9ff2011-04-23 00:07:561611 return false;
1612 }
[email protected]85fc9202011-05-05 00:04:591613 *extension_sync_data = GetSyncDataHelper(extension);
[email protected]b05fb9ff2011-04-23 00:07:561614 return true;
1615}
1616
1617void ExtensionService::GetSyncDataListHelper(
1618 const ExtensionList& extensions,
1619 ExtensionFilter filter,
1620 std::vector<ExtensionSyncData>* sync_data_list) const {
1621 for (ExtensionList::const_iterator it = extensions.begin();
1622 it != extensions.end(); ++it) {
1623 const Extension& extension = **it;
1624 if ((*filter)(extension)) {
1625 sync_data_list->push_back(GetSyncDataHelper(extension));
1626 }
1627 }
1628}
1629
1630std::vector<ExtensionSyncData> ExtensionService::GetSyncDataList(
1631 ExtensionFilter filter) const {
1632 std::vector<ExtensionSyncData> sync_data_list;
1633 GetSyncDataListHelper(extensions_, filter, &sync_data_list);
1634 GetSyncDataListHelper(disabled_extensions_, filter, &sync_data_list);
[email protected]45b6fee2011-05-03 09:41:311635 GetSyncDataListHelper(terminated_extensions_, filter, &sync_data_list);
[email protected]b05fb9ff2011-04-23 00:07:561636 return sync_data_list;
1637}
1638
[email protected]90310d92011-04-17 07:35:041639void ExtensionService::ProcessSyncData(
1640 const ExtensionSyncData& extension_sync_data,
[email protected]b05fb9ff2011-04-23 00:07:561641 ExtensionFilter filter) {
[email protected]90310d92011-04-17 07:35:041642 const std::string& id = extension_sync_data.id;
1643
1644 // Handle uninstalls first.
1645 if (extension_sync_data.uninstalled) {
1646 std::string error;
1647 if (!UninstallExtensionHelper(this, id)) {
1648 LOG(WARNING) << "Could not uninstall extension " << id
1649 << " for sync";
1650 }
1651 return;
1652 }
1653
[email protected]06f92562011-04-29 19:27:311654 // Set user settings.
1655 if (extension_sync_data.enabled) {
1656 EnableExtension(id);
1657 } else {
1658 DisableExtension(id);
1659 }
[email protected]81b14cc2011-04-29 00:39:371660 SetIsIncognitoEnabled(id, extension_sync_data.incognito_enabled);
1661
[email protected]06f92562011-04-29 19:27:311662 const Extension* extension = GetInstalledExtension(id);
[email protected]90310d92011-04-17 07:35:041663 if (extension) {
[email protected]06f92562011-04-29 19:27:311664 // If the extension is already installed, check if it's outdated.
[email protected]90310d92011-04-17 07:35:041665 int result = extension->version()->CompareTo(extension_sync_data.version);
1666 if (result < 0) {
1667 // Extension is outdated.
1668 CheckForUpdatesSoon();
1669 } else if (result > 0) {
1670 // Sync version is outdated. Do nothing for now, as sync code
1671 // in other places will eventually update the sync data.
1672 //
1673 // TODO(akalin): Move that code here.
1674 }
[email protected]06f92562011-04-29 19:27:311675 } else {
[email protected]06f92562011-04-29 19:27:311676 // TODO(akalin): Replace silent update with a list of enabled
1677 // permissions.
[email protected]6cc7dbae2011-04-29 21:18:331678 const bool kInstallSilently = true;
[email protected]06f92562011-04-29 19:27:311679 if (!pending_extension_manager()->AddFromSync(
1680 id,
1681 extension_sync_data.update_url,
1682 filter,
[email protected]6cc7dbae2011-04-29 21:18:331683 kInstallSilently)) {
[email protected]06f92562011-04-29 19:27:311684 LOG(WARNING) << "Could not add pending extension for " << id;
1685 return;
1686 }
1687 CheckForUpdatesSoon();
[email protected]90310d92011-04-17 07:35:041688 }
[email protected]90310d92011-04-17 07:35:041689}
1690
[email protected]c3cfb012011-04-06 22:07:351691bool ExtensionService::IsIncognitoEnabled(
1692 const std::string& extension_id) const {
1693 // If this is an existing component extension we always allow it to
1694 // work in incognito mode.
[email protected]81b14cc2011-04-29 00:39:371695 const Extension* extension = GetInstalledExtension(extension_id);
[email protected]c3cfb012011-04-06 22:07:351696 if (extension && extension->location() == Extension::COMPONENT)
[email protected]cb0ce1e022010-03-10 19:54:411697 return true;
1698
1699 // Check the prefs.
[email protected]c3cfb012011-04-06 22:07:351700 return extension_prefs_->IsIncognitoEnabled(extension_id);
[email protected]db7331a2010-02-25 22:10:501701}
[email protected]55a35692010-02-11 23:25:211702
[email protected]c3cfb012011-04-06 22:07:351703void ExtensionService::SetIsIncognitoEnabled(
1704 const std::string& extension_id, bool enabled) {
[email protected]81b14cc2011-04-29 00:39:371705 const Extension* extension = GetInstalledExtension(extension_id);
[email protected]c3cfb012011-04-06 22:07:351706 if (extension && extension->location() == Extension::COMPONENT) {
1707 // This shouldn't be called for component extensions.
1708 NOTREACHED();
1709 return;
1710 }
1711
[email protected]8c6c8c22011-03-09 12:52:341712 // Broadcast unloaded and loaded events to update browser state. Only bother
1713 // if the value changed and the extension is actually enabled, since there is
1714 // no UI otherwise.
[email protected]c3cfb012011-04-06 22:07:351715 bool old_enabled = extension_prefs_->IsIncognitoEnabled(extension_id);
[email protected]8c6c8c22011-03-09 12:52:341716 if (enabled == old_enabled)
1717 return;
1718
[email protected]c3cfb012011-04-06 22:07:351719 extension_prefs_->SetIsIncognitoEnabled(extension_id, enabled);
[email protected]81b14cc2011-04-29 00:39:371720
1721 // If the extension is enabled (and not terminated), unload and
1722 // reload it to update UI.
1723 const Extension* enabled_extension = GetExtensionById(extension_id, false);
1724 if (enabled_extension) {
1725 NotifyExtensionUnloaded(enabled_extension, UnloadedExtensionInfo::DISABLE);
1726 NotifyExtensionLoaded(enabled_extension);
[email protected]568f33d2010-08-04 17:06:411727 }
[email protected]55a35692010-02-11 23:25:211728}
1729
[email protected]eaa7dd182010-12-14 11:09:001730bool ExtensionService::CanCrossIncognito(const Extension* extension) {
[email protected]2a8f24e2010-11-03 21:37:051731 // We allow the extension to see events and data from another profile iff it
1732 // uses "spanning" behavior and it has incognito access. "split" mode
1733 // extensions only see events for a matching profile.
[email protected]c3cfb012011-04-06 22:07:351734 return IsIncognitoEnabled(extension->id()) &&
1735 !extension->incognito_split_mode();
[email protected]2a8f24e2010-11-03 21:37:051736}
1737
[email protected]5ef7b002011-05-12 23:16:201738bool ExtensionService::CanLoadInIncognito(const Extension* extension) const {
1739 if (extension->is_hosted_app())
1740 return true;
1741 // Packaged apps and regular extensions need to be enabled specifically for
1742 // incognito (and split mode should be set).
1743 return extension->incognito_split_mode() &&
1744 IsIncognitoEnabled(extension->id());
1745}
1746
[email protected]eaa7dd182010-12-14 11:09:001747bool ExtensionService::AllowFileAccess(const Extension* extension) {
[email protected]05c82182010-06-24 17:49:081748 return (CommandLine::ForCurrentProcess()->HasSwitch(
[email protected]334e04a2010-06-24 23:34:441749 switches::kDisableExtensionsFileAccessCheck) ||
[email protected]05c82182010-06-24 17:49:081750 extension_prefs_->AllowFileAccess(extension->id()));
1751}
1752
[email protected]eaa7dd182010-12-14 11:09:001753void ExtensionService::SetAllowFileAccess(const Extension* extension,
[email protected]3aff9ad2011-04-01 20:26:481754 bool allow) {
1755 // Reload to update browser state. Only bother if the value changed and the
1756 // extension is actually enabled, since there is no UI otherwise.
1757 bool old_allow = AllowFileAccess(extension);
1758 if (allow == old_allow)
1759 return;
1760
[email protected]05c82182010-06-24 17:49:081761 extension_prefs_->SetAllowFileAccess(extension->id(), allow);
[email protected]3aff9ad2011-04-01 20:26:481762
1763 bool extension_is_enabled = std::find(extensions_.begin(), extensions_.end(),
1764 extension) != extensions_.end();
1765 if (extension_is_enabled)
1766 ReloadExtension(extension->id());
[email protected]05c82182010-06-24 17:49:081767}
1768
[email protected]eaa7dd182010-12-14 11:09:001769bool ExtensionService::GetBrowserActionVisibility(const Extension* extension) {
[email protected]f681c782010-11-19 11:19:391770 return extension_prefs_->GetBrowserActionVisibility(extension);
1771}
1772
[email protected]eaa7dd182010-12-14 11:09:001773void ExtensionService::SetBrowserActionVisibility(const Extension* extension,
[email protected]8e4560b62011-01-14 10:09:141774 bool visible) {
[email protected]f681c782010-11-19 11:19:391775 extension_prefs_->SetBrowserActionVisibility(extension, visible);
1776}
1777
[email protected]8e4560b62011-01-14 10:09:141778// Some extensions will autoupdate themselves externally from Chrome. These
1779// are typically part of some larger client application package. To support
1780// these, the extension will register its location in the the preferences file
1781// (and also, on Windows, in the registry) and this code will periodically
1782// check that location for a .crx file, which it will then install locally if
1783// a new version is available.
1784// Errors are reported through ExtensionErrorReporter. Succcess is not
1785// reported.
[email protected]eaa7dd182010-12-14 11:09:001786void ExtensionService::CheckForExternalUpdates() {
[email protected]a29a517a2011-01-21 21:11:121787 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]8e4560b62011-01-14 10:09:141788
1789 // Note that this installation is intentionally silent (since it didn't
1790 // go through the front-end). Extensions that are registered in this
1791 // way are effectively considered 'pre-bundled', and so implicitly
1792 // trusted. In general, if something has HKLM or filesystem access,
1793 // they could install an extension manually themselves anyway.
[email protected]a29a517a2011-01-21 21:11:121794
1795 // If any external extension records give a URL, a provider will set
1796 // this to true. Used by OnExternalProviderReady() to see if we need
1797 // to start an update check to fetch a new external extension.
1798 external_extension_url_added_ = false;
[email protected]8e4560b62011-01-14 10:09:141799
1800 // Ask each external extension provider to give us a call back for each
1801 // extension they know about. See OnExternalExtension(File|UpdateUrl)Found.
1802 ProviderCollection::const_iterator i;
1803 for (i = external_extension_providers_.begin();
1804 i != external_extension_providers_.end(); ++i) {
1805 ExternalExtensionProviderInterface* provider = i->get();
1806 provider->VisitRegisteredExtension();
1807 }
1808
1809 // Uninstall of unclaimed extensions will happen after all the providers
[email protected]a29a517a2011-01-21 21:11:121810 // had reported ready. Every provider calls OnExternalProviderReady()
1811 // when it finishes, and OnExternalProviderReady() only acts when all
1812 // providers are ready. In case there are no providers, we call it
1813 // to trigger removal of extensions that used to have an external source.
1814 if (external_extension_providers_.empty())
1815 OnExternalProviderReady();
[email protected]9f1087e2009-06-15 17:29:321816}
1817
[email protected]8e4560b62011-01-14 10:09:141818void ExtensionService::OnExternalProviderReady() {
[email protected]a29a517a2011-01-21 21:11:121819 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1820
1821 // An external provider has finished loading. We only take action
[email protected]8e4560b62011-01-14 10:09:141822 // if all of them are finished. So we check them first.
1823 ProviderCollection::const_iterator i;
1824 for (i = external_extension_providers_.begin();
1825 i != external_extension_providers_.end(); ++i) {
1826 ExternalExtensionProviderInterface* provider = i->get();
[email protected]a29a517a2011-01-21 21:11:121827 if (!provider->IsReady())
[email protected]8e4560b62011-01-14 10:09:141828 return;
[email protected]8e4560b62011-01-14 10:09:141829 }
1830
[email protected]a29a517a2011-01-21 21:11:121831 // All the providers are ready. Install any pending extensions.
1832 if (external_extension_url_added_ && updater()) {
1833 external_extension_url_added_ = false;
[email protected]8e4560b62011-01-14 10:09:141834 updater()->CheckNow();
1835 }
1836
1837 // Uninstall all the unclaimed extensions.
1838 scoped_ptr<ExtensionPrefs::ExtensionsInfo> extensions_info(
1839 extension_prefs_->GetInstalledExtensionsInfo());
1840 for (size_t i = 0; i < extensions_info->size(); ++i) {
1841 ExtensionInfo* info = extensions_info->at(i).get();
1842 if (Extension::IsExternalLocation(info->extension_location))
1843 CheckExternalUninstall(info->extension_id);
1844 }
[email protected]6c751e72010-11-23 10:11:101845}
1846
[email protected]a9f39a312010-12-23 22:14:271847void ExtensionService::UnloadExtension(
1848 const std::string& extension_id,
1849 UnloadedExtensionInfo::Reason reason) {
[email protected]27e469a2010-01-11 20:35:091850 // Make sure the extension gets deleted after we return from this function.
[email protected]9adb9692010-10-29 23:14:021851 scoped_refptr<const Extension> extension(
[email protected]8001df22011-04-28 19:59:471852 GetExtensionByIdInternal(extension_id, true, true, false));
[email protected]631cf822009-05-15 07:01:251853
[email protected]fa0c96732010-11-17 00:14:231854 // This method can be called via PostTask, so the extension may have been
1855 // unloaded by the time this runs.
[email protected]dd163fb02011-05-04 22:22:171856 if (!extension) {
1857 // In case the extension may have crashed/uninstalled. Allow the profile to
1858 // clean up its RequestContexts.
1859 profile_->UnregisterExtensionWithRequestContexts(extension_id, reason);
[email protected]fa0c96732010-11-17 00:14:231860 return;
[email protected]dd163fb02011-05-04 22:22:171861 }
[email protected]0c6da502009-08-14 22:32:391862
[email protected]1eb175082010-02-10 09:26:161863 // Keep information about the extension so that we can reload it later
1864 // even if it's not permanently installed.
1865 unloaded_extension_paths_[extension->id()] = extension->path();
1866
[email protected]f17dbd42010-08-16 23:21:101867 // Clean up if the extension is meant to be enabled after a reload.
1868 disabled_extension_paths_.erase(extension->id());
1869
[email protected]d7e9a862010-11-03 21:57:491870 // Clean up runtime data.
1871 extension_runtime_data_.erase(extension_id);
1872
[email protected]0c6da502009-08-14 22:32:391873 ExtensionList::iterator iter = std::find(disabled_extensions_.begin(),
1874 disabled_extensions_.end(),
1875 extension.get());
1876 if (iter != disabled_extensions_.end()) {
[email protected]a9f39a312010-12-23 22:14:271877 UnloadedExtensionInfo details(extension, reason);
1878 details.already_disabled = true;
[email protected]0c6da502009-08-14 22:32:391879 disabled_extensions_.erase(iter);
[email protected]866930682009-08-18 22:53:471880 NotificationService::current()->Notify(
[email protected]432115822011-07-10 15:52:271881 chrome::NOTIFICATION_EXTENSION_UNLOADED,
[email protected]24e7a9d2009-11-04 11:11:341882 Source<Profile>(profile_),
[email protected]a9f39a312010-12-23 22:14:271883 Details<UnloadedExtensionInfo>(&details));
[email protected]dd163fb02011-05-04 22:22:171884 // Make sure the profile cleans up its RequestContexts when an already
1885 // disabled extension is unloaded (since they are also tracking the disabled
1886 // extensions).
1887 profile_->UnregisterExtensionWithRequestContexts(extension_id, reason);
[email protected]0c6da502009-08-14 22:32:391888 return;
1889 }
1890
1891 iter = std::find(extensions_.begin(), extensions_.end(), extension.get());
[email protected]894bb502009-05-21 22:39:571892
[email protected]631cf822009-05-15 07:01:251893 // Remove the extension from our list.
1894 extensions_.erase(iter);
1895
[email protected]a9f39a312010-12-23 22:14:271896 NotifyExtensionUnloaded(extension.get(), reason);
[email protected]631cf822009-05-15 07:01:251897}
1898
[email protected]eaa7dd182010-12-14 11:09:001899void ExtensionService::UnloadAllExtensions() {
[email protected]c8d407e2011-04-28 21:27:171900 profile_->GetExtensionSpecialStoragePolicy()->
1901 RevokeRightsForAllExtensions();
1902
[email protected]9f1087e2009-06-15 17:29:321903 extensions_.clear();
[email protected]cd500f72010-06-25 23:44:321904 disabled_extensions_.clear();
[email protected]bb7f40952011-01-13 00:21:201905 terminated_extension_ids_.clear();
1906 terminated_extensions_.clear();
[email protected]d7e9a862010-11-03 21:57:491907 extension_runtime_data_.clear();
[email protected]cd500f72010-06-25 23:44:321908
[email protected]c6e4a3412009-06-24 15:45:291909 // TODO(erikkay) should there be a notification for this? We can't use
1910 // EXTENSION_UNLOADED since that implies that the extension has been disabled
1911 // or uninstalled, and UnloadAll is just part of shutdown.
[email protected]9f1087e2009-06-15 17:29:321912}
1913
[email protected]eaa7dd182010-12-14 11:09:001914void ExtensionService::ReloadExtensions() {
[email protected]9f1087e2009-06-15 17:29:321915 UnloadAllExtensions();
1916 LoadAllExtensions();
1917}
1918
[email protected]eaa7dd182010-12-14 11:09:001919void ExtensionService::GarbageCollectExtensions() {
[email protected]39d9f62c2010-12-03 10:48:501920 if (extension_prefs_->pref_service()->ReadOnly())
[email protected]ba399672010-04-06 15:42:391921 return;
1922
[email protected]ca3dbf52010-05-19 22:27:061923 scoped_ptr<ExtensionPrefs::ExtensionsInfo> info(
1924 extension_prefs_->GetInstalledExtensionsInfo());
1925
1926 std::map<std::string, FilePath> extension_paths;
1927 for (size_t i = 0; i < info->size(); ++i)
1928 extension_paths[info->at(i)->extension_id] = info->at(i)->extension_path;
1929
[email protected]14908b72011-04-20 06:54:361930 if (!BrowserThread::PostTask(
1931 BrowserThread::FILE, FROM_HERE,
1932 NewRunnableFunction(
1933 &extension_file_util::GarbageCollectExtensions,
1934 install_directory_,
1935 extension_paths)))
1936 NOTREACHED();
[email protected]f6ccd652010-11-17 00:48:341937
1938 // Also garbage-collect themes. We check |profile_| to be
1939 // defensive; in the future, we may call GarbageCollectExtensions()
1940 // from somewhere other than Init() (e.g., in a timer).
1941 if (profile_) {
[email protected]18280372011-03-22 18:05:221942 ThemeServiceFactory::GetForProfile(profile_)->RemoveUnusedThemes();
[email protected]f6ccd652010-11-17 00:48:341943 }
[email protected]3cf4f0992009-02-03 23:00:301944}
1945
[email protected]eaa7dd182010-12-14 11:09:001946void ExtensionService::OnLoadedInstalledExtensions() {
[email protected]93fd78f42009-07-10 16:43:171947 if (updater_.get()) {
1948 updater_->Start();
1949 }
[email protected]fa6a9102010-11-22 15:38:501950
1951 ready_ = true;
[email protected]e72e8eb82009-06-18 17:21:511952 NotificationService::current()->Notify(
[email protected]432115822011-07-10 15:52:271953 chrome::NOTIFICATION_EXTENSIONS_READY,
[email protected]24e7a9d2009-11-04 11:11:341954 Source<Profile>(profile_),
[email protected]e72e8eb82009-06-18 17:21:511955 NotificationService::NoDetails());
1956}
1957
[email protected]49cd1572011-02-08 21:38:451958void ExtensionService::AddExtension(const Extension* extension) {
[email protected]ae09ca62009-08-21 19:46:461959 // Ensure extension is deleted unless we transfer ownership.
[email protected]9adb9692010-10-29 23:14:021960 scoped_refptr<const Extension> scoped_extension(extension);
[email protected]9f1087e2009-06-15 17:29:321961
[email protected]c8d407e2011-04-28 21:27:171962 // TODO(jstritar): We may be able to get rid of this branch by overriding the
1963 // default extension state to DISABLED when the --disable-extensions flag
1964 // is set (http://crbug.com/29067).
1965 if (!extensions_enabled() &&
1966 !extension->is_theme() &&
1967 extension->location() != Extension::COMPONENT &&
1968 !Extension::IsExternalLocation(extension->location()))
1969 return;
1970
1971 SetBeingUpgraded(extension, false);
1972
[email protected]1eb175082010-02-10 09:26:161973 // The extension is now loaded, remove its data from unloaded extension map.
1974 unloaded_extension_paths_.erase(extension->id());
1975
[email protected]bb7f40952011-01-13 00:21:201976 // If a terminated extension is loaded, remove it from the terminated list.
1977 UntrackTerminatedExtension(extension->id());
1978
[email protected]f17dbd42010-08-16 23:21:101979 // If the extension was disabled for a reload, then enable it.
1980 if (disabled_extension_paths_.erase(extension->id()) > 0)
1981 EnableExtension(extension->id());
1982
[email protected]d728e002010-12-08 04:46:231983 // Check if the extension's privileges have changed and disable the
1984 // extension if necessary.
[email protected]902fd7b2011-07-27 18:42:311985 InitializePermissions(extension);
[email protected]0c6da502009-08-14 22:32:391986
[email protected]ad83ca242011-07-29 01:32:251987 bool disabled = extension_prefs_->IsExtensionDisabled(extension->id());
[email protected]36429da2011-07-11 20:25:181988 if (disabled) {
[email protected]c8d407e2011-04-28 21:27:171989 disabled_extensions_.push_back(scoped_extension);
1990 // TODO(aa): This seems dodgy. It seems that AddExtension() could get called
1991 // with a disabled extension for other reasons other than that an update was
1992 // disabled.
1993 NotificationService::current()->Notify(
[email protected]432115822011-07-10 15:52:271994 chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED,
[email protected]c8d407e2011-04-28 21:27:171995 Source<Profile>(profile_),
1996 Details<const Extension>(extension));
1997 return;
[email protected]e72e8eb82009-06-18 17:21:511998 }
[email protected]aab98a52009-12-02 03:22:351999
[email protected]c8d407e2011-04-28 21:27:172000 extensions_.push_back(scoped_extension);
2001 NotifyExtensionLoaded(extension);
[email protected]aab98a52009-12-02 03:22:352002}
2003
[email protected]902fd7b2011-07-27 18:42:312004void ExtensionService::InitializePermissions(const Extension* extension) {
2005 // If the extension has used the optional permissions API, it will have a
2006 // custom set of active permissions defined in the extension prefs. Here,
2007 // we update the extension's active permissions based on the prefs.
2008 scoped_refptr<ExtensionPermissionSet> active_permissions =
2009 extension_prefs()->GetActivePermissions(extension->id());
2010
2011 if (active_permissions.get()) {
2012 // We restrict the active permissions to be within the bounds defined in the
2013 // extension's manifest.
2014 // a) active permissions must be a subset of optional + default permissions
2015 // b) active permissions must contains all default permissions
2016 scoped_refptr<ExtensionPermissionSet> total_permissions =
2017 ExtensionPermissionSet::CreateUnion(
2018 extension->required_permission_set(),
2019 extension->optional_permission_set());
2020
2021 // Make sure the active permissions contain no more than optional + default.
2022 scoped_refptr<ExtensionPermissionSet> adjusted_active =
2023 ExtensionPermissionSet::CreateIntersection(
2024 total_permissions.get(), active_permissions.get());
2025
2026 // Make sure the active permissions contain the default permissions.
2027 adjusted_active = ExtensionPermissionSet::CreateUnion(
2028 extension->required_permission_set(), adjusted_active.get());
2029
2030 UpdateActivePermissions(extension, adjusted_active);
2031 }
2032
[email protected]8d888c12010-11-30 00:00:252033 // We keep track of all permissions the user has granted each extension.
2034 // This allows extensions to gracefully support backwards compatibility
2035 // by including unknown permissions in their manifests. When the user
2036 // installs the extension, only the recognized permissions are recorded.
2037 // When the unknown permissions become recognized (e.g., through browser
2038 // upgrade), we can prompt the user to accept these new permissions.
2039 // Extensions can also silently upgrade to less permissions, and then
2040 // silently upgrade to a version that adds these permissions back.
2041 //
2042 // For example, pretend that Chrome 10 includes a permission "omnibox"
2043 // for an API that adds suggestions to the omnibox. An extension can
2044 // maintain backwards compatibility while still having "omnibox" in the
2045 // manifest. If a user installs the extension on Chrome 9, the browser
2046 // will record the permissions it recognized, not including "omnibox."
2047 // When upgrading to Chrome 10, "omnibox" will be recognized and Chrome
2048 // will disable the extension and prompt the user to approve the increase
2049 // in privileges. The extension could then release a new version that
2050 // removes the "omnibox" permission. When the user upgrades, Chrome will
2051 // still remember that "omnibox" had been granted, so that if the
2052 // extension once again includes "omnibox" in an upgrade, the extension
2053 // can upgrade without requiring this user's approval.
2054 const Extension* old = GetExtensionByIdInternal(extension->id(),
[email protected]8001df22011-04-28 19:59:472055 true, true, false);
[email protected]8d888c12010-11-30 00:00:252056 bool is_extension_upgrade = old != NULL;
2057 bool is_privilege_increase = false;
2058
[email protected]902fd7b2011-07-27 18:42:312059 // We only need to compare the granted permissions to the current permissions
2060 // if the extension is not allowed to silently increase its permissions.
2061 if (!extension->CanSilentlyIncreasePermissions()) {
[email protected]8d888c12010-11-30 00:00:252062 // Add all the recognized permissions if the granted permissions list
2063 // hasn't been initialized yet.
[email protected]902fd7b2011-07-27 18:42:312064 scoped_refptr<ExtensionPermissionSet> granted_permissions =
2065 extension_prefs_->GetGrantedPermissions(extension->id());
[email protected]0d3e4a22011-06-23 19:02:522066 CHECK(granted_permissions.get());
[email protected]8d888c12010-11-30 00:00:252067
2068 // Here, we check if an extension's privileges have increased in a manner
2069 // that requires the user's approval. This could occur because the browser
2070 // upgraded and recognized additional privileges, or an extension upgrades
2071 // to a version that requires additional privileges.
[email protected]0d3e4a22011-06-23 19:02:522072 is_privilege_increase =
[email protected]902fd7b2011-07-27 18:42:312073 granted_permissions->HasLessPrivilegesThan(
2074 extension->GetActivePermissions());
[email protected]8d888c12010-11-30 00:00:252075 }
2076
2077 if (is_extension_upgrade) {
[email protected]66e26872010-12-03 20:07:252078 // Other than for unpacked extensions, CrxInstaller should have guaranteed
2079 // that we aren't downgrading.
2080 if (extension->location() != Extension::LOAD)
2081 CHECK(extension->version()->CompareTo(*(old->version())) >= 0);
[email protected]8d888c12010-11-30 00:00:252082
2083 // Extensions get upgraded if the privileges are allowed to increase or
2084 // the privileges haven't increased.
2085 if (!is_privilege_increase) {
2086 SetBeingUpgraded(old, true);
2087 SetBeingUpgraded(extension, true);
2088 }
2089
2090 // To upgrade an extension in place, unload the old one and
2091 // then load the new one.
[email protected]a9f39a312010-12-23 22:14:272092 UnloadExtension(old->id(), UnloadedExtensionInfo::UPDATE);
[email protected]8d888c12010-11-30 00:00:252093 old = NULL;
2094 }
2095
2096 // Extension has changed permissions significantly. Disable it. A
2097 // notification should be sent by the caller.
2098 if (is_privilege_increase) {
[email protected]fe2dd7742011-04-19 22:52:492099 if (!extension_prefs_->DidExtensionEscalatePermissions(extension->id())) {
2100 RecordPermissionMessagesHistogram(
2101 extension, "Extensions.Permissions_AutoDisable");
2102 }
[email protected]b3317ad2011-04-28 23:46:002103 extension_prefs_->SetExtensionState(extension->id(), Extension::DISABLED);
[email protected]8d888c12010-11-30 00:00:252104 extension_prefs_->SetDidExtensionEscalatePermissions(extension, true);
2105 }
2106}
2107
[email protected]eaa7dd182010-12-14 11:09:002108void ExtensionService::UpdateActiveExtensionsInCrashReporter() {
[email protected]c8865962009-12-16 07:47:392109 std::set<std::string> extension_ids;
[email protected]aab98a52009-12-02 03:22:352110 for (size_t i = 0; i < extensions_.size(); ++i) {
[email protected]2a500c1b2010-11-05 15:27:342111 if (!extensions_[i]->is_theme() &&
2112 extensions_[i]->location() != Extension::COMPONENT)
[email protected]c8865962009-12-16 07:47:392113 extension_ids.insert(extensions_[i]->id());
[email protected]aab98a52009-12-02 03:22:352114 }
2115
2116 child_process_logging::SetActiveExtensions(extension_ids);
[email protected]6014d672008-12-05 00:38:252117}
2118
[email protected]e49002a2011-07-13 03:40:442119void ExtensionService::OnLoadSingleExtension(const Extension* extension,
2120 bool prompt_for_plugins) {
[email protected]5fb889382011-06-03 00:29:202121 // If this is a new install of an extension with plugins, prompt the user
2122 // first.
[email protected]e49002a2011-07-13 03:40:442123 if (show_extensions_prompts_ && prompt_for_plugins &&
[email protected]5fb889382011-06-03 00:29:202124 !extension->plugins().empty() &&
2125 disabled_extension_paths_.find(extension->id()) ==
2126 disabled_extension_paths_.end()) {
2127 SimpleExtensionLoadPrompt* prompt = new SimpleExtensionLoadPrompt(
2128 profile_, weak_ptr_factory_.GetWeakPtr(), extension);
2129 prompt->ShowPrompt();
2130 return; // continues in SimpleExtensionLoadPrompt::InstallUI*
2131 }
[email protected]8266d662011-07-12 21:53:262132 OnExtensionInstalled(extension, false); // Not from web store.
[email protected]5fb889382011-06-03 00:29:202133}
2134
[email protected]8266d662011-07-12 21:53:262135void ExtensionService::OnExtensionInstalled(
2136 const Extension* extension, bool from_webstore) {
[email protected]a29a517a2011-01-21 21:11:122137 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]a8af9fdb2010-10-28 21:52:202138
[email protected]4416c5a2010-06-26 01:28:572139 // Ensure extension is deleted unless we transfer ownership.
[email protected]9adb9692010-10-29 23:14:022140 scoped_refptr<const Extension> scoped_extension(extension);
[email protected]c3cfb012011-04-06 22:07:352141 const std::string& id = extension->id();
[email protected]ad83ca242011-07-29 01:32:252142 bool initial_enable = !extension_prefs_->IsExtensionDisabled(id);
[email protected]b2907fd2011-03-25 16:43:372143 PendingExtensionInfo pending_extension_info;
[email protected]c3cfb012011-04-06 22:07:352144 if (pending_extension_manager()->GetById(id, &pending_extension_info)) {
2145 pending_extension_manager()->Remove(id);
[email protected]8ef78fd2010-08-19 17:14:322146
[email protected]483d1ff2011-03-03 17:12:022147 if (!pending_extension_info.ShouldAllowInstall(*extension)) {
[email protected]4416c5a2010-06-26 01:28:572148 LOG(WARNING)
[email protected]ae6cb3022011-04-04 20:11:542149 << "ShouldAllowInstall() returned false for "
[email protected]c3cfb012011-04-06 22:07:352150 << id << " of type " << extension->GetType()
[email protected]7fa19f82010-12-21 19:40:082151 << " and update URL " << extension->update_url().spec()
2152 << "; not installing";
[email protected]ae6cb3022011-04-04 20:11:542153
2154 NotificationService::current()->Notify(
[email protected]432115822011-07-10 15:52:272155 chrome::NOTIFICATION_EXTENSION_INSTALL_NOT_ALLOWED,
[email protected]ae6cb3022011-04-04 20:11:542156 Source<Profile>(profile_),
2157 Details<const Extension>(extension));
2158
[email protected]4416c5a2010-06-26 01:28:572159 // Delete the extension directory since we're not going to
2160 // load it.
[email protected]14908b72011-04-20 06:54:362161 if (!BrowserThread::PostTask(
2162 BrowserThread::FILE, FROM_HERE,
2163 NewRunnableFunction(&extension_file_util::DeleteFile,
2164 extension->path(), true)))
2165 NOTREACHED();
[email protected]4416c5a2010-06-26 01:28:572166 return;
2167 }
[email protected]4416c5a2010-06-26 01:28:572168 } else {
[email protected]c3cfb012011-04-06 22:07:352169 // We explicitly want to re-enable an uninstalled external
2170 // extension; if we're here, that means the user is manually
2171 // installing the extension.
[email protected]6cc7dbae2011-04-29 21:18:332172 if (IsExternalExtensionUninstalled(id)) {
2173 initial_enable = true;
2174 }
[email protected]aa142702010-03-26 01:26:332175 }
2176
[email protected]07533022011-06-27 20:42:552177 // Do not record the install histograms for upgrades.
2178 if (!GetExtensionByIdInternal(extension->id(), true, true, false)) {
2179 UMA_HISTOGRAM_ENUMERATION("Extensions.InstallType",
2180 extension->GetType(), 100);
2181 RecordPermissionMessagesHistogram(
2182 extension, "Extensions.Permissions_Install");
2183 }
2184
[email protected]eda3c362010-11-12 08:08:232185 ShownSectionsHandler::OnExtensionInstalled(profile_->GetPrefs(), extension);
[email protected]4416c5a2010-06-26 01:28:572186 extension_prefs_->OnExtensionInstalled(
[email protected]8266d662011-07-12 21:53:262187 extension,
2188 initial_enable ? Extension::ENABLED : Extension::DISABLED,
2189 from_webstore);
[email protected]25b34332009-06-05 21:53:192190
[email protected]3aff9ad2011-04-01 20:26:482191 // Unpacked extensions default to allowing file access, but if that has been
2192 // overridden, don't reset the value.
2193 if (Extension::ShouldAlwaysAllowFileAccess(Extension::LOAD) &&
[email protected]c3cfb012011-04-06 22:07:352194 !extension_prefs_->HasAllowFileAccessSetting(id)) {
2195 extension_prefs_->SetAllowFileAccess(id, true);
[email protected]3aff9ad2011-04-01 20:26:482196 }
[email protected]92a5b1d2010-07-20 00:42:002197
[email protected]a3e61e82011-04-15 20:32:082198 NotificationService::current()->Notify(
[email protected]432115822011-07-10 15:52:272199 chrome::NOTIFICATION_EXTENSION_INSTALLED,
[email protected]a3e61e82011-04-15 20:32:082200 Source<Profile>(profile_),
2201 Details<const Extension>(extension));
[email protected]7577a5c52009-07-30 06:21:582202
[email protected]49cd1572011-02-08 21:38:452203 // Transfer ownership of |extension| to AddExtension.
2204 AddExtension(scoped_extension);
[email protected]4a190632009-05-09 01:07:422205}
2206
[email protected]eaa7dd182010-12-14 11:09:002207const Extension* ExtensionService::GetExtensionByIdInternal(
[email protected]8001df22011-04-28 19:59:472208 const std::string& id, bool include_enabled, bool include_disabled,
2209 bool include_terminated) const {
[email protected]e957fe52009-06-23 16:51:052210 std::string lowercase_id = StringToLowerASCII(id);
[email protected]0c6da502009-08-14 22:32:392211 if (include_enabled) {
2212 for (ExtensionList::const_iterator iter = extensions_.begin();
2213 iter != extensions_.end(); ++iter) {
2214 if ((*iter)->id() == lowercase_id)
2215 return *iter;
2216 }
2217 }
2218 if (include_disabled) {
2219 for (ExtensionList::const_iterator iter = disabled_extensions_.begin();
2220 iter != disabled_extensions_.end(); ++iter) {
2221 if ((*iter)->id() == lowercase_id)
2222 return *iter;
2223 }
[email protected]ce5c4502009-05-06 16:46:112224 }
[email protected]8001df22011-04-28 19:59:472225 if (include_terminated) {
2226 for (ExtensionList::const_iterator iter = terminated_extensions_.begin();
2227 iter != terminated_extensions_.end(); ++iter) {
2228 if ((*iter)->id() == lowercase_id)
2229 return *iter;
2230 }
2231 }
[email protected]ce5c4502009-05-06 16:46:112232 return NULL;
2233}
2234
[email protected]bb7f40952011-01-13 00:21:202235void ExtensionService::TrackTerminatedExtension(const Extension* extension) {
2236 if (terminated_extension_ids_.insert(extension->id()).second)
2237 terminated_extensions_.push_back(make_scoped_refptr(extension));
[email protected]fa2416f2011-05-03 08:41:202238
2239 UnloadExtension(extension->id(), UnloadedExtensionInfo::DISABLE);
[email protected]bb7f40952011-01-13 00:21:202240}
2241
2242void ExtensionService::UntrackTerminatedExtension(const std::string& id) {
[email protected]fa2416f2011-05-03 08:41:202243 std::string lowercase_id = StringToLowerASCII(id);
2244 if (terminated_extension_ids_.erase(lowercase_id) <= 0)
[email protected]bb7f40952011-01-13 00:21:202245 return;
2246
[email protected]bb7f40952011-01-13 00:21:202247 for (ExtensionList::iterator iter = terminated_extensions_.begin();
2248 iter != terminated_extensions_.end(); ++iter) {
2249 if ((*iter)->id() == lowercase_id) {
2250 terminated_extensions_.erase(iter);
2251 return;
2252 }
2253 }
2254}
2255
[email protected]0dfe05c2011-02-23 23:03:362256const Extension* ExtensionService::GetTerminatedExtension(
[email protected]8001df22011-04-28 19:59:472257 const std::string& id) const {
2258 return GetExtensionByIdInternal(id, false, false, true);
2259}
2260
2261const Extension* ExtensionService::GetInstalledExtension(
2262 const std::string& id) const {
2263 return GetExtensionByIdInternal(id, true, true, true);
[email protected]0dfe05c2011-02-23 23:03:362264}
2265
[email protected]eaa7dd182010-12-14 11:09:002266const Extension* ExtensionService::GetWebStoreApp() {
[email protected]d3071992010-10-08 15:24:072267 return GetExtensionById(extension_misc::kWebStoreAppId, false);
2268}
2269
[email protected]eaa7dd182010-12-14 11:09:002270const Extension* ExtensionService::GetExtensionByURL(const GURL& url) {
[email protected]a888b29e62010-04-01 13:38:572271 return url.scheme() != chrome::kExtensionScheme ? NULL :
2272 GetExtensionById(url.host(), false);
2273}
2274
[email protected]eaa7dd182010-12-14 11:09:002275const Extension* ExtensionService::GetExtensionByWebExtent(const GURL& url) {
[email protected]a888b29e62010-04-01 13:38:572276 for (size_t i = 0; i < extensions_.size(); ++i) {
[email protected]cced75a2011-05-20 08:31:122277 if (extensions_[i]->web_extent().MatchesURL(url))
[email protected]a888b29e62010-04-01 13:38:572278 return extensions_[i];
2279 }
2280 return NULL;
[email protected]9f1087e2009-06-15 17:29:322281}
2282
[email protected]eaa7dd182010-12-14 11:09:002283bool ExtensionService::ExtensionBindingsAllowed(const GURL& url) {
[email protected]056ad2a2011-07-12 02:13:552284 // Allow bindings for all packaged extensions.
2285 // Note that GetExtensionByURL may return an Extension for hosted apps
2286 // if the URL came from GetEffectiveURL.
2287 const Extension* extension = GetExtensionByURL(url);
2288 if (extension && extension->GetType() != Extension::TYPE_HOSTED_APP)
[email protected]583d45c12010-08-31 02:48:122289 return true;
2290
2291 // Allow bindings for all component, hosted apps.
[email protected]056ad2a2011-07-12 02:13:552292 if (!extension)
2293 extension = GetExtensionByWebExtent(url);
[email protected]583d45c12010-08-31 02:48:122294 return (extension && extension->location() == Extension::COMPONENT);
2295}
2296
[email protected]eaa7dd182010-12-14 11:09:002297const Extension* ExtensionService::GetExtensionByOverlappingWebExtent(
[email protected]cced75a2011-05-20 08:31:122298 const URLPatternSet& extent) {
[email protected]22c966c2010-06-26 06:35:022299 for (size_t i = 0; i < extensions_.size(); ++i) {
2300 if (extensions_[i]->web_extent().OverlapsWith(extent))
2301 return extensions_[i];
2302 }
2303
[email protected]6d2e60bd2010-06-03 22:37:392304 return NULL;
2305}
2306
[email protected]eaa7dd182010-12-14 11:09:002307const SkBitmap& ExtensionService::GetOmniboxIcon(
[email protected]b671760b2010-07-15 21:13:472308 const std::string& extension_id) {
2309 return omnibox_icon_manager_.GetIcon(extension_id);
2310}
2311
[email protected]eaa7dd182010-12-14 11:09:002312const SkBitmap& ExtensionService::GetOmniboxPopupIcon(
[email protected]29d0d4ac2010-09-08 21:10:312313 const std::string& extension_id) {
2314 return omnibox_popup_icon_manager_.GetIcon(extension_id);
2315}
2316
[email protected]eaa7dd182010-12-14 11:09:002317void ExtensionService::OnExternalExtensionFileFound(
[email protected]8ef78fd2010-08-19 17:14:322318 const std::string& id,
[email protected]8e4560b62011-01-14 10:09:142319 const Version* version,
[email protected]8ef78fd2010-08-19 17:14:322320 const FilePath& path,
2321 Extension::Location location) {
[email protected]ab22ba42011-01-14 16:36:382322 CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2323 CHECK(Extension::IdIsValid(id));
[email protected]79c833b52011-04-05 18:31:012324 if (extension_prefs_->IsExternalExtensionUninstalled(id))
[email protected]683d0702010-12-06 16:25:572325 return;
[email protected]a8af9fdb2010-10-28 21:52:202326
[email protected]8e4560b62011-01-14 10:09:142327 DCHECK(version);
2328
[email protected]7577a5c52009-07-30 06:21:582329 // Before even bothering to unpack, check and see if we already have this
[email protected]4c967932009-07-31 01:15:492330 // version. This is important because these extensions are going to get
[email protected]7577a5c52009-07-30 06:21:582331 // installed on every startup.
[email protected]9adb9692010-10-29 23:14:022332 const Extension* existing = GetExtensionById(id, true);
[email protected]7577a5c52009-07-30 06:21:582333 if (existing) {
[email protected]8e4560b62011-01-14 10:09:142334 switch (existing->version()->CompareTo(*version)) {
[email protected]7577a5c52009-07-30 06:21:582335 case -1: // existing version is older, we should upgrade
2336 break;
2337 case 0: // existing version is same, do nothing
2338 return;
2339 case 1: // existing version is newer, uh-oh
2340 LOG(WARNING) << "Found external version of extension " << id
2341 << "that is older than current version. Current version "
2342 << "is: " << existing->VersionString() << ". New version "
2343 << "is: " << version << ". Keeping current version.";
2344 return;
2345 }
2346 }
2347
[email protected]b2907fd2011-03-25 16:43:372348 pending_extension_manager()->AddFromExternalFile(id, location);
[email protected]9c635f22010-12-02 09:36:362349
[email protected]14908b72011-04-20 06:54:362350 // no client (silent install)
2351 scoped_refptr<CrxInstaller> installer(MakeCrxInstaller(NULL));
[email protected]6dfbbf82010-03-12 23:09:162352 installer->set_install_source(location);
2353 installer->set_expected_id(id);
[email protected]cb0e50312011-05-09 15:03:072354 installer->set_expected_version(*version);
2355 installer->set_install_cause(extension_misc::INSTALL_CAUSE_EXTERNAL_FILE);
[email protected]6dfbbf82010-03-12 23:09:162356 installer->InstallCrx(path);
[email protected]7577a5c52009-07-30 06:21:582357}
2358
[email protected]eaa7dd182010-12-14 11:09:002359void ExtensionService::ReportExtensionLoadError(
[email protected]d11c8e92009-10-20 23:26:402360 const FilePath& extension_path,
2361 const std::string &error,
[email protected]432115822011-07-10 15:52:272362 int type,
[email protected]d11c8e92009-10-20 23:26:402363 bool be_noisy) {
2364 NotificationService* service = NotificationService::current();
2365 service->Notify(type,
[email protected]24e7a9d2009-11-04 11:11:342366 Source<Profile>(profile_),
[email protected]d11c8e92009-10-20 23:26:402367 Details<const std::string>(&error));
2368
[email protected]8a205c02011-02-04 20:41:332369 std::string path_str = UTF16ToUTF8(extension_path.LossyDisplayName());
[email protected]18d4b6c2010-09-21 03:21:042370 std::string message = base::StringPrintf(
2371 "Could not load extension from '%s'. %s",
2372 path_str.c_str(), error.c_str());
[email protected]d11c8e92009-10-20 23:26:402373 ExtensionErrorReporter::GetInstance()->ReportError(message, be_noisy);
2374}
2375
[email protected]eaa7dd182010-12-14 11:09:002376void ExtensionService::DidCreateRenderViewForBackgroundPage(
[email protected]406027c02010-09-27 08:03:182377 ExtensionHost* host) {
2378 OrphanedDevTools::iterator iter =
[email protected]2d2f6cfc2011-05-06 21:09:332379 orphaned_dev_tools_.find(host->extension_id());
[email protected]406027c02010-09-27 08:03:182380 if (iter == orphaned_dev_tools_.end())
2381 return;
2382
2383 DevToolsManager::GetInstance()->AttachClientHost(
2384 iter->second, host->render_view_host());
2385 orphaned_dev_tools_.erase(iter);
2386}
2387
[email protected]432115822011-07-10 15:52:272388void ExtensionService::Observe(int type,
[email protected]fa2416f2011-05-03 08:41:202389 const NotificationSource& source,
2390 const NotificationDetails& details) {
[email protected]432115822011-07-10 15:52:272391 switch (type) {
2392 case chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED: {
[email protected]bc535ee52010-08-31 18:40:322393 if (profile_ != Source<Profile>(source).ptr()->GetOriginalProfile())
2394 break;
[email protected]a4ed6282009-12-14 20:51:162395
[email protected]f128af42010-08-05 18:05:262396 ExtensionHost* host = Details<ExtensionHost>(details).ptr();
2397
[email protected]fa2416f2011-05-03 08:41:202398 // Mark the extension as terminated and Unload it. We want it to
2399 // be in a consistent state: either fully working or not loaded
2400 // at all, but never half-crashed. We do it in a PostTask so
2401 // that other handlers of this notification will still have
2402 // access to the Extension and ExtensionHost.
[email protected]14908b72011-04-20 06:54:362403 MessageLoop::current()->PostTask(
2404 FROM_HERE,
2405 method_factory_.NewRunnableMethod(
[email protected]fa2416f2011-05-03 08:41:202406 &ExtensionService::TrackTerminatedExtension,
2407 host->extension()));
[email protected]31f77262009-12-02 20:48:532408 break;
2409 }
[email protected]432115822011-07-10 15:52:272410 case content::NOTIFICATION_RENDERER_PROCESS_CREATED: {
[email protected]77a6970c2011-04-23 16:58:562411 RenderProcessHost* process = Source<RenderProcessHost>(source).ptr();
2412 // Valid extension function names, used to setup bindings in renderer.
2413 std::vector<std::string> function_names;
2414 ExtensionFunctionDispatcher::GetAllFunctionNames(&function_names);
2415 process->Send(new ExtensionMsg_SetFunctionNames(function_names));
[email protected]31f77262009-12-02 20:48:532416
[email protected]77a6970c2011-04-23 16:58:562417 // Scripting whitelist. This is modified by tests and must be communicated
2418 // to renderers.
2419 process->Send(new ExtensionMsg_SetScriptingWhitelist(
2420 *Extension::GetScriptingWhitelist()));
2421
2422 // Loaded extensions.
2423 for (size_t i = 0; i < extensions_.size(); ++i) {
2424 process->Send(new ExtensionMsg_Loaded(
[email protected]902fd7b2011-07-27 18:42:312425 ExtensionMsg_Loaded_Params(
2426 extensions_[i], extensions_[i]->GetActivePermissions())));
[email protected]77a6970c2011-04-23 16:58:562427 }
2428 break;
2429 }
[email protected]432115822011-07-10 15:52:272430 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: {
[email protected]da5683db2011-04-23 17:12:212431 RenderProcessHost* process = Source<RenderProcessHost>(source).ptr();
2432 installed_app_hosts_.erase(process->id());
2433 break;
2434 }
[email protected]432115822011-07-10 15:52:272435 case chrome::NOTIFICATION_PREF_CHANGED: {
[email protected]aa96d3a2010-08-21 08:45:252436 std::string* pref_name = Details<std::string>(details).ptr();
[email protected]6c751e72010-11-23 10:11:102437 if (*pref_name == prefs::kExtensionInstallAllowList ||
2438 *pref_name == prefs::kExtensionInstallDenyList) {
2439 CheckAdminBlacklist();
[email protected]6c751e72010-11-23 10:11:102440 } else {
2441 NOTREACHED() << "Unexpected preference name.";
2442 }
[email protected]aa96d3a2010-08-21 08:45:252443 break;
2444 }
2445
[email protected]4814b512009-11-07 00:12:292446 default:
2447 NOTREACHED() << "Unexpected notification type.";
2448 }
2449}
2450
[email protected]eaa7dd182010-12-14 11:09:002451bool ExtensionService::HasApps() const {
[email protected]ec5b50d2010-10-09 16:35:182452 return !GetAppIds().empty();
2453}
[email protected]377011d2010-07-20 04:18:502454
[email protected]eaa7dd182010-12-14 11:09:002455ExtensionIdSet ExtensionService::GetAppIds() const {
[email protected]ec5b50d2010-10-09 16:35:182456 ExtensionIdSet result;
[email protected]377011d2010-07-20 04:18:502457 for (ExtensionList::const_iterator it = extensions_.begin();
2458 it != extensions_.end(); ++it) {
[email protected]ec5b50d2010-10-09 16:35:182459 if ((*it)->is_app() && (*it)->location() != Extension::COMPONENT)
2460 result.insert((*it)->id());
[email protected]377011d2010-07-20 04:18:502461 }
2462
[email protected]ec5b50d2010-10-09 16:35:182463 return result;
[email protected]377011d2010-07-20 04:18:502464}
[email protected]d7e9a862010-11-03 21:57:492465
[email protected]14908b72011-04-20 06:54:362466scoped_refptr<CrxInstaller> ExtensionService::MakeCrxInstaller(
2467 ExtensionInstallUI* client) {
2468 return new CrxInstaller(weak_ptr_factory_.GetWeakPtr(), client);
2469}
2470
[email protected]eaa7dd182010-12-14 11:09:002471bool ExtensionService::IsBackgroundPageReady(const Extension* extension) {
[email protected]d7e9a862010-11-03 21:57:492472 return (extension->background_url().is_empty() ||
2473 extension_runtime_data_[extension->id()].background_page_ready);
2474}
2475
[email protected]eaa7dd182010-12-14 11:09:002476void ExtensionService::SetBackgroundPageReady(const Extension* extension) {
[email protected]d7e9a862010-11-03 21:57:492477 DCHECK(!extension->background_url().is_empty());
2478 extension_runtime_data_[extension->id()].background_page_ready = true;
2479 NotificationService::current()->Notify(
[email protected]432115822011-07-10 15:52:272480 chrome::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY,
[email protected]d7e9a862010-11-03 21:57:492481 Source<const Extension>(extension),
2482 NotificationService::NoDetails());
2483}
2484
[email protected]eaa7dd182010-12-14 11:09:002485bool ExtensionService::IsBeingUpgraded(const Extension* extension) {
[email protected]d7e9a862010-11-03 21:57:492486 return extension_runtime_data_[extension->id()].being_upgraded;
2487}
2488
[email protected]eaa7dd182010-12-14 11:09:002489void ExtensionService::SetBeingUpgraded(const Extension* extension,
[email protected]d7e9a862010-11-03 21:57:492490 bool value) {
2491 extension_runtime_data_[extension->id()].being_upgraded = value;
2492}
[email protected]1bead0712010-11-27 17:41:532493
[email protected]eaa7dd182010-12-14 11:09:002494PropertyBag* ExtensionService::GetPropertyBag(const Extension* extension) {
[email protected]1bead0712010-11-27 17:41:532495 return &extension_runtime_data_[extension->id()].property_bag;
2496}
[email protected]cebc3dc2011-04-18 17:15:002497
2498void ExtensionService::RegisterNaClModule(const GURL& url,
2499 const std::string& mime_type) {
2500 NaClModuleInfo info;
2501 info.url = url;
2502 info.mime_type = mime_type;
2503
2504 DCHECK(FindNaClModule(url) == nacl_module_list_.end());
2505 nacl_module_list_.push_front(info);
2506}
2507
2508void ExtensionService::UnregisterNaClModule(const GURL& url) {
2509 NaClModuleInfoList::iterator iter = FindNaClModule(url);
2510 DCHECK(iter != nacl_module_list_.end());
2511 nacl_module_list_.erase(iter);
2512}
2513
[email protected]ed0ba002011-05-26 16:55:132514void ExtensionService::UpdatePluginListWithNaClModules() {
[email protected]300c0ea2011-07-15 23:04:332515 // An extension has been added which has a nacl_module component, which means
2516 // there is a MIME type that module wants to handle, so we need to add that
2517 // MIME type to plugins which handle NaCl modules in order to allow the
2518 // individual modules to handle these types.
[email protected]ed0ba002011-05-26 16:55:132519 const PepperPluginInfo* pepper_info = NULL;
2520 std::vector<PepperPluginInfo> plugins;
2521 PepperPluginRegistry::ComputeList(&plugins);
[email protected]300c0ea2011-07-15 23:04:332522
2523 // Search the entire plugin list for plugins that handle the NaCl MIME type.
2524 // There can be multiple plugins like this, for instance the internal NaCl
2525 // plugin and a plugin registered by --register-pepper-plugins during tests.
[email protected]ed0ba002011-05-26 16:55:132526 for (size_t i = 0; i < plugins.size(); ++i) {
[email protected]300c0ea2011-07-15 23:04:332527 pepper_info = &plugins[i];
2528 CHECK(pepper_info);
2529 std::vector<webkit::npapi::WebPluginMimeType>::const_iterator mime_iter;
2530 // Check each MIME type the plugins handle for the NaCl MIME type.
2531 for (mime_iter = pepper_info->mime_types.begin();
2532 mime_iter != pepper_info->mime_types.end(); ++mime_iter) {
2533 if (mime_iter->mime_type == kNaClPluginMimeType) {
2534 // This plugin handles "application/x-nacl".
2535
2536 webkit::npapi::PluginList::Singleton()->
2537 UnregisterInternalPlugin(pepper_info->path);
2538
2539 webkit::npapi::WebPluginInfo info = pepper_info->ToWebPluginInfo();
2540
2541 for (ExtensionService::NaClModuleInfoList::const_iterator iter =
2542 nacl_module_list_.begin();
2543 iter != nacl_module_list_.end(); ++iter) {
2544 // Add the MIME type specified in the extension to this NaCl plugin,
2545 // With an extra "nacl" argument to specify the location of the NaCl
2546 // manifest file.
2547 webkit::npapi::WebPluginMimeType mime_type_info;
2548 mime_type_info.mime_type = iter->mime_type;
2549 mime_type_info.additional_param_names.push_back(UTF8ToUTF16("nacl"));
2550 mime_type_info.additional_param_values.push_back(
2551 UTF8ToUTF16(iter->url.spec()));
2552 info.mime_types.push_back(mime_type_info);
2553 }
2554
2555 webkit::npapi::PluginList::Singleton()->RefreshPlugins();
2556 webkit::npapi::PluginList::Singleton()->RegisterInternalPlugin(info);
2557 // This plugin has been modified, no need to check the rest of its
2558 // types, but continue checking other plugins.
2559 break;
2560 }
[email protected]ed0ba002011-05-26 16:55:132561 }
2562 }
[email protected]ed0ba002011-05-26 16:55:132563}
2564
[email protected]cebc3dc2011-04-18 17:15:002565ExtensionService::NaClModuleInfoList::iterator
2566 ExtensionService::FindNaClModule(const GURL& url) {
2567 for (NaClModuleInfoList::iterator iter = nacl_module_list_.begin();
2568 iter != nacl_module_list_.end(); ++iter) {
2569 if (iter->url == url)
2570 return iter;
2571 }
2572 return nacl_module_list_.end();
2573}