1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/extensions/extension_service.h"
6
7#include <algorithm>
8#include <set>
9
10#include "base/basictypes.h"
11#include "base/command_line.h"
12#include "base/file_util.h"
13#include "base/metrics/histogram.h"
14#include "base/path_service.h"
15#include "base/stl_util-inl.h"
16#include "base/string16.h"
17#include "base/string_number_conversions.h"
18#include "base/string_util.h"
19#include "base/stringprintf.h"
20#include "base/threading/thread_restrictions.h"
21#include "base/time.h"
22#include "base/utf_string_conversions.h"
23#include "base/values.h"
24#include "base/version.h"
25#include "chrome/browser/browser_process.h"
26#include "chrome/browser/debugger/devtools_manager.h"
27#include "chrome/browser/extensions/crx_installer.h"
28#include "chrome/browser/extensions/apps_promo.h"
29#include "chrome/browser/extensions/extension_accessibility_api.h"
30#include "chrome/browser/extensions/extension_bookmarks_module.h"
31#include "chrome/browser/extensions/extension_browser_event_router.h"
32#include "chrome/browser/extensions/extension_cookies_api.h"
33#include "chrome/browser/extensions/extension_data_deleter.h"
34#include "chrome/browser/extensions/extension_error_reporter.h"
35#include "chrome/browser/extensions/extension_history_api.h"
36#include "chrome/browser/extensions/extension_host.h"
37#include "chrome/browser/extensions/extension_management_api.h"
38#include "chrome/browser/extensions/extension_preference_api.h"
39#include "chrome/browser/extensions/extension_process_manager.h"
40#include "chrome/browser/extensions/extension_processes_api.h"
41#include "chrome/browser/extensions/extension_special_storage_policy.h"
42#include "chrome/browser/extensions/extension_sync_data.h"
43#include "chrome/browser/extensions/extension_updater.h"
44#include "chrome/browser/extensions/extension_web_ui.h"
45#include "chrome/browser/extensions/extension_webnavigation_api.h"
46#include "chrome/browser/extensions/external_extension_provider_impl.h"
47#include "chrome/browser/extensions/external_extension_provider_interface.h"
48#include "chrome/browser/extensions/pending_extension_manager.h"
49#include "chrome/browser/net/chrome_url_request_context.h"
50#include "chrome/browser/prefs/pref_service.h"
51#include "chrome/browser/profiles/profile.h"
52#include "chrome/browser/search_engines/template_url_model.h"
53#include "chrome/browser/themes/theme_service.h"
54#include "chrome/browser/themes/theme_service_factory.h"
55#include "chrome/browser/ui/webui/shown_sections_handler.h"
56#include "chrome/common/child_process_logging.h"
57#include "chrome/common/chrome_paths.h"
58#include "chrome/common/chrome_switches.h"
59#include "chrome/common/extensions/extension.h"
60#include "chrome/common/extensions/extension_constants.h"
61#include "chrome/common/extensions/extension_error_utils.h"
62#include "chrome/common/extensions/extension_file_util.h"
63#include "chrome/common/extensions/extension_l10n_util.h"
64#include "chrome/common/extensions/extension_resource.h"
65#include "chrome/common/pref_names.h"
66#include "chrome/common/url_constants.h"
67#include "content/browser/browser_thread.h"
68#include "content/browser/plugin_process_host.h"
69#include "content/browser/plugin_service.h"
70#include "content/common/json_value_serializer.h"
71#include "content/common/notification_service.h"
72#include "content/common/notification_type.h"
73#include "content/common/pepper_plugin_registry.h"
74#include "googleurl/src/gurl.h"
75#include "net/base/registry_controlled_domain.h"
76#include "webkit/database/database_tracker.h"
77#include "webkit/database/database_util.h"
78#include "webkit/plugins/npapi/plugin_list.h"
79
80#if defined(OS_CHROMEOS)
81#include "chrome/browser/chromeos/extensions/file_browser_event_router.h"
82#include "webkit/fileapi/file_system_context.h"
83#include "webkit/fileapi/file_system_mount_point_provider.h"
84#include "webkit/fileapi/file_system_path_manager.h"
85#endif
86
87using base::Time;
88
89namespace errors = extension_manifest_errors;
90
91namespace {
92
93#if defined(OS_LINUX)
94static const int kOmniboxIconPaddingLeft = 2;
95static const int kOmniboxIconPaddingRight = 2;
96#elif defined(OS_MACOSX)
97static const int kOmniboxIconPaddingLeft = 0;
98static const int kOmniboxIconPaddingRight = 2;
99#else
100static const int kOmniboxIconPaddingLeft = 0;
101static const int kOmniboxIconPaddingRight = 0;
102#endif
103
104// The following enumeration is used in histograms matching
105// Extensions.ManifestReload* .  Values may be added, as long
106// as existing values are not changed.
107enum ManifestReloadReason {
108  NOT_NEEDED = 0,  // Reload not needed.
109  UNPACKED_DIR,  // Unpacked directory
110  NEEDS_RELOCALIZATION,  // The local has changed since we read this extension.
111  NUM_MANIFEST_RELOAD_REASONS
112};
113
114ManifestReloadReason ShouldReloadExtensionManifest(const ExtensionInfo& info) {
115  // Always reload manifests of unpacked extensions, because they can change
116  // on disk independent of the manifest in our prefs.
117  if (info.extension_location == Extension::LOAD)
118    return UNPACKED_DIR;
119
120  // Reload the manifest if it needs to be relocalized.
121  if (extension_l10n_util::ShouldRelocalizeManifest(info))
122    return NEEDS_RELOCALIZATION;
123
124  return NOT_NEEDED;
125}
126
127static void ForceShutdownPlugin(const FilePath& plugin_path) {
128  PluginProcessHost* plugin =
129      PluginService::GetInstance()->FindNpapiPluginProcess(plugin_path);
130  if (plugin)
131    plugin->ForceShutdown();
132}
133
134}  // namespace
135
136ExtensionService::ExtensionRuntimeData::ExtensionRuntimeData()
137    : background_page_ready(false),
138      being_upgraded(false) {
139}
140
141ExtensionService::ExtensionRuntimeData::~ExtensionRuntimeData() {
142}
143
144ExtensionService::NaClModuleInfo::NaClModuleInfo() {
145}
146
147ExtensionService::NaClModuleInfo::~NaClModuleInfo() {
148}
149
150// ExtensionService.
151
152const char* ExtensionService::kInstallDirectoryName = "Extensions";
153const char* ExtensionService::kCurrentVersionFileName = "Current Version";
154
155// Implements IO for the ExtensionService.
156
157class ExtensionServiceBackend
158    : public base::RefCountedThreadSafe<ExtensionServiceBackend> {
159 public:
160  // |install_directory| is a path where to look for extensions to load.
161  explicit ExtensionServiceBackend(const FilePath& install_directory);
162
163  // Loads a single extension from |path| where |path| is the top directory of
164  // a specific extension where its manifest file lives.
165  // Errors are reported through ExtensionErrorReporter. On success,
166  // AddExtension() is called.
167  // TODO(erikkay): It might be useful to be able to load a packed extension
168  // (presumably into memory) without installing it.
169  void LoadSingleExtension(const FilePath &path,
170                           scoped_refptr<ExtensionService> frontend);
171
172 private:
173  friend class base::RefCountedThreadSafe<ExtensionServiceBackend>;
174
175  virtual ~ExtensionServiceBackend();
176
177  // Finish installing the extension in |crx_path| after it has been unpacked to
178  // |unpacked_path|.  If |expected_id| is not empty, it's verified against the
179  // extension's manifest before installation. If |silent| is true, there will
180  // be no install confirmation dialog. |from_gallery| indicates whether the
181  // crx was installed from our gallery, which results in different UI.
182  //
183  // Note: We take ownership of |extension|.
184  void OnExtensionUnpacked(const FilePath& crx_path,
185                           const FilePath& unpacked_path,
186                           const Extension* extension,
187                           const std::string expected_id);
188
189  // Notify the frontend that there was an error loading an extension.
190  void ReportExtensionLoadError(const FilePath& extension_path,
191                                const std::string& error);
192
193  // This is a naked pointer which is set by each entry point.
194  // The entry point is responsible for ensuring lifetime.
195  ExtensionService* frontend_;
196
197  // The top-level extensions directory being installed to.
198  FilePath install_directory_;
199
200  // Whether errors result in noisy alerts.
201  bool alert_on_error_;
202
203  DISALLOW_COPY_AND_ASSIGN(ExtensionServiceBackend);
204};
205
206ExtensionServiceBackend::ExtensionServiceBackend(
207    const FilePath& install_directory)
208        : frontend_(NULL),
209          install_directory_(install_directory),
210          alert_on_error_(false) {
211}
212
213ExtensionServiceBackend::~ExtensionServiceBackend() {
214}
215
216void ExtensionServiceBackend::LoadSingleExtension(
217    const FilePath& path_in, scoped_refptr<ExtensionService> frontend) {
218  CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
219
220  frontend_ = frontend;
221
222  // Explicit UI loads are always noisy.
223  alert_on_error_ = true;
224
225  FilePath extension_path = path_in;
226  file_util::AbsolutePath(&extension_path);
227
228  int flags = Extension::ShouldAlwaysAllowFileAccess(Extension::LOAD) ?
229      Extension::ALLOW_FILE_ACCESS : Extension::NO_FLAGS;
230  if (Extension::ShouldDoStrictErrorChecking(Extension::LOAD))
231    flags |= Extension::STRICT_ERROR_CHECKS;
232  std::string error;
233  scoped_refptr<const Extension> extension(extension_file_util::LoadExtension(
234      extension_path,
235      Extension::LOAD,
236      flags,
237      &error));
238
239  if (!extension) {
240    ReportExtensionLoadError(extension_path, error);
241    return;
242  }
243
244  // Report this as an installed extension so that it gets remembered in the
245  // prefs.
246  BrowserThread::PostTask(
247      BrowserThread::UI, FROM_HERE,
248      NewRunnableMethod(frontend_,
249                        &ExtensionService::OnExtensionInstalled,
250                        extension));
251}
252
253void ExtensionServiceBackend::ReportExtensionLoadError(
254    const FilePath& extension_path, const std::string &error) {
255  CHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
256  BrowserThread::PostTask(
257      BrowserThread::UI, FROM_HERE,
258      NewRunnableMethod(
259          frontend_,
260          &ExtensionService::ReportExtensionLoadError, extension_path,
261          error, NotificationType::EXTENSION_INSTALL_ERROR, alert_on_error_));
262}
263
264void ExtensionService::CheckExternalUninstall(const std::string& id) {
265  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
266
267  // Check if the providers know about this extension.
268  ProviderCollection::const_iterator i;
269  for (i = external_extension_providers_.begin();
270       i != external_extension_providers_.end(); ++i) {
271    DCHECK(i->get()->IsReady());
272    if (i->get()->HasExtension(id))
273      return;  // Yup, known extension, don't uninstall.
274  }
275
276  // This is an external extension that we don't have registered.  Uninstall.
277  UninstallExtension(id, true, NULL);
278}
279
280void ExtensionService::ClearProvidersForTesting() {
281  external_extension_providers_.clear();
282}
283
284void ExtensionService::AddProviderForTesting(
285    ExternalExtensionProviderInterface* test_provider) {
286  CHECK(test_provider);
287  external_extension_providers_.push_back(
288      linked_ptr<ExternalExtensionProviderInterface>(test_provider));
289}
290
291void ExtensionService::OnExternalExtensionUpdateUrlFound(
292    const std::string& id,
293    const GURL& update_url,
294    Extension::Location location) {
295  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
296  CHECK(Extension::IdIsValid(id));
297
298  if (GetExtensionById(id, true)) {
299    // Already installed.  Do not change the update URL that the extension set.
300    return;
301  }
302  pending_extension_manager()->AddFromExternalUpdateUrl(
303      id, update_url, location);
304  external_extension_url_added_ |= true;
305}
306
307bool ExtensionService::IsDownloadFromGallery(const GURL& download_url,
308                                             const GURL& referrer_url) {
309  // Special-case the themes mini-gallery.
310  // TODO(erikkay) When that gallery goes away, remove this code.
311  if (IsDownloadFromMiniGallery(download_url) &&
312      StartsWithASCII(referrer_url.spec(),
313                      extension_urls::kMiniGalleryBrowsePrefix, false)) {
314    return true;
315  }
316
317  const Extension* download_extension = GetExtensionByWebExtent(download_url);
318  const Extension* referrer_extension = GetExtensionByWebExtent(referrer_url);
319  const Extension* webstore_app = GetWebStoreApp();
320
321  bool referrer_valid = (referrer_extension == webstore_app);
322  bool download_valid = (download_extension == webstore_app);
323
324  // If the command-line gallery URL is set, then be a bit more lenient.
325  GURL store_url =
326      GURL(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
327           switches::kAppsGalleryURL));
328  if (!store_url.is_empty()) {
329    std::string store_tld =
330        net::RegistryControlledDomainService::GetDomainAndRegistry(store_url);
331    if (!referrer_valid) {
332      std::string referrer_tld =
333          net::RegistryControlledDomainService::GetDomainAndRegistry(
334              referrer_url);
335      // The referrer gets stripped when transitioning from https to http,
336      // or when hitting an unknown test cert and that commonly happens in
337      // testing environments.  Given this, we allow an empty referrer when
338      // the command-line flag is set.
339      // Otherwise, the TLD must match the TLD of the command-line url.
340      referrer_valid = referrer_url.is_empty() || (referrer_tld == store_tld);
341    }
342
343    if (!download_valid) {
344      std::string download_tld =
345          net::RegistryControlledDomainService::GetDomainAndRegistry(
346              GURL(download_url));
347
348      // Otherwise, the TLD must match the TLD of the command-line url.
349      download_valid = (download_tld == store_tld);
350    }
351  }
352
353  return (referrer_valid && download_valid);
354}
355
356bool ExtensionService::IsDownloadFromMiniGallery(const GURL& download_url) {
357  return StartsWithASCII(download_url.spec(),
358                         extension_urls::kMiniGalleryDownloadPrefix,
359                         false);  // case_sensitive
360}
361
362const Extension* ExtensionService::GetInstalledApp(const GURL& url) {
363  // Check for hosted app.
364  const Extension* app = GetExtensionByWebExtent(url);
365  if (app)
366    return app;
367
368  // Check for packaged app.
369  app = GetExtensionByURL(url);
370  if (app && app->is_app())
371    return app;
372
373  return NULL;
374}
375
376bool ExtensionService::IsInstalledApp(const GURL& url) {
377  return !!GetInstalledApp(url);
378}
379
380// static
381// This function is used to implement the command-line switch
382// --uninstall-extension.  The LOG statements within this function are used to
383// inform the user if the uninstall cannot be done.
384bool ExtensionService::UninstallExtensionHelper(
385    ExtensionService* extensions_service,
386    const std::string& extension_id) {
387
388  const Extension* extension =
389      extensions_service->GetExtensionById(extension_id, true);
390  if (!extension)
391    extension = extensions_service->GetTerminatedExtension(extension_id);
392
393  // We can't call UninstallExtension with an invalid extension ID.
394  if (!extension) {
395    LOG(WARNING) << "Attempted uninstallation of non-existent extension with "
396                 << "id: " << extension_id;
397    return false;
398  }
399
400  // The following call to UninstallExtension will not allow an uninstall of a
401  // policy-controlled extension.
402  std::string error;
403  if (!extensions_service->UninstallExtension(extension_id, false, &error)) {
404    LOG(WARNING) << "Cannot uninstall extension with id " << extension_id
405                 << ": " << error;
406    return false;
407  }
408
409  return true;
410}
411
412ExtensionService::ExtensionService(Profile* profile,
413                                   const CommandLine* command_line,
414                                   const FilePath& install_directory,
415                                   ExtensionPrefs* extension_prefs,
416                                   bool autoupdate_enabled,
417                                   bool extensions_enabled)
418    : profile_(profile),
419      extension_prefs_(extension_prefs),
420      ALLOW_THIS_IN_INITIALIZER_LIST(pending_extension_manager_(*this)),
421      install_directory_(install_directory),
422      extensions_enabled_(extensions_enabled),
423      show_extensions_prompts_(true),
424      ready_(false),
425      ALLOW_THIS_IN_INITIALIZER_LIST(toolbar_model_(this)),
426      apps_promo_(profile->GetPrefs()),
427      event_routers_initialized_(false) {
428  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
429
430  // Figure out if extension installation should be enabled.
431  if (command_line->HasSwitch(switches::kDisableExtensions)) {
432    extensions_enabled_ = false;
433  } else if (profile->GetPrefs()->GetBoolean(prefs::kDisableExtensions)) {
434    extensions_enabled_ = false;
435  }
436
437  registrar_.Add(this, NotificationType::EXTENSION_PROCESS_TERMINATED,
438                 NotificationService::AllSources());
439  pref_change_registrar_.Init(profile->GetPrefs());
440  pref_change_registrar_.Add(prefs::kExtensionInstallAllowList, this);
441  pref_change_registrar_.Add(prefs::kExtensionInstallDenyList, this);
442
443  // Set up the ExtensionUpdater
444  if (autoupdate_enabled) {
445    int update_frequency = kDefaultUpdateFrequencySeconds;
446    if (command_line->HasSwitch(switches::kExtensionsUpdateFrequency)) {
447      base::StringToInt(command_line->GetSwitchValueASCII(
448          switches::kExtensionsUpdateFrequency),
449          &update_frequency);
450    }
451    updater_.reset(new ExtensionUpdater(this,
452                                        extension_prefs,
453                                        profile->GetPrefs(),
454                                        profile,
455                                        update_frequency));
456  }
457
458  backend_ = new ExtensionServiceBackend(install_directory_);
459
460  if (extensions_enabled_) {
461    ExternalExtensionProviderImpl::CreateExternalProviders(
462        this, profile_, &external_extension_providers_);
463  }
464
465  // Use monochrome icons for Omnibox icons.
466  omnibox_popup_icon_manager_.set_monochrome(true);
467  omnibox_icon_manager_.set_monochrome(true);
468  omnibox_icon_manager_.set_padding(gfx::Insets(0, kOmniboxIconPaddingLeft,
469                                                0, kOmniboxIconPaddingRight));
470}
471
472const ExtensionList* ExtensionService::extensions() const {
473  return &extensions_;
474}
475
476const ExtensionList* ExtensionService::disabled_extensions() const {
477  return &disabled_extensions_;
478}
479
480const ExtensionList* ExtensionService::terminated_extensions() const {
481  return &terminated_extensions_;
482}
483
484PendingExtensionManager* ExtensionService::pending_extension_manager() {
485  return &pending_extension_manager_;
486}
487
488ExtensionService::~ExtensionService() {
489  DCHECK(!profile_);  // Profile should have told us it's going away.
490  UnloadAllExtensions();
491
492  ProviderCollection::const_iterator i;
493  for (i = external_extension_providers_.begin();
494       i != external_extension_providers_.end(); ++i) {
495    ExternalExtensionProviderInterface* provider = i->get();
496    provider->ServiceShutdown();
497  }
498
499#if defined(OS_CHROMEOS)
500  if (event_routers_initialized_) {
501    ExtensionFileBrowserEventRouter::GetInstance()->
502        StopObservingFileSystemEvents();
503  }
504#endif
505}
506
507void ExtensionService::InitEventRouters() {
508  if (event_routers_initialized_)
509    return;
510
511  ExtensionHistoryEventRouter::GetInstance()->ObserveProfile(profile_);
512  ExtensionAccessibilityEventRouter::GetInstance()->ObserveProfile(profile_);
513  browser_event_router_.reset(new ExtensionBrowserEventRouter(profile_));
514  browser_event_router_->Init();
515  preference_event_router_.reset(new ExtensionPreferenceEventRouter(profile_));
516  ExtensionBookmarkEventRouter::GetInstance()->Observe(
517      profile_->GetBookmarkModel());
518  ExtensionCookiesEventRouter::GetInstance()->Init();
519  ExtensionManagementEventRouter::GetInstance()->Init();
520  ExtensionProcessesEventRouter::GetInstance()->ObserveProfile(profile_);
521  ExtensionWebNavigationEventRouter::GetInstance()->Init();
522#if defined(OS_CHROMEOS)
523  ExtensionFileBrowserEventRouter::GetInstance()->ObserveFileSystemEvents(
524      profile_);
525#endif
526  event_routers_initialized_ = true;
527}
528
529const Extension* ExtensionService::GetExtensionById(
530    const std::string& id, bool include_disabled) const {
531  return GetExtensionByIdInternal(id, true, include_disabled);
532}
533
534void ExtensionService::Init() {
535  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
536
537  DCHECK(!ready_);  // Can't redo init.
538  DCHECK_EQ(extensions_.size(), 0u);
539
540  // Hack: we need to ensure the ResourceDispatcherHost is ready before we load
541  // the first extension, because its members listen for loaded notifications.
542  g_browser_process->resource_dispatcher_host();
543
544  LoadAllExtensions();
545
546  // TODO(erikkay) this should probably be deferred to a future point
547  // rather than running immediately at startup.
548  CheckForExternalUpdates();
549
550  // TODO(erikkay) this should probably be deferred as well.
551  GarbageCollectExtensions();
552}
553
554void ExtensionService::UpdateExtension(const std::string& id,
555                                       const FilePath& extension_path,
556                                       const GURL& download_url) {
557  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
558
559  PendingExtensionInfo pending_extension_info;
560  bool is_pending_extension = pending_extension_manager_.GetById(
561      id, &pending_extension_info);
562
563  const Extension* extension = GetExtensionByIdInternal(id, true, true);
564  if (!is_pending_extension && !extension) {
565    LOG(WARNING) << "Will not update extension " << id
566                 << " because it is not installed or pending";
567    // Delete extension_path since we're not creating a CrxInstaller
568    // that would do it for us.
569    BrowserThread::PostTask(
570        BrowserThread::FILE, FROM_HERE,
571        NewRunnableFunction(
572            extension_file_util::DeleteFile, extension_path, false));
573    return;
574  }
575
576  // We want a silent install only for non-pending extensions and
577  // pending extensions that have install_silently set.
578  ExtensionInstallUI* client =
579      (!is_pending_extension || pending_extension_info.install_silently()) ?
580      NULL : new ExtensionInstallUI(profile_);
581
582  scoped_refptr<CrxInstaller> installer(
583      new CrxInstaller(this,  // frontend
584                       client));
585  installer->set_expected_id(id);
586  if (is_pending_extension)
587    installer->set_install_source(pending_extension_info.install_source());
588  else if (extension)
589    installer->set_install_source(extension->location());
590  installer->set_delete_source(true);
591  installer->set_original_url(download_url);
592  installer->InstallCrx(extension_path);
593}
594
595void ExtensionService::ReloadExtension(const std::string& extension_id) {
596  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
597  FilePath path;
598  const Extension* current_extension = GetExtensionById(extension_id, false);
599
600  // Disable the extension if it's loaded. It might not be loaded if it crashed.
601  if (current_extension) {
602    // If the extension has an inspector open for its background page, detach
603    // the inspector and hang onto a cookie for it, so that we can reattach
604    // later.
605    ExtensionProcessManager* manager = profile_->GetExtensionProcessManager();
606    ExtensionHost* host = manager->GetBackgroundHostForExtension(
607        current_extension);
608    if (host) {
609      // Look for an open inspector for the background page.
610      int devtools_cookie = DevToolsManager::GetInstance()->DetachClientHost(
611          host->render_view_host());
612      if (devtools_cookie >= 0)
613        orphaned_dev_tools_[extension_id] = devtools_cookie;
614    }
615
616    path = current_extension->path();
617    DisableExtension(extension_id);
618    disabled_extension_paths_[extension_id] = path;
619  } else {
620    path = unloaded_extension_paths_[extension_id];
621  }
622
623  // Check the installed extensions to see if what we're reloading was already
624  // installed.
625  scoped_ptr<ExtensionInfo> installed_extension(
626      extension_prefs_->GetInstalledExtensionInfo(extension_id));
627  if (installed_extension.get() &&
628      installed_extension->extension_manifest.get()) {
629    LoadInstalledExtension(*installed_extension, false);
630  } else {
631    // We should always be able to remember the extension's path. If it's not in
632    // the map, someone failed to update |unloaded_extension_paths_|.
633    CHECK(!path.empty());
634    LoadExtension(path);
635  }
636}
637
638bool ExtensionService::UninstallExtension(const std::string& extension_id,
639                                          bool external_uninstall,
640                                          std::string* error) {
641  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
642
643  const Extension* extension =
644      GetExtensionByIdInternal(extension_id, true, true);
645  if (!extension)
646    extension = GetTerminatedExtension(extension_id);
647
648  // Callers should not send us nonexistent extensions.
649  CHECK(extension);
650
651  // Get hold of information we need after unloading, since the extension
652  // pointer will be invalid then.
653  GURL extension_url(extension->url());
654  Extension::Location location(extension->location());
655
656  // Policy change which triggers an uninstall will always set
657  // |external_uninstall| to true so this is the only way to uninstall
658  // managed extensions.
659  if (!Extension::UserMayDisable(location) && !external_uninstall) {
660    NotificationService::current()->Notify(
661        NotificationType::EXTENSION_UNINSTALL_NOT_ALLOWED,
662        Source<Profile>(profile_),
663        Details<const Extension>(extension));
664    if (error != NULL) {
665      *error = errors::kCannotUninstallManagedExtension;
666    }
667    return false;
668  }
669
670  UninstalledExtensionInfo uninstalled_extension_info(*extension);
671
672  UMA_HISTOGRAM_ENUMERATION("Extensions.UninstallType",
673                            extension->GetType(), 100);
674  RecordPermissionMessagesHistogram(
675      extension, "Extensions.Permissions_Uninstall");
676
677  // Also copy the extension identifier since the reference might have been
678  // obtained via Extension::id().
679  std::string extension_id_copy(extension_id);
680
681  if (profile_->GetTemplateURLModel())
682    profile_->GetTemplateURLModel()->UnregisterExtensionKeyword(extension);
683
684  // Unload before doing more cleanup to ensure that nothing is hanging on to
685  // any of these resources.
686  UnloadExtension(extension_id, UnloadedExtensionInfo::UNINSTALL);
687
688  extension_prefs_->OnExtensionUninstalled(extension_id_copy, location,
689                                           external_uninstall);
690
691  // Tell the backend to start deleting installed extensions on the file thread.
692  if (Extension::LOAD != location) {
693    BrowserThread::PostTask(
694      BrowserThread::FILE, FROM_HERE,
695      NewRunnableFunction(
696          &extension_file_util::UninstallExtension,
697          install_directory_,
698          extension_id_copy));
699  }
700
701  ClearExtensionData(extension_url);
702  UntrackTerminatedExtension(extension_id);
703
704  // Notify interested parties that we've uninstalled this extension.
705  NotificationService::current()->Notify(
706      NotificationType::EXTENSION_UNINSTALLED,
707      Source<Profile>(profile_),
708      Details<UninstalledExtensionInfo>(&uninstalled_extension_info));
709
710  return true;
711}
712
713void ExtensionService::ClearExtensionData(const GURL& extension_url) {
714  scoped_refptr<ExtensionDataDeleter> deleter(
715      new ExtensionDataDeleter(profile_, extension_url));
716  deleter->StartDeleting();
717}
718
719bool ExtensionService::IsExtensionEnabled(
720    const std::string& extension_id) const {
721  // TODO(akalin): GetExtensionState() isn't very safe as it returns
722  // Extension::ENABLED by default; either change it to return
723  // something else by default or create a separate function that does
724  // so.
725  return
726      extension_prefs_->GetExtensionState(extension_id) == Extension::ENABLED;
727}
728
729bool ExtensionService::IsExternalExtensionUninstalled(
730    const std::string& extension_id) const {
731  return extension_prefs_->IsExternalExtensionUninstalled(extension_id);
732}
733
734void ExtensionService::EnableExtension(const std::string& extension_id) {
735  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
736
737  const Extension* extension =
738      GetExtensionByIdInternal(extension_id, false, true);
739  if (!extension)
740    return;
741
742  extension_prefs_->SetExtensionState(extension, Extension::ENABLED);
743
744  // Move it over to the enabled list.
745  extensions_.push_back(make_scoped_refptr(extension));
746  ExtensionList::iterator iter = std::find(disabled_extensions_.begin(),
747                                           disabled_extensions_.end(),
748                                           extension);
749  disabled_extensions_.erase(iter);
750
751  // Make sure any browser action contained within it is not hidden.
752  extension_prefs_->SetBrowserActionVisibility(extension, true);
753
754  ExtensionWebUI::RegisterChromeURLOverrides(profile_,
755      extension->GetChromeURLOverrides());
756
757  NotifyExtensionLoaded(extension);
758  UpdateActiveExtensionsInCrashReporter();
759}
760
761void ExtensionService::DisableExtension(const std::string& extension_id) {
762  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
763
764  const Extension* extension =
765      GetExtensionByIdInternal(extension_id, true, false);
766  // The extension may have been disabled already.
767  if (!extension)
768    return;
769
770  if (!Extension::UserMayDisable(extension->location()))
771    return;
772
773  extension_prefs_->SetExtensionState(extension, Extension::DISABLED);
774
775  // Move it over to the disabled list.
776  disabled_extensions_.push_back(make_scoped_refptr(extension));
777  ExtensionList::iterator iter = std::find(extensions_.begin(),
778                                           extensions_.end(),
779                                           extension);
780  extensions_.erase(iter);
781
782  ExtensionWebUI::UnregisterChromeURLOverrides(profile_,
783      extension->GetChromeURLOverrides());
784
785  NotifyExtensionUnloaded(extension, UnloadedExtensionInfo::DISABLE);
786  UpdateActiveExtensionsInCrashReporter();
787}
788
789void ExtensionService::GrantPermissions(const Extension* extension) {
790  CHECK(extension);
791
792  // We only maintain the granted permissions prefs for INTERNAL extensions.
793  CHECK_EQ(Extension::INTERNAL, extension->location());
794
795  ExtensionExtent effective_hosts = extension->GetEffectiveHostPermissions();
796  extension_prefs_->AddGrantedPermissions(extension->id(),
797                                          extension->HasFullPermissions(),
798                                          extension->api_permissions(),
799                                          effective_hosts);
800}
801
802void ExtensionService::GrantPermissionsAndEnableExtension(
803    const Extension* extension) {
804  CHECK(extension);
805  RecordPermissionMessagesHistogram(
806      extension, "Extensions.Permissions_ReEnable");
807  GrantPermissions(extension);
808  extension_prefs_->SetDidExtensionEscalatePermissions(extension, false);
809  EnableExtension(extension->id());
810}
811
812void ExtensionService::LoadExtension(const FilePath& extension_path) {
813  BrowserThread::PostTask(
814      BrowserThread::FILE, FROM_HERE,
815      NewRunnableMethod(
816          backend_.get(),
817          &ExtensionServiceBackend::LoadSingleExtension,
818          extension_path, scoped_refptr<ExtensionService>(this)));
819}
820
821void ExtensionService::LoadComponentExtensions() {
822  for (RegisteredComponentExtensions::iterator it =
823           component_extension_manifests_.begin();
824       it != component_extension_manifests_.end(); ++it) {
825    LoadComponentExtension(*it);
826  }
827}
828
829const Extension* ExtensionService::LoadComponentExtension(
830    const ComponentExtensionInfo &info) {
831  JSONStringValueSerializer serializer(info.manifest);
832  scoped_ptr<Value> manifest(serializer.Deserialize(NULL, NULL));
833  if (!manifest.get()) {
834    DLOG(ERROR) << "Failed to parse manifest for extension";
835    return NULL;
836  }
837
838  int flags = Extension::REQUIRE_KEY;
839  if (Extension::ShouldDoStrictErrorChecking(Extension::COMPONENT))
840    flags |= Extension::STRICT_ERROR_CHECKS;
841  std::string error;
842  scoped_refptr<const Extension> extension(Extension::Create(
843      info.root_directory,
844      Extension::COMPONENT,
845      *static_cast<DictionaryValue*>(manifest.get()),
846      flags,
847      &error));
848  if (!extension.get()) {
849    NOTREACHED() << error;
850    return NULL;
851  }
852  AddExtension(extension);
853  return extension;
854}
855
856void ExtensionService::LoadAllExtensions() {
857  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
858
859  base::TimeTicks start_time = base::TimeTicks::Now();
860
861  // Load any component extensions.
862  LoadComponentExtensions();
863
864  // Load the previously installed extensions.
865  scoped_ptr<ExtensionPrefs::ExtensionsInfo> extensions_info(
866      extension_prefs_->GetInstalledExtensionsInfo());
867
868  std::vector<int> reload_reason_counts(NUM_MANIFEST_RELOAD_REASONS, 0);
869  bool should_write_prefs = false;
870
871  for (size_t i = 0; i < extensions_info->size(); ++i) {
872    ExtensionInfo* info = extensions_info->at(i).get();
873
874    ManifestReloadReason reload_reason = ShouldReloadExtensionManifest(*info);
875    ++reload_reason_counts[reload_reason];
876    UMA_HISTOGRAM_ENUMERATION("Extensions.ManifestReloadEnumValue",
877                              reload_reason, 100);
878
879    if (reload_reason != NOT_NEEDED) {
880      // Reloading and extension reads files from disk.  We do this on the
881      // UI thread because reloads should be very rare, and the complexity
882      // added by delaying the time when the extensions service knows about
883      // all extensions is significant.  See crbug.com/37548 for details.
884      // |allow_io| disables tests that file operations run on the file
885      // thread.
886      base::ThreadRestrictions::ScopedAllowIO allow_io;
887
888      int flags = Extension::NO_FLAGS;
889      if (Extension::ShouldDoStrictErrorChecking(info->extension_location))
890        flags |= Extension::STRICT_ERROR_CHECKS;
891      if (extension_prefs_->AllowFileAccess(info->extension_id))
892        flags |= Extension::ALLOW_FILE_ACCESS;
893      std::string error;
894      scoped_refptr<const Extension> extension(
895          extension_file_util::LoadExtension(
896              info->extension_path,
897              info->extension_location,
898              flags,
899              &error));
900
901      if (extension.get()) {
902        extensions_info->at(i)->extension_manifest.reset(
903            static_cast<DictionaryValue*>(
904                extension->manifest_value()->DeepCopy()));
905        should_write_prefs = true;
906      }
907    }
908  }
909
910  for (size_t i = 0; i < extensions_info->size(); ++i) {
911    LoadInstalledExtension(*extensions_info->at(i), should_write_prefs);
912  }
913
914  OnLoadedInstalledExtensions();
915
916  // The histograms Extensions.ManifestReload* allow us to validate
917  // the assumption that reloading manifest is a rare event.
918  UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadNotNeeded",
919                           reload_reason_counts[NOT_NEEDED]);
920  UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadUnpackedDir",
921                           reload_reason_counts[UNPACKED_DIR]);
922  UMA_HISTOGRAM_COUNTS_100("Extensions.ManifestReloadNeedsRelocalization",
923                           reload_reason_counts[NEEDS_RELOCALIZATION]);
924
925  UMA_HISTOGRAM_COUNTS_100("Extensions.LoadAll", extensions_.size());
926  UMA_HISTOGRAM_COUNTS_100("Extensions.Disabled", disabled_extensions_.size());
927
928  UMA_HISTOGRAM_TIMES("Extensions.LoadAllTime",
929                      base::TimeTicks::Now() - start_time);
930
931  int app_count = 0;
932  int hosted_app_count = 0;
933  int packaged_app_count = 0;
934  int user_script_count = 0;
935  int extension_count = 0;
936  int theme_count = 0;
937  int external_count = 0;
938  int page_action_count = 0;
939  int browser_action_count = 0;
940  ExtensionList::iterator ex;
941  for (ex = extensions_.begin(); ex != extensions_.end(); ++ex) {
942    Extension::Location location = (*ex)->location();
943    Extension::Type type = (*ex)->GetType();
944    if ((*ex)->is_app()) {
945      UMA_HISTOGRAM_ENUMERATION("Extensions.AppLocation",
946                                location, 100);
947    } else if (type == Extension::TYPE_EXTENSION) {
948      UMA_HISTOGRAM_ENUMERATION("Extensions.ExtensionLocation",
949                                location, 100);
950    }
951
952    // Don't count component extensions, since they are only extensions as an
953    // implementation detail.
954    if (location == Extension::COMPONENT)
955      continue;
956
957    // Don't count unpacked extensions, since they're a developer-specific
958    // feature.
959    if (location == Extension::LOAD)
960      continue;
961
962    // Using an enumeration shows us the total installed ratio across all users.
963    // Using the totals per user at each startup tells us the distribution of
964    // usage for each user (e.g. 40% of users have at least one app installed).
965    UMA_HISTOGRAM_ENUMERATION("Extensions.LoadType", type, 100);
966    switch (type) {
967      case Extension::TYPE_THEME:
968        ++theme_count;
969        break;
970      case Extension::TYPE_USER_SCRIPT:
971        ++user_script_count;
972        break;
973      case Extension::TYPE_HOSTED_APP:
974        ++app_count;
975        ++hosted_app_count;
976        break;
977      case Extension::TYPE_PACKAGED_APP:
978        ++app_count;
979        ++packaged_app_count;
980        break;
981      case Extension::TYPE_EXTENSION:
982      default:
983        ++extension_count;
984        break;
985    }
986    if (Extension::IsExternalLocation(location))
987      ++external_count;
988    if ((*ex)->page_action() != NULL)
989      ++page_action_count;
990    if ((*ex)->browser_action() != NULL)
991      ++browser_action_count;
992
993    RecordPermissionMessagesHistogram(
994        ex->get(), "Extensions.Permissions_Load");
995  }
996  UMA_HISTOGRAM_COUNTS_100("Extensions.LoadApp", app_count);
997  UMA_HISTOGRAM_COUNTS_100("Extensions.LoadHostedApp", hosted_app_count);
998  UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPackagedApp", packaged_app_count);
999  UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExtension", extension_count);
1000  UMA_HISTOGRAM_COUNTS_100("Extensions.LoadUserScript", user_script_count);
1001  UMA_HISTOGRAM_COUNTS_100("Extensions.LoadTheme", theme_count);
1002  UMA_HISTOGRAM_COUNTS_100("Extensions.LoadExternal", external_count);
1003  UMA_HISTOGRAM_COUNTS_100("Extensions.LoadPageAction", page_action_count);
1004  UMA_HISTOGRAM_COUNTS_100("Extensions.LoadBrowserAction",
1005                           browser_action_count);
1006}
1007
1008// static
1009void ExtensionService::RecordPermissionMessagesHistogram(
1010    const Extension* e, const char* histogram) {
1011  // Since this is called from multiple sources, and since the Histogram macros
1012  // use statics, we need to manually lookup the Histogram ourselves.
1013  base::Histogram* counter = base::LinearHistogram::FactoryGet(
1014      histogram,
1015      1,
1016      Extension::PermissionMessage::ID_ENUM_BOUNDARY,
1017      Extension::PermissionMessage::ID_ENUM_BOUNDARY + 1,
1018      base::Histogram::kUmaTargetedHistogramFlag);
1019
1020  std::vector<Extension::PermissionMessage> permissions =
1021      e->GetPermissionMessages();
1022  if (permissions.empty()) {
1023    counter->Add(Extension::PermissionMessage::ID_NONE);
1024  } else {
1025    std::vector<Extension::PermissionMessage>::iterator it;
1026    for (it = permissions.begin(); it != permissions.end(); ++it)
1027      counter->Add(it->message_id());
1028  }
1029}
1030
1031void ExtensionService::LoadInstalledExtension(const ExtensionInfo& info,
1032                                              bool write_to_prefs) {
1033  std::string error;
1034  scoped_refptr<const Extension> extension(NULL);
1035  if (!extension_prefs_->IsExtensionAllowedByPolicy(info.extension_id)) {
1036    error = errors::kDisabledByPolicy;
1037  } else if (info.extension_manifest.get()) {
1038    int flags = Extension::NO_FLAGS;
1039    if (info.extension_location != Extension::LOAD)
1040      flags |= Extension::REQUIRE_KEY;
1041    if (Extension::ShouldDoStrictErrorChecking(info.extension_location))
1042      flags |= Extension::STRICT_ERROR_CHECKS;
1043    if (extension_prefs_->AllowFileAccess(info.extension_id))
1044      flags |= Extension::ALLOW_FILE_ACCESS;
1045    extension = Extension::Create(
1046        info.extension_path,
1047        info.extension_location,
1048        *info.extension_manifest,
1049        flags,
1050        &error);
1051  } else {
1052    error = errors::kManifestUnreadable;
1053  }
1054
1055  if (!extension) {
1056    ReportExtensionLoadError(info.extension_path,
1057                             error,
1058                             NotificationType::EXTENSION_INSTALL_ERROR,
1059                             false);
1060    return;
1061  }
1062
1063  if (write_to_prefs)
1064    extension_prefs_->UpdateManifest(extension);
1065
1066  AddExtension(extension);
1067}
1068
1069void ExtensionService::NotifyExtensionLoaded(const Extension* extension) {
1070  // The ChromeURLRequestContexts need to be first to know that the extension
1071  // was loaded, otherwise a race can arise where a renderer that is created
1072  // for the extension may try to load an extension URL with an extension id
1073  // that the request context doesn't yet know about. The profile is responsible
1074  // for ensuring its URLRequestContexts appropriately discover the loaded
1075  // extension.
1076  if (profile_) {
1077    profile_->RegisterExtensionWithRequestContexts(extension);
1078    profile_->GetExtensionSpecialStoragePolicy()->
1079        GrantRightsForExtension(extension);
1080  }
1081
1082  NotificationService::current()->Notify(
1083      NotificationType::EXTENSION_LOADED,
1084      Source<Profile>(profile_),
1085      Details<const Extension>(extension));
1086
1087  bool plugins_changed = false;
1088  for (size_t i = 0; i < extension->plugins().size(); ++i) {
1089    const Extension::PluginInfo& plugin = extension->plugins()[i];
1090    webkit::npapi::PluginList::Singleton()->RefreshPlugins();
1091    webkit::npapi::PluginList::Singleton()->AddExtraPluginPath(plugin.path);
1092    plugins_changed = true;
1093    if (!plugin.is_public) {
1094      PluginService::GetInstance()->RestrictPluginToUrl(
1095          plugin.path, extension->url());
1096    }
1097  }
1098
1099  bool nacl_modules_changed = false;
1100  for (size_t i = 0; i < extension->nacl_modules().size(); ++i) {
1101    const Extension::NaClModuleInfo& module = extension->nacl_modules()[i];
1102    RegisterNaClModule(module.url, module.mime_type);
1103    nacl_modules_changed = true;
1104  }
1105
1106  if (nacl_modules_changed)
1107    UpdatePluginListWithNaClModules();
1108
1109  if (plugins_changed || nacl_modules_changed)
1110    PluginService::GetInstance()->PurgePluginListCache(false);
1111}
1112
1113void ExtensionService::NotifyExtensionUnloaded(
1114    const Extension* extension, UnloadedExtensionInfo::Reason reason) {
1115  UnloadedExtensionInfo details(extension, reason);
1116  NotificationService::current()->Notify(
1117      NotificationType::EXTENSION_UNLOADED,
1118      Source<Profile>(profile_),
1119      Details<UnloadedExtensionInfo>(&details));
1120
1121  if (profile_) {
1122    profile_->UnregisterExtensionWithRequestContexts(extension->id(), reason);
1123    profile_->GetExtensionSpecialStoragePolicy()->
1124        RevokeRightsForExtension(extension);
1125#if defined(OS_CHROMEOS)
1126    // Revoke external file access to
1127    if (profile_->GetFileSystemContext() &&
1128        profile_->GetFileSystemContext()->path_manager() &&
1129        profile_->GetFileSystemContext()->path_manager()->external_provider()) {
1130      profile_->GetFileSystemContext()->path_manager()->external_provider()->
1131          RevokeAccessForExtension(extension->id());
1132    }
1133#endif
1134  }
1135
1136  bool plugins_changed = false;
1137  for (size_t i = 0; i < extension->plugins().size(); ++i) {
1138    const Extension::PluginInfo& plugin = extension->plugins()[i];
1139    BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
1140                            NewRunnableFunction(&ForceShutdownPlugin,
1141                                                plugin.path));
1142    webkit::npapi::PluginList::Singleton()->RefreshPlugins();
1143    webkit::npapi::PluginList::Singleton()->RemoveExtraPluginPath(
1144        plugin.path);
1145    plugins_changed = true;
1146    if (!plugin.is_public)
1147      PluginService::GetInstance()->RestrictPluginToUrl(plugin.path, GURL());
1148  }
1149
1150  bool nacl_modules_changed = false;
1151  for (size_t i = 0; i < extension->nacl_modules().size(); ++i) {
1152    const Extension::NaClModuleInfo& module = extension->nacl_modules()[i];
1153    UnregisterNaClModule(module.url);
1154    nacl_modules_changed = true;
1155  }
1156
1157  if (nacl_modules_changed)
1158    UpdatePluginListWithNaClModules();
1159
1160  if (plugins_changed || nacl_modules_changed)
1161    PluginService::GetInstance()->PurgePluginListCache(false);
1162}
1163
1164void ExtensionService::UpdateExtensionBlacklist(
1165  const std::vector<std::string>& blacklist) {
1166  // Use this set to indicate if an extension in the blacklist has been used.
1167  std::set<std::string> blacklist_set;
1168  for (unsigned int i = 0; i < blacklist.size(); ++i) {
1169    if (Extension::IdIsValid(blacklist[i])) {
1170      blacklist_set.insert(blacklist[i]);
1171    }
1172  }
1173  extension_prefs_->UpdateBlacklist(blacklist_set);
1174  std::vector<std::string> to_be_removed;
1175  // Loop current extensions, unload installed extensions.
1176  for (ExtensionList::const_iterator iter = extensions_.begin();
1177       iter != extensions_.end(); ++iter) {
1178    const Extension* extension = (*iter);
1179    if (blacklist_set.find(extension->id()) != blacklist_set.end()) {
1180      to_be_removed.push_back(extension->id());
1181    }
1182  }
1183
1184  // UnloadExtension will change the extensions_ list. So, we should
1185  // call it outside the iterator loop.
1186  for (unsigned int i = 0; i < to_be_removed.size(); ++i) {
1187    UnloadExtension(to_be_removed[i], UnloadedExtensionInfo::DISABLE);
1188  }
1189}
1190
1191Profile* ExtensionService::profile() {
1192  return profile_;
1193}
1194
1195void ExtensionService::DestroyingProfile() {
1196  if (updater_.get()) {
1197    updater_->Stop();
1198  }
1199  browser_event_router_.reset();
1200  preference_event_router_.reset();
1201  pref_change_registrar_.RemoveAll();
1202  profile_ = NULL;
1203  toolbar_model_.DestroyingProfile();
1204}
1205
1206ExtensionPrefs* ExtensionService::extension_prefs() {
1207  return extension_prefs_;
1208}
1209
1210ExtensionUpdater* ExtensionService::updater() {
1211  return updater_.get();
1212}
1213
1214void ExtensionService::CheckAdminBlacklist() {
1215  std::vector<std::string> to_be_removed;
1216  // Loop through extensions list, unload installed extensions.
1217  for (ExtensionList::const_iterator iter = extensions_.begin();
1218       iter != extensions_.end(); ++iter) {
1219    const Extension* extension = (*iter);
1220    if (!extension_prefs_->IsExtensionAllowedByPolicy(extension->id()))
1221      to_be_removed.push_back(extension->id());
1222  }
1223
1224  // UnloadExtension will change the extensions_ list. So, we should
1225  // call it outside the iterator loop.
1226  for (unsigned int i = 0; i < to_be_removed.size(); ++i)
1227    UnloadExtension(to_be_removed[i], UnloadedExtensionInfo::DISABLE);
1228}
1229
1230void ExtensionService::CheckForUpdatesSoon() {
1231  if (updater()) {
1232    updater()->CheckSoon();
1233  } else {
1234    LOG(WARNING) << "CheckForUpdatesSoon() called with auto-update turned off";
1235  }
1236}
1237
1238void ExtensionService::ProcessSyncData(
1239    const ExtensionSyncData& extension_sync_data,
1240    PendingExtensionInfo::ShouldAllowInstallPredicate should_allow) {
1241  const std::string& id = extension_sync_data.id;
1242
1243  // Handle uninstalls first.
1244  if (extension_sync_data.uninstalled) {
1245    std::string error;
1246    if (!UninstallExtensionHelper(this, id)) {
1247      LOG(WARNING) << "Could not uninstall extension " << id
1248                   << " for sync";
1249    }
1250    return;
1251  }
1252
1253  const Extension* extension = GetExtensionByIdInternal(id, true, true);
1254  // TODO(akalin): Figure out what to do with terminated extensions.
1255
1256  // Handle already-installed extensions (just update settings).
1257  //
1258  // TODO(akalin): Ideally, we should be able to set prefs for an
1259  // extension regardless of whether or not it's installed (and have
1260  // it automatially apply on install).
1261  if (extension) {
1262    if (extension_sync_data.enabled) {
1263      EnableExtension(id);
1264    } else {
1265      DisableExtension(id);
1266    }
1267    SetIsIncognitoEnabled(id, extension_sync_data.incognito_enabled);
1268    int result = extension->version()->CompareTo(extension_sync_data.version);
1269    if (result < 0) {
1270      // Extension is outdated.
1271      CheckForUpdatesSoon();
1272    } else if (result > 0) {
1273      // Sync version is outdated.  Do nothing for now, as sync code
1274      // in other places will eventually update the sync data.
1275      //
1276      // TODO(akalin): Move that code here.
1277    }
1278    return;
1279  }
1280
1281  // Handle not-yet-installed extensions.
1282  //
1283  // TODO(akalin): Replace silent update with a list of enabled
1284  // permissions.
1285  pending_extension_manager()->AddFromSync(
1286      id,
1287      extension_sync_data.update_url,
1288      should_allow,
1289      true,  // install_silently
1290      extension_sync_data.enabled,
1291      extension_sync_data.incognito_enabled);
1292  CheckForUpdatesSoon();
1293}
1294
1295bool ExtensionService::IsIncognitoEnabled(
1296    const std::string& extension_id) const {
1297  // If this is an existing component extension we always allow it to
1298  // work in incognito mode.
1299  const Extension* extension = GetExtensionById(extension_id, true);
1300  if (extension && extension->location() == Extension::COMPONENT)
1301    return true;
1302
1303  // Check the prefs.
1304  return extension_prefs_->IsIncognitoEnabled(extension_id);
1305}
1306
1307void ExtensionService::SetIsIncognitoEnabled(
1308    const std::string& extension_id, bool enabled) {
1309  const Extension* extension = GetExtensionById(extension_id, false);
1310  if (extension && extension->location() == Extension::COMPONENT) {
1311    // This shouldn't be called for component extensions.
1312    NOTREACHED();
1313    return;
1314  }
1315
1316  // Broadcast unloaded and loaded events to update browser state. Only bother
1317  // if the value changed and the extension is actually enabled, since there is
1318  // no UI otherwise.
1319  bool old_enabled = extension_prefs_->IsIncognitoEnabled(extension_id);
1320  if (enabled == old_enabled)
1321    return;
1322
1323  extension_prefs_->SetIsIncognitoEnabled(extension_id, enabled);
1324  if (extension) {
1325    NotifyExtensionUnloaded(extension, UnloadedExtensionInfo::DISABLE);
1326    NotifyExtensionLoaded(extension);
1327  }
1328}
1329
1330bool ExtensionService::CanCrossIncognito(const Extension* extension) {
1331  // We allow the extension to see events and data from another profile iff it
1332  // uses "spanning" behavior and it has incognito access. "split" mode
1333  // extensions only see events for a matching profile.
1334  return IsIncognitoEnabled(extension->id()) &&
1335      !extension->incognito_split_mode();
1336}
1337
1338bool ExtensionService::AllowFileAccess(const Extension* extension) {
1339  return (CommandLine::ForCurrentProcess()->HasSwitch(
1340              switches::kDisableExtensionsFileAccessCheck) ||
1341          extension_prefs_->AllowFileAccess(extension->id()));
1342}
1343
1344void ExtensionService::SetAllowFileAccess(const Extension* extension,
1345                                          bool allow) {
1346  // Reload to update browser state. Only bother if the value changed and the
1347  // extension is actually enabled, since there is no UI otherwise.
1348  bool old_allow = AllowFileAccess(extension);
1349  if (allow == old_allow)
1350    return;
1351
1352  extension_prefs_->SetAllowFileAccess(extension->id(), allow);
1353
1354  bool extension_is_enabled = std::find(extensions_.begin(), extensions_.end(),
1355                                        extension) != extensions_.end();
1356  if (extension_is_enabled)
1357    ReloadExtension(extension->id());
1358}
1359
1360bool ExtensionService::GetBrowserActionVisibility(const Extension* extension) {
1361  return extension_prefs_->GetBrowserActionVisibility(extension);
1362}
1363
1364void ExtensionService::SetBrowserActionVisibility(const Extension* extension,
1365                                                  bool visible) {
1366  extension_prefs_->SetBrowserActionVisibility(extension, visible);
1367}
1368
1369// Some extensions will autoupdate themselves externally from Chrome.  These
1370// are typically part of some larger client application package.  To support
1371// these, the extension will register its location in the the preferences file
1372// (and also, on Windows, in the registry) and this code will periodically
1373// check that location for a .crx file, which it will then install locally if
1374// a new version is available.
1375// Errors are reported through ExtensionErrorReporter. Succcess is not
1376// reported.
1377void ExtensionService::CheckForExternalUpdates() {
1378  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1379
1380  // Note that this installation is intentionally silent (since it didn't
1381  // go through the front-end).  Extensions that are registered in this
1382  // way are effectively considered 'pre-bundled', and so implicitly
1383  // trusted.  In general, if something has HKLM or filesystem access,
1384  // they could install an extension manually themselves anyway.
1385
1386  // If any external extension records give a URL, a provider will set
1387  // this to true.  Used by OnExternalProviderReady() to see if we need
1388  // to start an update check to fetch a new external extension.
1389  external_extension_url_added_ = false;
1390
1391  // Ask each external extension provider to give us a call back for each
1392  // extension they know about. See OnExternalExtension(File|UpdateUrl)Found.
1393  ProviderCollection::const_iterator i;
1394  for (i = external_extension_providers_.begin();
1395       i != external_extension_providers_.end(); ++i) {
1396    ExternalExtensionProviderInterface* provider = i->get();
1397    provider->VisitRegisteredExtension();
1398  }
1399
1400  // Uninstall of unclaimed extensions will happen after all the providers
1401  // had reported ready.  Every provider calls OnExternalProviderReady()
1402  // when it finishes, and OnExternalProviderReady() only acts when all
1403  // providers are ready.  In case there are no providers, we call it
1404  // to trigger removal of extensions that used to have an external source.
1405  if (external_extension_providers_.empty())
1406    OnExternalProviderReady();
1407}
1408
1409void ExtensionService::OnExternalProviderReady() {
1410  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1411
1412  // An external provider has finished loading.  We only take action
1413  // if all of them are finished. So we check them first.
1414  ProviderCollection::const_iterator i;
1415  for (i = external_extension_providers_.begin();
1416       i != external_extension_providers_.end(); ++i) {
1417    ExternalExtensionProviderInterface* provider = i->get();
1418    if (!provider->IsReady())
1419      return;
1420  }
1421
1422  // All the providers are ready.  Install any pending extensions.
1423  if (external_extension_url_added_ && updater()) {
1424    external_extension_url_added_ = false;
1425    updater()->CheckNow();
1426  }
1427
1428  // Uninstall all the unclaimed extensions.
1429  scoped_ptr<ExtensionPrefs::ExtensionsInfo> extensions_info(
1430      extension_prefs_->GetInstalledExtensionsInfo());
1431  for (size_t i = 0; i < extensions_info->size(); ++i) {
1432    ExtensionInfo* info = extensions_info->at(i).get();
1433    if (Extension::IsExternalLocation(info->extension_location))
1434      CheckExternalUninstall(info->extension_id);
1435  }
1436}
1437
1438void ExtensionService::UnloadExtension(
1439    const std::string& extension_id,
1440    UnloadedExtensionInfo::Reason reason) {
1441  // Make sure the extension gets deleted after we return from this function.
1442  scoped_refptr<const Extension> extension(
1443      GetExtensionByIdInternal(extension_id, true, true));
1444
1445  // This method can be called via PostTask, so the extension may have been
1446  // unloaded by the time this runs.
1447  if (!extension) {
1448    // In case the extension may have crashed/uninstalled. Allow the profile to
1449    // clean up its RequestContexts.
1450    profile_->UnregisterExtensionWithRequestContexts(extension_id, reason);
1451    return;
1452  }
1453
1454  // Keep information about the extension so that we can reload it later
1455  // even if it's not permanently installed.
1456  unloaded_extension_paths_[extension->id()] = extension->path();
1457
1458  // Clean up if the extension is meant to be enabled after a reload.
1459  disabled_extension_paths_.erase(extension->id());
1460
1461  // Clean up runtime data.
1462  extension_runtime_data_.erase(extension_id);
1463
1464  ExtensionWebUI::UnregisterChromeURLOverrides(profile_,
1465      extension->GetChromeURLOverrides());
1466
1467  ExtensionList::iterator iter = std::find(disabled_extensions_.begin(),
1468                                           disabled_extensions_.end(),
1469                                           extension.get());
1470  if (iter != disabled_extensions_.end()) {
1471    UnloadedExtensionInfo details(extension, reason);
1472    details.already_disabled = true;
1473    disabled_extensions_.erase(iter);
1474    NotificationService::current()->Notify(
1475        NotificationType::EXTENSION_UNLOADED,
1476        Source<Profile>(profile_),
1477        Details<UnloadedExtensionInfo>(&details));
1478    // Make sure the profile cleans up its RequestContexts when an already
1479    // disabled extension is unloaded (since they are also tracking the disabled
1480    // extensions).
1481    profile_->UnregisterExtensionWithRequestContexts(extension_id, reason);
1482    return;
1483  }
1484
1485  iter = std::find(extensions_.begin(), extensions_.end(), extension.get());
1486
1487  // Remove the extension from our list.
1488  extensions_.erase(iter);
1489
1490  NotifyExtensionUnloaded(extension.get(), reason);
1491  UpdateActiveExtensionsInCrashReporter();
1492}
1493
1494void ExtensionService::UnloadAllExtensions() {
1495  if (profile_) {
1496    profile_->GetExtensionSpecialStoragePolicy()->
1497        RevokeRightsForAllExtensions();
1498  }
1499  extensions_.clear();
1500  disabled_extensions_.clear();
1501  terminated_extension_ids_.clear();
1502  terminated_extensions_.clear();
1503  extension_runtime_data_.clear();
1504
1505  // TODO(erikkay) should there be a notification for this?  We can't use
1506  // EXTENSION_UNLOADED since that implies that the extension has been disabled
1507  // or uninstalled, and UnloadAll is just part of shutdown.
1508}
1509
1510void ExtensionService::ReloadExtensions() {
1511  UnloadAllExtensions();
1512  LoadAllExtensions();
1513}
1514
1515void ExtensionService::GarbageCollectExtensions() {
1516  if (extension_prefs_->pref_service()->ReadOnly())
1517    return;
1518
1519  scoped_ptr<ExtensionPrefs::ExtensionsInfo> info(
1520      extension_prefs_->GetInstalledExtensionsInfo());
1521
1522  std::map<std::string, FilePath> extension_paths;
1523  for (size_t i = 0; i < info->size(); ++i)
1524    extension_paths[info->at(i)->extension_id] = info->at(i)->extension_path;
1525
1526  BrowserThread::PostTask(
1527      BrowserThread::FILE, FROM_HERE,
1528      NewRunnableFunction(
1529          &extension_file_util::GarbageCollectExtensions, install_directory_,
1530          extension_paths));
1531
1532  // Also garbage-collect themes.  We check |profile_| to be
1533  // defensive; in the future, we may call GarbageCollectExtensions()
1534  // from somewhere other than Init() (e.g., in a timer).
1535  if (profile_) {
1536    ThemeServiceFactory::GetForProfile(profile_)->RemoveUnusedThemes();
1537  }
1538}
1539
1540void ExtensionService::OnLoadedInstalledExtensions() {
1541  if (updater_.get()) {
1542    updater_->Start();
1543  }
1544
1545  ready_ = true;
1546  NotificationService::current()->Notify(
1547      NotificationType::EXTENSIONS_READY,
1548      Source<Profile>(profile_),
1549      NotificationService::NoDetails());
1550}
1551
1552void ExtensionService::AddExtension(const Extension* extension) {
1553  // Ensure extension is deleted unless we transfer ownership.
1554  scoped_refptr<const Extension> scoped_extension(extension);
1555
1556  // The extension is now loaded, remove its data from unloaded extension map.
1557  unloaded_extension_paths_.erase(extension->id());
1558
1559  // If a terminated extension is loaded, remove it from the terminated list.
1560  UntrackTerminatedExtension(extension->id());
1561
1562  // If the extension was disabled for a reload, then enable it.
1563  if (disabled_extension_paths_.erase(extension->id()) > 0)
1564    EnableExtension(extension->id());
1565
1566  // TODO(jstritar): We may be able to get rid of this branch by overriding the
1567  // default extension state to DISABLED when the --disable-extensions flag
1568  // is set (http://crbug.com/29067).
1569  if (!extensions_enabled() &&
1570      !extension->is_theme() &&
1571      extension->location() != Extension::COMPONENT &&
1572      !Extension::IsExternalLocation(extension->location()))
1573    return;
1574
1575  // Check if the extension's privileges have changed and disable the
1576  // extension if necessary.
1577  DisableIfPrivilegeIncrease(extension);
1578
1579  switch (extension_prefs_->GetExtensionState(extension->id())) {
1580    case Extension::ENABLED:
1581      extensions_.push_back(scoped_extension);
1582
1583      NotifyExtensionLoaded(extension);
1584
1585      ExtensionWebUI::RegisterChromeURLOverrides(
1586          profile_, extension->GetChromeURLOverrides());
1587      break;
1588    case Extension::DISABLED:
1589      disabled_extensions_.push_back(scoped_extension);
1590      NotificationService::current()->Notify(
1591          NotificationType::EXTENSION_UPDATE_DISABLED,
1592          Source<Profile>(profile_),
1593          Details<const Extension>(extension));
1594      break;
1595    default:
1596      NOTREACHED();
1597      break;
1598  }
1599
1600  SetBeingUpgraded(extension, false);
1601
1602  UpdateActiveExtensionsInCrashReporter();
1603
1604  if (profile_->GetTemplateURLModel())
1605    profile_->GetTemplateURLModel()->RegisterExtensionKeyword(extension);
1606
1607  // Load the icon for omnibox-enabled extensions so it will be ready to display
1608  // in the URL bar.
1609  if (!extension->omnibox_keyword().empty()) {
1610    omnibox_popup_icon_manager_.LoadIcon(extension);
1611    omnibox_icon_manager_.LoadIcon(extension);
1612  }
1613}
1614
1615void ExtensionService::DisableIfPrivilegeIncrease(const Extension* extension) {
1616  // We keep track of all permissions the user has granted each extension.
1617  // This allows extensions to gracefully support backwards compatibility
1618  // by including unknown permissions in their manifests. When the user
1619  // installs the extension, only the recognized permissions are recorded.
1620  // When the unknown permissions become recognized (e.g., through browser
1621  // upgrade), we can prompt the user to accept these new permissions.
1622  // Extensions can also silently upgrade to less permissions, and then
1623  // silently upgrade to a version that adds these permissions back.
1624  //
1625  // For example, pretend that Chrome 10 includes a permission "omnibox"
1626  // for an API that adds suggestions to the omnibox. An extension can
1627  // maintain backwards compatibility while still having "omnibox" in the
1628  // manifest. If a user installs the extension on Chrome 9, the browser
1629  // will record the permissions it recognized, not including "omnibox."
1630  // When upgrading to Chrome 10, "omnibox" will be recognized and Chrome
1631  // will disable the extension and prompt the user to approve the increase
1632  // in privileges. The extension could then release a new version that
1633  // removes the "omnibox" permission. When the user upgrades, Chrome will
1634  // still remember that "omnibox" had been granted, so that if the
1635  // extension once again includes "omnibox" in an upgrade, the extension
1636  // can upgrade without requiring this user's approval.
1637  const Extension* old = GetExtensionByIdInternal(extension->id(),
1638                                                  true, true);
1639  bool granted_full_access;
1640  std::set<std::string> granted_apis;
1641  ExtensionExtent granted_extent;
1642
1643  bool is_extension_upgrade = old != NULL;
1644  bool is_privilege_increase = false;
1645
1646  // We only record the granted permissions for INTERNAL extensions, since
1647  // they can't silently increase privileges.
1648  if (extension->location() == Extension::INTERNAL) {
1649    // Add all the recognized permissions if the granted permissions list
1650    // hasn't been initialized yet.
1651    if (!extension_prefs_->GetGrantedPermissions(extension->id(),
1652                                                 &granted_full_access,
1653                                                 &granted_apis,
1654                                                 &granted_extent)) {
1655      GrantPermissions(extension);
1656      CHECK(extension_prefs_->GetGrantedPermissions(extension->id(),
1657                                                    &granted_full_access,
1658                                                    &granted_apis,
1659                                                    &granted_extent));
1660    }
1661
1662    // Here, we check if an extension's privileges have increased in a manner
1663    // that requires the user's approval. This could occur because the browser
1664    // upgraded and recognized additional privileges, or an extension upgrades
1665    // to a version that requires additional privileges.
1666    is_privilege_increase = Extension::IsPrivilegeIncrease(
1667        granted_full_access, granted_apis, granted_extent, extension);
1668  }
1669
1670  if (is_extension_upgrade) {
1671    // Other than for unpacked extensions, CrxInstaller should have guaranteed
1672    // that we aren't downgrading.
1673    if (extension->location() != Extension::LOAD)
1674      CHECK(extension->version()->CompareTo(*(old->version())) >= 0);
1675
1676    // Extensions get upgraded if the privileges are allowed to increase or
1677    // the privileges haven't increased.
1678    if (!is_privilege_increase) {
1679      SetBeingUpgraded(old, true);
1680      SetBeingUpgraded(extension, true);
1681    }
1682
1683    // To upgrade an extension in place, unload the old one and
1684    // then load the new one.
1685    UnloadExtension(old->id(), UnloadedExtensionInfo::UPDATE);
1686    old = NULL;
1687  }
1688
1689  // Extension has changed permissions significantly. Disable it. A
1690  // notification should be sent by the caller.
1691  if (is_privilege_increase) {
1692    if (!extension_prefs_->DidExtensionEscalatePermissions(extension->id())) {
1693      RecordPermissionMessagesHistogram(
1694          extension, "Extensions.Permissions_AutoDisable");
1695    }
1696    extension_prefs_->SetExtensionState(extension, Extension::DISABLED);
1697    extension_prefs_->SetDidExtensionEscalatePermissions(extension, true);
1698  }
1699}
1700
1701void ExtensionService::UpdateActiveExtensionsInCrashReporter() {
1702  std::set<std::string> extension_ids;
1703  for (size_t i = 0; i < extensions_.size(); ++i) {
1704    if (!extensions_[i]->is_theme() &&
1705        extensions_[i]->location() != Extension::COMPONENT)
1706      extension_ids.insert(extensions_[i]->id());
1707  }
1708
1709  child_process_logging::SetActiveExtensions(extension_ids);
1710}
1711
1712void ExtensionService::OnExtensionInstalled(const Extension* extension) {
1713  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1714
1715  // Ensure extension is deleted unless we transfer ownership.
1716  scoped_refptr<const Extension> scoped_extension(extension);
1717  const std::string& id = extension->id();
1718  bool initial_enable = false;
1719  bool initial_enable_incognito = false;
1720
1721  PendingExtensionInfo pending_extension_info;
1722  if (pending_extension_manager()->GetById(id, &pending_extension_info)) {
1723    pending_extension_manager()->Remove(id);
1724
1725    if (!pending_extension_info.ShouldAllowInstall(*extension)) {
1726      LOG(WARNING)
1727          << "ShouldAllowInstall() returned false for "
1728          << id << " of type " << extension->GetType()
1729          << " and update URL " << extension->update_url().spec()
1730          << "; not installing";
1731
1732      NotificationService::current()->Notify(
1733          NotificationType::EXTENSION_INSTALL_NOT_ALLOWED,
1734          Source<Profile>(profile_),
1735          Details<const Extension>(extension));
1736
1737      // Delete the extension directory since we're not going to
1738      // load it.
1739      BrowserThread::PostTask(
1740          BrowserThread::FILE, FROM_HERE,
1741          NewRunnableFunction(&extension_file_util::DeleteFile,
1742                              extension->path(), true));
1743      return;
1744    }
1745
1746    if (extension->is_theme()) {
1747      DCHECK(pending_extension_info.enable_on_install());
1748      initial_enable = true;
1749      DCHECK(!pending_extension_info.enable_incognito_on_install());
1750      initial_enable_incognito = false;
1751    } else {
1752      initial_enable = pending_extension_info.enable_on_install();
1753      initial_enable_incognito =
1754          pending_extension_info.enable_incognito_on_install();
1755    }
1756  } else {
1757    // We explicitly want to re-enable an uninstalled external
1758    // extension; if we're here, that means the user is manually
1759    // installing the extension.
1760    initial_enable =
1761        IsExtensionEnabled(id) || IsExternalExtensionUninstalled(id);
1762    initial_enable_incognito = IsIncognitoEnabled(id);
1763  }
1764
1765  UMA_HISTOGRAM_ENUMERATION("Extensions.InstallType",
1766                            extension->GetType(), 100);
1767  RecordPermissionMessagesHistogram(
1768      extension, "Extensions.Permissions_Install");
1769  ShownSectionsHandler::OnExtensionInstalled(profile_->GetPrefs(), extension);
1770  extension_prefs_->OnExtensionInstalled(
1771      extension, initial_enable ? Extension::ENABLED : Extension::DISABLED,
1772      initial_enable_incognito);
1773
1774  // Unpacked extensions default to allowing file access, but if that has been
1775  // overridden, don't reset the value.
1776  if (Extension::ShouldAlwaysAllowFileAccess(Extension::LOAD) &&
1777      !extension_prefs_->HasAllowFileAccessSetting(id)) {
1778    extension_prefs_->SetAllowFileAccess(id, true);
1779  }
1780
1781  NotificationService::current()->Notify(
1782      NotificationType::EXTENSION_INSTALLED,
1783      Source<Profile>(profile_),
1784      Details<const Extension>(extension));
1785
1786  // Transfer ownership of |extension| to AddExtension.
1787  AddExtension(scoped_extension);
1788}
1789
1790const Extension* ExtensionService::GetExtensionByIdInternal(
1791    const std::string& id, bool include_enabled, bool include_disabled) const {
1792  std::string lowercase_id = StringToLowerASCII(id);
1793  if (include_enabled) {
1794    for (ExtensionList::const_iterator iter = extensions_.begin();
1795        iter != extensions_.end(); ++iter) {
1796      if ((*iter)->id() == lowercase_id)
1797        return *iter;
1798    }
1799  }
1800  if (include_disabled) {
1801    for (ExtensionList::const_iterator iter = disabled_extensions_.begin();
1802        iter != disabled_extensions_.end(); ++iter) {
1803      if ((*iter)->id() == lowercase_id)
1804        return *iter;
1805    }
1806  }
1807  return NULL;
1808}
1809
1810void ExtensionService::TrackTerminatedExtension(const Extension* extension) {
1811  if (terminated_extension_ids_.insert(extension->id()).second)
1812    terminated_extensions_.push_back(make_scoped_refptr(extension));
1813}
1814
1815void ExtensionService::UntrackTerminatedExtension(const std::string& id) {
1816  if (terminated_extension_ids_.erase(id) <= 0)
1817    return;
1818
1819  std::string lowercase_id = StringToLowerASCII(id);
1820  for (ExtensionList::iterator iter = terminated_extensions_.begin();
1821       iter != terminated_extensions_.end(); ++iter) {
1822    if ((*iter)->id() == lowercase_id) {
1823      terminated_extensions_.erase(iter);
1824      return;
1825    }
1826  }
1827}
1828
1829const Extension* ExtensionService::GetTerminatedExtension(
1830    const std::string& id) {
1831  std::string lowercase_id = StringToLowerASCII(id);
1832  for (ExtensionList::const_iterator iter = terminated_extensions_.begin();
1833       iter != terminated_extensions_.end(); ++iter) {
1834    if ((*iter)->id() == lowercase_id)
1835      return *iter;
1836  }
1837  return NULL;
1838}
1839
1840const Extension* ExtensionService::GetWebStoreApp() {
1841  return GetExtensionById(extension_misc::kWebStoreAppId, false);
1842}
1843
1844const Extension* ExtensionService::GetExtensionByURL(const GURL& url) {
1845  return url.scheme() != chrome::kExtensionScheme ? NULL :
1846      GetExtensionById(url.host(), false);
1847}
1848
1849const Extension* ExtensionService::GetExtensionByWebExtent(const GURL& url) {
1850  for (size_t i = 0; i < extensions_.size(); ++i) {
1851    if (extensions_[i]->web_extent().ContainsURL(url))
1852      return extensions_[i];
1853  }
1854  return NULL;
1855}
1856
1857bool ExtensionService::ExtensionBindingsAllowed(const GURL& url) {
1858  // Allow bindings for all packaged extension.
1859  if (GetExtensionByURL(url))
1860    return true;
1861
1862  // Allow bindings for all component, hosted apps.
1863  const Extension* extension = GetExtensionByWebExtent(url);
1864  return (extension && extension->location() == Extension::COMPONENT);
1865}
1866
1867const Extension* ExtensionService::GetExtensionByOverlappingWebExtent(
1868    const ExtensionExtent& extent) {
1869  for (size_t i = 0; i < extensions_.size(); ++i) {
1870    if (extensions_[i]->web_extent().OverlapsWith(extent))
1871      return extensions_[i];
1872  }
1873
1874  return NULL;
1875}
1876
1877const SkBitmap& ExtensionService::GetOmniboxIcon(
1878    const std::string& extension_id) {
1879  return omnibox_icon_manager_.GetIcon(extension_id);
1880}
1881
1882const SkBitmap& ExtensionService::GetOmniboxPopupIcon(
1883    const std::string& extension_id) {
1884  return omnibox_popup_icon_manager_.GetIcon(extension_id);
1885}
1886
1887void ExtensionService::OnExternalExtensionFileFound(
1888         const std::string& id,
1889         const Version* version,
1890         const FilePath& path,
1891         Extension::Location location) {
1892  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1893  CHECK(Extension::IdIsValid(id));
1894  if (extension_prefs_->IsExternalExtensionUninstalled(id))
1895    return;
1896
1897  DCHECK(version);
1898
1899  // Before even bothering to unpack, check and see if we already have this
1900  // version. This is important because these extensions are going to get
1901  // installed on every startup.
1902  const Extension* existing = GetExtensionById(id, true);
1903  if (existing) {
1904    switch (existing->version()->CompareTo(*version)) {
1905      case -1:  // existing version is older, we should upgrade
1906        break;
1907      case 0:  // existing version is same, do nothing
1908        return;
1909      case 1:  // existing version is newer, uh-oh
1910        LOG(WARNING) << "Found external version of extension " << id
1911                     << "that is older than current version. Current version "
1912                     << "is: " << existing->VersionString() << ". New version "
1913                     << "is: " << version << ". Keeping current version.";
1914        return;
1915    }
1916  }
1917
1918  pending_extension_manager()->AddFromExternalFile(id, location);
1919
1920  scoped_refptr<CrxInstaller> installer(
1921      new CrxInstaller(this,  // frontend
1922                       NULL));  // no client (silent install)
1923  installer->set_install_source(location);
1924  installer->set_expected_id(id);
1925  installer->set_expected_version(*version),
1926  installer->InstallCrx(path);
1927}
1928
1929void ExtensionService::ReportExtensionLoadError(
1930    const FilePath& extension_path,
1931    const std::string &error,
1932    NotificationType type,
1933    bool be_noisy) {
1934  NotificationService* service = NotificationService::current();
1935  service->Notify(type,
1936                  Source<Profile>(profile_),
1937                  Details<const std::string>(&error));
1938
1939  std::string path_str = UTF16ToUTF8(extension_path.LossyDisplayName());
1940  std::string message = base::StringPrintf(
1941      "Could not load extension from '%s'. %s",
1942      path_str.c_str(), error.c_str());
1943  ExtensionErrorReporter::GetInstance()->ReportError(message, be_noisy);
1944}
1945
1946void ExtensionService::DidCreateRenderViewForBackgroundPage(
1947    ExtensionHost* host) {
1948  OrphanedDevTools::iterator iter =
1949      orphaned_dev_tools_.find(host->extension_id());
1950  if (iter == orphaned_dev_tools_.end())
1951    return;
1952
1953  DevToolsManager::GetInstance()->AttachClientHost(
1954      iter->second, host->render_view_host());
1955  orphaned_dev_tools_.erase(iter);
1956}
1957
1958void ExtensionService::Observe(NotificationType type,
1959                                const NotificationSource& source,
1960                                const NotificationDetails& details) {
1961  switch (type.value) {
1962    case NotificationType::EXTENSION_PROCESS_TERMINATED: {
1963      if (profile_ != Source<Profile>(source).ptr()->GetOriginalProfile())
1964        break;
1965
1966      ExtensionHost* host = Details<ExtensionHost>(details).ptr();
1967      TrackTerminatedExtension(host->extension());
1968
1969      // Unload the entire extension. We want it to be in a consistent state:
1970      // either fully working or not loaded at all, but never half-crashed.
1971      // We do it in a PostTask so that other handlers of this notification will
1972      // still have access to the Extension and ExtensionHost.
1973      MessageLoop::current()->PostTask(FROM_HERE,
1974          NewRunnableMethod(this,
1975                            &ExtensionService::UnloadExtension,
1976                            host->extension()->id(),
1977                            UnloadedExtensionInfo::DISABLE));
1978      break;
1979    }
1980
1981    case NotificationType::PREF_CHANGED: {
1982      std::string* pref_name = Details<std::string>(details).ptr();
1983      if (*pref_name == prefs::kExtensionInstallAllowList ||
1984          *pref_name == prefs::kExtensionInstallDenyList) {
1985        CheckAdminBlacklist();
1986      } else {
1987        NOTREACHED() << "Unexpected preference name.";
1988      }
1989      break;
1990    }
1991
1992    default:
1993      NOTREACHED() << "Unexpected notification type.";
1994  }
1995}
1996
1997bool ExtensionService::HasApps() const {
1998  return !GetAppIds().empty();
1999}
2000
2001ExtensionIdSet ExtensionService::GetAppIds() const {
2002  ExtensionIdSet result;
2003  for (ExtensionList::const_iterator it = extensions_.begin();
2004       it != extensions_.end(); ++it) {
2005    if ((*it)->is_app() && (*it)->location() != Extension::COMPONENT)
2006      result.insert((*it)->id());
2007  }
2008
2009  return result;
2010}
2011
2012bool ExtensionService::IsBackgroundPageReady(const Extension* extension) {
2013  return (extension->background_url().is_empty() ||
2014          extension_runtime_data_[extension->id()].background_page_ready);
2015}
2016
2017void ExtensionService::SetBackgroundPageReady(const Extension* extension) {
2018  DCHECK(!extension->background_url().is_empty());
2019  extension_runtime_data_[extension->id()].background_page_ready = true;
2020  NotificationService::current()->Notify(
2021      NotificationType::EXTENSION_BACKGROUND_PAGE_READY,
2022      Source<const Extension>(extension),
2023      NotificationService::NoDetails());
2024}
2025
2026bool ExtensionService::IsBeingUpgraded(const Extension* extension) {
2027  return extension_runtime_data_[extension->id()].being_upgraded;
2028}
2029
2030void ExtensionService::SetBeingUpgraded(const Extension* extension,
2031                                         bool value) {
2032  extension_runtime_data_[extension->id()].being_upgraded = value;
2033}
2034
2035PropertyBag* ExtensionService::GetPropertyBag(const Extension* extension) {
2036  return &extension_runtime_data_[extension->id()].property_bag;
2037}
2038
2039void ExtensionService::RegisterNaClModule(const GURL& url,
2040                                          const std::string& mime_type) {
2041  NaClModuleInfo info;
2042  info.url = url;
2043  info.mime_type = mime_type;
2044
2045  DCHECK(FindNaClModule(url) == nacl_module_list_.end());
2046  nacl_module_list_.push_front(info);
2047}
2048
2049void ExtensionService::UnregisterNaClModule(const GURL& url) {
2050  NaClModuleInfoList::iterator iter = FindNaClModule(url);
2051  DCHECK(iter != nacl_module_list_.end());
2052  nacl_module_list_.erase(iter);
2053}
2054
2055void ExtensionService::UpdatePluginListWithNaClModules() {
2056  FilePath path;
2057  PathService::Get(chrome::FILE_NACL_PLUGIN, &path);
2058
2059  webkit::npapi::PluginList::Singleton()->UnregisterInternalPlugin(path);
2060
2061  const PepperPluginInfo* pepper_info =
2062      PepperPluginRegistry::GetInstance()->GetInfoForPlugin(path);
2063  webkit::npapi::WebPluginInfo info = pepper_info->ToWebPluginInfo();
2064
2065  DCHECK(nacl_module_list_.size() <= 1);
2066  for (NaClModuleInfoList::iterator iter = nacl_module_list_.begin();
2067       iter != nacl_module_list_.end(); ++iter) {
2068    webkit::npapi::WebPluginMimeType mime_type_info;
2069    mime_type_info.mime_type = iter->mime_type;
2070    mime_type_info.additional_param_names.push_back(UTF8ToUTF16("nacl"));
2071    mime_type_info.additional_param_values.push_back(
2072        UTF8ToUTF16(iter->url.spec()));
2073    info.mime_types.push_back(mime_type_info);
2074  }
2075
2076  webkit::npapi::PluginList::Singleton()->RefreshPlugins();
2077  webkit::npapi::PluginList::Singleton()->RegisterInternalPlugin(info);
2078}
2079
2080ExtensionService::NaClModuleInfoList::iterator
2081    ExtensionService::FindNaClModule(const GURL& url) {
2082  for (NaClModuleInfoList::iterator iter = nacl_module_list_.begin();
2083       iter != nacl_module_list_.end(); ++iter) {
2084    if (iter->url == url)
2085      return iter;
2086  }
2087  return nacl_module_list_.end();
2088}
2089