extension_service.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
1// Copyright (c) 2013 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 <iterator>
9#include <set>
10
11#include "base/basictypes.h"
12#include "base/bind.h"
13#include "base/callback.h"
14#include "base/command_line.h"
15#include "base/file_util.h"
16#include "base/logging.h"
17#include "base/metrics/histogram.h"
18#include "base/path_service.h"
19#include "base/prefs/pref_service.h"
20#include "base/stl_util.h"
21#include "base/string_util.h"
22#include "base/stringprintf.h"
23#include "base/strings/string_number_conversions.h"
24#include "base/threading/sequenced_worker_pool.h"
25#include "base/threading/thread_restrictions.h"
26#include "base/time.h"
27#include "base/utf_string_conversions.h"
28#include "base/values.h"
29#include "base/version.h"
30#include "chrome/browser/app_mode/app_mode_utils.h"
31#include "chrome/browser/browser_process.h"
32#include "chrome/browser/devtools/devtools_window.h"
33#include "chrome/browser/extensions/api/app_runtime/app_runtime_api.h"
34#include "chrome/browser/extensions/api/declarative/rules_registry_service.h"
35#include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
36#include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
37#include "chrome/browser/extensions/api/runtime/runtime_api.h"
38#include "chrome/browser/extensions/api/storage/settings_frontend.h"
39#include "chrome/browser/extensions/app_sync_data.h"
40#include "chrome/browser/extensions/browser_event_router.h"
41#include "chrome/browser/extensions/component_loader.h"
42#include "chrome/browser/extensions/crx_installer.h"
43#include "chrome/browser/extensions/data_deleter.h"
44#include "chrome/browser/extensions/extension_disabled_ui.h"
45#include "chrome/browser/extensions/extension_error_reporter.h"
46#include "chrome/browser/extensions/extension_error_ui.h"
47#include "chrome/browser/extensions/extension_host.h"
48#include "chrome/browser/extensions/extension_install_ui.h"
49#include "chrome/browser/extensions/extension_process_manager.h"
50#include "chrome/browser/extensions/extension_sorting.h"
51#include "chrome/browser/extensions/extension_special_storage_policy.h"
52#include "chrome/browser/extensions/extension_sync_data.h"
53#include "chrome/browser/extensions/extension_system.h"
54#include "chrome/browser/extensions/external_install_ui.h"
55#include "chrome/browser/extensions/external_provider_impl.h"
56#include "chrome/browser/extensions/external_provider_interface.h"
57#include "chrome/browser/extensions/installed_loader.h"
58#include "chrome/browser/extensions/lazy_background_task_queue.h"
59#include "chrome/browser/extensions/management_policy.h"
60#include "chrome/browser/extensions/pending_extension_manager.h"
61#include "chrome/browser/extensions/permissions_updater.h"
62#include "chrome/browser/extensions/platform_app_launcher.h"
63#include "chrome/browser/extensions/shell_window_registry.h"
64#include "chrome/browser/extensions/unpacked_installer.h"
65#include "chrome/browser/extensions/update_observer.h"
66#include "chrome/browser/extensions/updater/extension_updater.h"
67#include "chrome/browser/plugins/chrome_plugin_service_filter.h"
68#include "chrome/browser/profiles/profile.h"
69#include "chrome/browser/profiles/profile_manager.h"
70#include "chrome/browser/themes/theme_service.h"
71#include "chrome/browser/themes/theme_service_factory.h"
72#include "chrome/browser/ui/webui/favicon_source.h"
73#include "chrome/browser/ui/webui/ntp/thumbnail_source.h"
74#include "chrome/browser/ui/webui/theme_source.h"
75#include "chrome/common/child_process_logging.h"
76#include "chrome/common/chrome_notification_types.h"
77#include "chrome/common/chrome_paths.h"
78#include "chrome/common/chrome_switches.h"
79#include "chrome/common/chrome_version_info.h"
80#include "chrome/common/extensions/api/plugins/plugins_handler.h"
81#include "chrome/common/extensions/background_info.h"
82#include "chrome/common/extensions/extension.h"
83#include "chrome/common/extensions/extension_file_util.h"
84#include "chrome/common/extensions/extension_manifest_constants.h"
85#include "chrome/common/extensions/extension_messages.h"
86#include "chrome/common/extensions/feature_switch.h"
87#include "chrome/common/extensions/features/feature.h"
88#include "chrome/common/extensions/incognito_handler.h"
89#include "chrome/common/extensions/manifest.h"
90#include "chrome/common/extensions/manifest_handlers/app_isolation_info.h"
91#include "chrome/common/extensions/manifest_url_handler.h"
92#include "chrome/common/extensions/permissions/permissions_data.h"
93#include "chrome/common/pref_names.h"
94#include "chrome/common/startup_metric_utils.h"
95#include "chrome/common/url_constants.h"
96#include "content/public/browser/browser_thread.h"
97#include "content/public/browser/devtools_agent_host.h"
98#include "content/public/browser/notification_service.h"
99#include "content/public/browser/notification_types.h"
100#include "content/public/browser/plugin_service.h"
101#include "content/public/browser/render_process_host.h"
102#include "content/public/browser/site_instance.h"
103#include "content/public/browser/storage_partition.h"
104#include "content/public/browser/url_data_source.h"
105#include "content/public/common/pepper_plugin_info.h"
106#include "extensions/common/constants.h"
107#include "extensions/common/error_utils.h"
108#include "googleurl/src/gurl.h"
109#include "grit/generated_resources.h"
110#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
111#include "sync/api/sync_change.h"
112#include "sync/api/sync_error_factory.h"
113#include "webkit/browser/database/database_tracker.h"
114#include "webkit/browser/database/database_util.h"
115
116#if defined(OS_CHROMEOS)
117#include "chrome/browser/chromeos/extensions/install_limiter.h"
118#include "webkit/browser/fileapi/file_system_context.h"
119#include "webkit/browser/fileapi/file_system_mount_point_provider.h"
120#endif
121
122using content::BrowserContext;
123using content::BrowserThread;
124using content::DevToolsAgentHost;
125using content::PluginService;
126using extensions::CrxInstaller;
127using extensions::Extension;
128using extensions::ExtensionIdSet;
129using extensions::ExtensionInfo;
130using extensions::FeatureSwitch;
131using extensions::Manifest;
132using extensions::PermissionMessage;
133using extensions::PermissionMessages;
134using extensions::PermissionSet;
135using extensions::UnloadedExtensionInfo;
136
137namespace errors = extension_manifest_errors;
138
139namespace {
140
141// Histogram values for logging events related to externally installed
142// extensions.
143enum ExternalExtensionEvent {
144  EXTERNAL_EXTENSION_INSTALLED = 0,
145  EXTERNAL_EXTENSION_IGNORED,
146  EXTERNAL_EXTENSION_REENABLED,
147  EXTERNAL_EXTENSION_UNINSTALLED,
148  EXTERNAL_EXTENSION_BUCKET_BOUNDARY,
149};
150
151// Prompt the user this many times before considering an extension acknowledged.
152static const int kMaxExtensionAcknowledgePromptCount = 3;
153
154// Wait this many seconds after an extensions becomes idle before updating it.
155static const int kUpdateIdleDelay = 5;
156
157// Wait this many seconds before trying to garbage collect extensions again.
158static const int kGarbageCollectRetryDelay = 30;
159
160const char* kNaClPluginMimeType = "application/x-nacl";
161
162static bool IsSyncableExtension(const Extension& extension) {
163  return extension.GetSyncType() == Extension::SYNC_TYPE_EXTENSION;
164}
165
166static bool IsSyncableApp(const Extension& extension) {
167  return extension.GetSyncType() == Extension::SYNC_TYPE_APP;
168}
169
170}  // namespace
171
172ExtensionService::ExtensionRuntimeData::ExtensionRuntimeData()
173    : background_page_ready(false),
174      being_upgraded(false),
175      has_used_webrequest(false) {
176}
177
178ExtensionService::ExtensionRuntimeData::~ExtensionRuntimeData() {
179}
180
181ExtensionService::NaClModuleInfo::NaClModuleInfo() {
182}
183
184ExtensionService::NaClModuleInfo::~NaClModuleInfo() {
185}
186
187// ExtensionService.
188
189const char ExtensionService::kLocalAppSettingsDirectoryName[] =
190    "Local App Settings";
191const char ExtensionService::kLocalExtensionSettingsDirectoryName[] =
192    "Local Extension Settings";
193const char ExtensionService::kSyncAppSettingsDirectoryName[] =
194    "Sync App Settings";
195const char ExtensionService::kSyncExtensionSettingsDirectoryName[] =
196    "Sync Extension Settings";
197const char ExtensionService::kManagedSettingsDirectoryName[] =
198    "Managed Extension Settings";
199const char ExtensionService::kStateStoreName[] = "Extension State";
200const char ExtensionService::kRulesStoreName[] = "Extension Rules";
201
202void ExtensionService::CheckExternalUninstall(const std::string& id) {
203  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
204
205  // Check if the providers know about this extension.
206  extensions::ProviderCollection::const_iterator i;
207  for (i = external_extension_providers_.begin();
208       i != external_extension_providers_.end(); ++i) {
209    DCHECK(i->get()->IsReady());
210    if (i->get()->HasExtension(id))
211      return;  // Yup, known extension, don't uninstall.
212  }
213
214  // We get the list of external extensions to check from preferences.
215  // It is possible that an extension has preferences but is not loaded.
216  // For example, an extension that requires experimental permissions
217  // will not be loaded if the experimental command line flag is not used.
218  // In this case, do not uninstall.
219  if (!GetInstalledExtension(id)) {
220    // We can't call UninstallExtension with an unloaded/invalid
221    // extension ID.
222    LOG(WARNING) << "Attempted uninstallation of unloaded/invalid extension "
223                 << "with id: " << id;
224    return;
225  }
226  UninstallExtension(id, true, NULL);
227}
228
229void ExtensionService::SetFileTaskRunnerForTesting(
230    base::SequencedTaskRunner* task_runner) {
231  file_task_runner_ = task_runner;
232}
233
234void ExtensionService::ClearProvidersForTesting() {
235  external_extension_providers_.clear();
236}
237
238void ExtensionService::AddProviderForTesting(
239    extensions::ExternalProviderInterface* test_provider) {
240  CHECK(test_provider);
241  external_extension_providers_.push_back(
242      linked_ptr<extensions::ExternalProviderInterface>(test_provider));
243}
244
245bool ExtensionService::OnExternalExtensionUpdateUrlFound(
246    const std::string& id,
247    const GURL& update_url,
248    Manifest::Location location) {
249  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
250  CHECK(Extension::IdIsValid(id));
251
252  const Extension* extension = GetExtensionById(id, true);
253  if (extension) {
254    // Already installed. Skip this install if the current location has
255    // higher priority than |location|.
256    Manifest::Location current = extension->location();
257    if (current == Manifest::GetHigherPriorityLocation(current, location))
258      return false;
259    // Otherwise, overwrite the current installation.
260  }
261
262  // Add |id| to the set of pending extensions.  If it can not be added,
263  // then there is already a pending record from a higher-priority install
264  // source.  In this case, signal that this extension will not be
265  // installed by returning false.
266  if (!pending_extension_manager()->AddFromExternalUpdateUrl(
267          id, update_url, location)) {
268    return false;
269  }
270
271  update_once_all_providers_are_ready_ = true;
272  return true;
273}
274
275const Extension* ExtensionService::GetInstalledApp(const GURL& url) const {
276  const Extension* extension = extensions_.GetExtensionOrAppByURL(
277      ExtensionURLInfo(url));
278  return (extension && extension->is_app()) ? extension : NULL;
279}
280
281bool ExtensionService::IsInstalledApp(const GURL& url) const {
282  return !!GetInstalledApp(url);
283}
284
285const Extension* ExtensionService::GetIsolatedAppForRenderer(
286    int renderer_child_id) const {
287  std::set<std::string> extension_ids =
288      process_map_.GetExtensionsInProcess(renderer_child_id);
289  // All apps in one process share the same partition.
290  // It is only possible for the app to have isolated storage
291  // if there is only 1 app in the process.
292  if (extension_ids.size() != 1)
293    return NULL;
294
295  const extensions::Extension* extension =
296      extensions_.GetByID(*(extension_ids.begin()));
297  // We still need to check if the extension has isolated storage,
298  // because it's common for there to be one extension in a process
299  // without isolated storage.
300  if (extension &&
301      extensions::AppIsolationInfo::HasIsolatedStorage(extension))
302    return extension;
303
304  return NULL;
305}
306
307// static
308// This function is used to implement the command-line switch
309// --uninstall-extension, and to uninstall an extension via sync.  The LOG
310// statements within this function are used to inform the user if the uninstall
311// cannot be done.
312bool ExtensionService::UninstallExtensionHelper(
313    ExtensionService* extensions_service,
314    const std::string& extension_id) {
315  // We can't call UninstallExtension with an invalid extension ID.
316  if (!extensions_service->GetInstalledExtension(extension_id)) {
317    LOG(WARNING) << "Attempted uninstallation of non-existent extension with "
318                 << "id: " << extension_id;
319    return false;
320  }
321
322  // The following call to UninstallExtension will not allow an uninstall of a
323  // policy-controlled extension.
324  string16 error;
325  if (!extensions_service->UninstallExtension(extension_id, false, &error)) {
326    LOG(WARNING) << "Cannot uninstall extension with id " << extension_id
327                 << ": " << error;
328    return false;
329  }
330
331  return true;
332}
333
334ExtensionService::ExtensionService(Profile* profile,
335                                   const CommandLine* command_line,
336                                   const base::FilePath& install_directory,
337                                   extensions::ExtensionPrefs* extension_prefs,
338                                   extensions::Blacklist* blacklist,
339                                   bool autoupdate_enabled,
340                                   bool extensions_enabled,
341                                   extensions::OneShotEvent* ready)
342    : extensions::Blacklist::Observer(blacklist),
343      profile_(profile),
344      system_(extensions::ExtensionSystem::Get(profile)),
345      extension_prefs_(extension_prefs),
346      blacklist_(blacklist),
347      settings_frontend_(extensions::SettingsFrontend::Create(profile)),
348      pending_extension_manager_(*this),
349      install_directory_(install_directory),
350      extensions_enabled_(extensions_enabled),
351      show_extensions_prompts_(true),
352      install_updates_when_idle_(true),
353      ready_(ready),
354      toolbar_model_(this),
355      menu_manager_(profile),
356      event_routers_initialized_(false),
357      update_once_all_providers_are_ready_(false),
358      browser_terminating_(false),
359      installs_delayed_(false),
360      is_first_run_(false),
361      app_sync_bundle_(this),
362      extension_sync_bundle_(this) {
363  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
364
365  // Figure out if extension installation should be enabled.
366  if (command_line->HasSwitch(switches::kDisableExtensions) ||
367      profile->GetPrefs()->GetBoolean(prefs::kDisableExtensions)) {
368    extensions_enabled_ = false;
369  }
370
371  registrar_.Add(this, chrome::NOTIFICATION_APP_TERMINATING,
372                 content::NotificationService::AllBrowserContextsAndSources());
373  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED,
374                 content::NotificationService::AllBrowserContextsAndSources());
375  registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CREATED,
376                 content::NotificationService::AllBrowserContextsAndSources());
377  registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED,
378                 content::NotificationService::AllBrowserContextsAndSources());
379  registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED,
380                 content::NotificationService::AllBrowserContextsAndSources());
381  registrar_.Add(this, chrome::NOTIFICATION_UPGRADE_RECOMMENDED,
382                 content::NotificationService::AllBrowserContextsAndSources());
383  pref_change_registrar_.Init(profile->GetPrefs());
384  base::Closure callback =
385      base::Bind(&ExtensionService::OnExtensionInstallPrefChanged,
386                 base::Unretained(this));
387  pref_change_registrar_.Add(prefs::kExtensionInstallAllowList, callback);
388  pref_change_registrar_.Add(prefs::kExtensionInstallDenyList, callback);
389  pref_change_registrar_.Add(prefs::kExtensionAllowedTypes, callback);
390
391  // Set up the ExtensionUpdater
392  if (autoupdate_enabled) {
393    int update_frequency = kDefaultUpdateFrequencySeconds;
394    if (command_line->HasSwitch(switches::kExtensionsUpdateFrequency)) {
395      base::StringToInt(command_line->GetSwitchValueASCII(
396          switches::kExtensionsUpdateFrequency),
397          &update_frequency);
398    }
399    updater_.reset(new extensions::ExtensionUpdater(this,
400                                                    extension_prefs,
401                                                    profile->GetPrefs(),
402                                                    profile,
403                                                    blacklist,
404                                                    update_frequency));
405  }
406
407  component_loader_.reset(
408      new extensions::ComponentLoader(this,
409                                      profile->GetPrefs(),
410                                      g_browser_process->local_state()));
411
412  if (extensions_enabled_) {
413    extensions::ExternalProviderImpl::CreateExternalProviders(
414        this, profile_, &external_extension_providers_);
415  }
416
417  // Set this as the ExtensionService for extension sorting to ensure it
418  // cause syncs if required.
419  extension_prefs_->extension_sorting()->SetExtensionService(this);
420
421  is_first_run_ = !extension_prefs_->SetAlertSystemFirstRun();
422
423#if defined(ENABLE_EXTENSIONS)
424  extension_action_storage_manager_.reset(
425      new extensions::ExtensionActionStorageManager(profile_));
426#endif
427
428  // How long is the path to the Extensions directory?
429  UMA_HISTOGRAM_CUSTOM_COUNTS("Extensions.ExtensionRootPathLength",
430                              install_directory_.value().length(), 0, 500, 100);
431}
432
433const ExtensionSet* ExtensionService::extensions() const {
434  return &extensions_;
435}
436
437const ExtensionSet* ExtensionService::disabled_extensions() const {
438  return &disabled_extensions_;
439}
440
441const ExtensionSet* ExtensionService::terminated_extensions() const {
442  return &terminated_extensions_;
443}
444
445const ExtensionSet* ExtensionService::blacklisted_extensions() const {
446  return &blacklisted_extensions_;
447}
448
449scoped_ptr<const ExtensionSet>
450    ExtensionService::GenerateInstalledExtensionsSet() const {
451  scoped_ptr<ExtensionSet> installed_extensions(new ExtensionSet());
452  installed_extensions->InsertAll(extensions_);
453  installed_extensions->InsertAll(disabled_extensions_);
454  installed_extensions->InsertAll(terminated_extensions_);
455  installed_extensions->InsertAll(blacklisted_extensions_);
456  return installed_extensions.PassAs<const ExtensionSet>();
457}
458
459extensions::PendingExtensionManager*
460    ExtensionService::pending_extension_manager() {
461  return &pending_extension_manager_;
462}
463
464ExtensionService::~ExtensionService() {
465  // No need to unload extensions here because they are profile-scoped, and the
466  // profile is in the process of being deleted.
467
468  extensions::ProviderCollection::const_iterator i;
469  for (i = external_extension_providers_.begin();
470       i != external_extension_providers_.end(); ++i) {
471    extensions::ExternalProviderInterface* provider = i->get();
472    provider->ServiceShutdown();
473  }
474}
475
476void ExtensionService::InitEventRoutersAfterImport() {
477  RegisterForImportFinished();
478}
479
480void ExtensionService::RegisterForImportFinished() {
481  if (!registrar_.IsRegistered(this, chrome::NOTIFICATION_IMPORT_FINISHED,
482                               content::Source<Profile>(profile_))) {
483    registrar_.Add(this, chrome::NOTIFICATION_IMPORT_FINISHED,
484                   content::Source<Profile>(profile_));
485  }
486}
487
488void ExtensionService::InitAfterImport() {
489  startup_metric_utils::ScopedSlowStartupUMA
490      scoped_timer("Startup.SlowStartupExtensionServiceInitAfterImport");
491  component_loader_->LoadAll();
492
493  CheckForExternalUpdates();
494
495  GarbageCollectExtensions();
496
497  // Idempotent, so although there is a possible race if the import
498  // process finished sometime in the middle of ProfileImpl::InitExtensions,
499  // it cannot happen twice.
500  InitEventRouters();
501}
502
503void ExtensionService::InitEventRouters() {
504  if (event_routers_initialized_)
505    return;
506
507#if defined(ENABLE_EXTENSIONS)
508  browser_event_router_.reset(new extensions::BrowserEventRouter(profile_));
509#endif  // defined(ENABLE_EXTENSIONS)
510  event_routers_initialized_ = true;
511}
512
513void ExtensionService::Shutdown() {
514  // Do nothing for now.
515}
516
517const Extension* ExtensionService::GetExtensionById(
518    const std::string& id, bool include_disabled) const {
519  int include_mask = INCLUDE_ENABLED;
520  if (include_disabled) {
521    // Include blacklisted extensions here because there are hundreds of
522    // callers of this function, and many might assume that this includes those
523    // that have been disabled due to blacklisting.
524    include_mask |= INCLUDE_DISABLED | INCLUDE_BLACKLISTED;
525  }
526  return GetExtensionById(id, include_mask);
527}
528
529GURL ExtensionService::GetSiteForExtensionId(const std::string& extension_id) {
530  return content::SiteInstance::GetSiteForURL(
531      profile_,
532      Extension::GetBaseURLFromExtensionId(extension_id));
533}
534
535const Extension* ExtensionService::GetExtensionById(
536    const std::string& id, int include_mask) const {
537  std::string lowercase_id = StringToLowerASCII(id);
538  if (include_mask & INCLUDE_ENABLED) {
539    const Extension* extension = extensions_.GetByID(lowercase_id);
540    if (extension)
541      return extension;
542  }
543  if (include_mask & INCLUDE_DISABLED) {
544    const Extension* extension = disabled_extensions_.GetByID(lowercase_id);
545    if (extension)
546      return extension;
547  }
548  if (include_mask & INCLUDE_TERMINATED) {
549    const Extension* extension = terminated_extensions_.GetByID(lowercase_id);
550    if (extension)
551      return extension;
552  }
553  if (include_mask & INCLUDE_BLACKLISTED) {
554    const Extension* extension = blacklisted_extensions_.GetByID(lowercase_id);
555    if (extension)
556      return extension;
557  }
558  return NULL;
559}
560
561void ExtensionService::Init() {
562  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
563
564  DCHECK(!is_ready());  // Can't redo init.
565  DCHECK_EQ(extensions_.size(), 0u);
566
567  const CommandLine* cmd_line = CommandLine::ForCurrentProcess();
568  if (cmd_line->HasSwitch(switches::kInstallFromWebstore) ||
569      cmd_line->HasSwitch(switches::kLimitedInstallFromWebstore)) {
570    // The sole purpose of this launch is to install a new extension from CWS
571    // and immediately terminate: loading already installed extensions is
572    // unnecessary and may interfere with the inline install dialog (e.g. if an
573    // extension listens to onStartup and opens a window).
574    SetReadyAndNotifyListeners();
575  } else {
576    // TODO(mek): It might be cleaner to do the FinishDelayedInstallInfo stuff
577    // here instead of in installedloader.
578    if (g_browser_process->profile_manager() &&
579        g_browser_process->profile_manager()->will_import()) {
580      // Do not load any component extensions, since they may conflict with the
581      // import process.
582
583      extensions::InstalledLoader(this).LoadAllExtensions();
584      SetReadyAndNotifyListeners();
585      RegisterForImportFinished();
586    } else {
587      // In this case, LoadAllExtensions() calls OnLoadedInstalledExtensions().
588      component_loader_->LoadAll();
589      extensions::InstalledLoader(this).LoadAllExtensions();
590      SetReadyAndNotifyListeners();
591
592      // TODO(erikkay) this should probably be deferred to a future point
593      // rather than running immediately at startup.
594      CheckForExternalUpdates();
595
596      // TODO(erikkay) this should probably be deferred as well.
597      GarbageCollectExtensions();
598    }
599
600    if (extension_prefs_->NeedsStorageGarbageCollection()) {
601      GarbageCollectIsolatedStorage();
602      extension_prefs_->SetNeedsStorageGarbageCollection(false);
603    }
604  }
605}
606
607bool ExtensionService::UpdateExtension(const std::string& id,
608                                       const base::FilePath& extension_path,
609                                       const GURL& download_url,
610                                       CrxInstaller** out_crx_installer) {
611  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
612  if (browser_terminating_) {
613    LOG(WARNING) << "Skipping UpdateExtension due to browser shutdown";
614    // Leak the temp file at extension_path. We don't want to add to the disk
615    // I/O burden at shutdown, we can't rely on the I/O completing anyway, and
616    // the file is in the OS temp directory which should be cleaned up for us.
617    return false;
618  }
619
620  const extensions::PendingExtensionInfo* pending_extension_info =
621      pending_extension_manager()->GetById(id);
622
623  const Extension* extension = GetInstalledExtension(id);
624  if (!pending_extension_info && !extension) {
625    LOG(WARNING) << "Will not update extension " << id
626                 << " because it is not installed or pending";
627    // Delete extension_path since we're not creating a CrxInstaller
628    // that would do it for us.
629    if (!GetFileTaskRunner()->PostTask(
630            FROM_HERE,
631            base::Bind(
632                &extension_file_util::DeleteFile, extension_path, false)))
633      NOTREACHED();
634
635    return false;
636  }
637
638  // We want a silent install only for non-pending extensions and
639  // pending extensions that have install_silently set.
640  ExtensionInstallPrompt* client = NULL;
641  if (pending_extension_info && !pending_extension_info->install_silently())
642    client = ExtensionInstallUI::CreateInstallPromptWithProfile(profile_);
643
644  scoped_refptr<CrxInstaller> installer(CrxInstaller::Create(this, client));
645  installer->set_expected_id(id);
646  if (pending_extension_info) {
647    installer->set_install_source(pending_extension_info->install_source());
648    if (pending_extension_info->install_silently())
649      installer->set_allow_silent_install(true);
650  } else if (extension) {
651    installer->set_install_source(extension->location());
652  }
653  // If the extension was installed from or has migrated to the webstore, or
654  // its auto-update URL is from the webstore, treat it as a webstore install.
655  // Note that we ignore some older extensions with blank auto-update URLs
656  // because we are mostly concerned with restrictions on NaCl extensions,
657  // which are newer.
658  int creation_flags = Extension::NO_FLAGS;
659  if ((extension && extension->from_webstore()) ||
660      (extension && extension->UpdatesFromGallery()) ||
661      (!extension && extension_urls::IsWebstoreUpdateUrl(
662           pending_extension_info->update_url()))) {
663    creation_flags |= Extension::FROM_WEBSTORE;
664  }
665
666  // Bookmark apps being updated is kind of a contradiction, but that's because
667  // we mark the default apps as bookmark apps, and they're hosted in the web
668  // store, thus they can get updated. See http://crbug.com/101605 for more
669  // details.
670  if (extension && extension->from_bookmark())
671    creation_flags |= Extension::FROM_BOOKMARK;
672
673  if (extension && extension->was_installed_by_default())
674    creation_flags |= Extension::WAS_INSTALLED_BY_DEFAULT;
675
676  installer->set_creation_flags(creation_flags);
677
678  installer->set_delete_source(true);
679  installer->set_download_url(download_url);
680  installer->set_install_cause(extension_misc::INSTALL_CAUSE_UPDATE);
681  installer->InstallCrx(extension_path);
682
683  if (out_crx_installer)
684    *out_crx_installer = installer;
685
686  return true;
687}
688
689void ExtensionService::ReloadExtension(const std::string& extension_id) {
690  int events = HasShellWindows(extension_id) ? EVENT_LAUNCHED : EVENT_NONE;
691  ReloadExtensionWithEvents(extension_id, events);
692}
693
694void ExtensionService::RestartExtension(const std::string& extension_id) {
695  ReloadExtensionWithEvents(extension_id, EVENT_RESTARTED);
696}
697
698void ExtensionService::ReloadExtensionWithEvents(
699    const std::string& extension_id,
700    int events) {
701  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
702
703  // If the extension is already reloading, don't reload again.
704  if (extension_prefs_->GetDisableReasons(extension_id) &
705      Extension::DISABLE_RELOAD) {
706    return;
707  }
708
709  base::FilePath path;
710  const Extension* current_extension = GetExtensionById(extension_id, false);
711
712  // Disable the extension if it's loaded. It might not be loaded if it crashed.
713  if (current_extension) {
714    // If the extension has an inspector open for its background page, detach
715    // the inspector and hang onto a cookie for it, so that we can reattach
716    // later.
717    // TODO(yoz): this is not incognito-safe!
718    ExtensionProcessManager* manager = system_->process_manager();
719    extensions::ExtensionHost* host =
720        manager->GetBackgroundHostForExtension(extension_id);
721    if (host && DevToolsAgentHost::HasFor(host->render_view_host())) {
722      // Look for an open inspector for the background page.
723      std::string devtools_cookie = DevToolsAgentHost::DisconnectRenderViewHost(
724          host->render_view_host());
725      if (devtools_cookie != std::string())
726        orphaned_dev_tools_[extension_id] = devtools_cookie;
727    }
728
729    path = current_extension->path();
730    DisableExtension(extension_id, Extension::DISABLE_RELOAD);
731    reloading_extensions_.insert(extension_id);
732  } else {
733    path = unloaded_extension_paths_[extension_id];
734  }
735
736  on_load_events_[extension_id] = events;
737
738  if (delayed_updates_for_idle_.Contains(extension_id)) {
739    FinishDelayedInstallation(extension_id);
740    return;
741  }
742
743  // If we're reloading a component extension, use the component extension
744  // loader's reloader.
745  if (component_loader_->Exists(extension_id)) {
746    component_loader_->Reload(extension_id);
747    return;
748  }
749
750  // Check the installed extensions to see if what we're reloading was already
751  // installed.
752  scoped_ptr<ExtensionInfo> installed_extension(
753      extension_prefs_->GetInstalledExtensionInfo(extension_id));
754  if (installed_extension.get() &&
755      installed_extension->extension_manifest.get()) {
756    extensions::InstalledLoader(this).Load(*installed_extension, false);
757  } else {
758    // Otherwise, the extension is unpacked (location LOAD).
759    // We should always be able to remember the extension's path. If it's not in
760    // the map, someone failed to update |unloaded_extension_paths_|.
761    CHECK(!path.empty());
762    extensions::UnpackedInstaller::Create(this)->Load(path);
763  }
764}
765
766bool ExtensionService::UninstallExtension(
767    std::string extension_id,
768    bool external_uninstall,
769    string16* error) {
770  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
771
772  scoped_refptr<const Extension> extension(GetInstalledExtension(extension_id));
773
774  // Callers should not send us nonexistent extensions.
775  CHECK(extension);
776
777  // Policy change which triggers an uninstall will always set
778  // |external_uninstall| to true so this is the only way to uninstall
779  // managed extensions.
780  if (!external_uninstall &&
781      !system_->management_policy()->UserMayModifySettings(
782        extension.get(), error)) {
783    content::NotificationService::current()->Notify(
784        chrome::NOTIFICATION_EXTENSION_UNINSTALL_NOT_ALLOWED,
785        content::Source<Profile>(profile_),
786        content::Details<const Extension>(extension));
787    return false;
788  }
789
790  // Extract the data we need for sync now, but don't actually sync until we've
791  // completed the uninstallation.
792  syncer::SyncChange sync_change;
793  if (app_sync_bundle_.HandlesApp(*extension)) {
794    sync_change = app_sync_bundle_.CreateSyncChangeToDelete(extension);
795  } else if (extension_sync_bundle_.HandlesExtension(*extension)) {
796    sync_change = extension_sync_bundle_.CreateSyncChangeToDelete(extension);
797  }
798
799  if (IsUnacknowledgedExternalExtension(extension)) {
800    UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalExtensionEvent",
801                              EXTERNAL_EXTENSION_UNINSTALLED,
802                              EXTERNAL_EXTENSION_BUCKET_BOUNDARY);
803  }
804  UMA_HISTOGRAM_ENUMERATION("Extensions.UninstallType",
805                            extension->GetType(), 100);
806  RecordPermissionMessagesHistogram(
807      extension, "Extensions.Permissions_Uninstall");
808
809  // Unload before doing more cleanup to ensure that nothing is hanging on to
810  // any of these resources.
811  UnloadExtension(extension_id, extension_misc::UNLOAD_REASON_UNINSTALL);
812
813  extension_prefs_->OnExtensionUninstalled(extension_id, extension->location(),
814                                           external_uninstall);
815
816  // Tell the backend to start deleting installed extensions on the file thread.
817  if (!Manifest::IsUnpackedLocation(extension->location())) {
818    if (!GetFileTaskRunner()->PostTask(
819            FROM_HERE,
820            base::Bind(
821                &extension_file_util::UninstallExtension,
822                install_directory_,
823                extension_id)))
824      NOTREACHED();
825  }
826
827  GURL launch_web_url_origin(extension->launch_web_url());
828  launch_web_url_origin = launch_web_url_origin.GetOrigin();
829  bool is_storage_isolated =
830      extensions::AppIsolationInfo::HasIsolatedStorage(extension);
831
832  if (is_storage_isolated) {
833    BrowserContext::AsyncObliterateStoragePartition(
834        profile_,
835        GetSiteForExtensionId(extension_id),
836        base::Bind(&ExtensionService::OnNeedsToGarbageCollectIsolatedStorage,
837                   AsWeakPtr()));
838  } else {
839    if (extension->is_hosted_app() &&
840        !profile_->GetExtensionSpecialStoragePolicy()->
841            IsStorageProtected(launch_web_url_origin)) {
842      extensions::DataDeleter::StartDeleting(
843          profile_, extension_id, launch_web_url_origin);
844    }
845    extensions::DataDeleter::StartDeleting(profile_, extension_id,
846                                           extension->url());
847  }
848
849  UntrackTerminatedExtension(extension_id);
850
851  // Notify interested parties that we've uninstalled this extension.
852  content::NotificationService::current()->Notify(
853      chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
854      content::Source<Profile>(profile_),
855      content::Details<const Extension>(extension));
856
857  if (app_sync_bundle_.HasExtensionId(extension_id) &&
858      sync_change.sync_data().GetDataType() == syncer::APPS) {
859    app_sync_bundle_.ProcessDeletion(extension_id, sync_change);
860  } else if (extension_sync_bundle_.HasExtensionId(extension_id) &&
861             sync_change.sync_data().GetDataType() == syncer::EXTENSIONS) {
862    extension_sync_bundle_.ProcessDeletion(extension_id, sync_change);
863  }
864
865  delayed_updates_for_idle_.Remove(extension_id);
866  delayed_installs_.Remove(extension_id);
867
868  // Track the uninstallation.
869  UMA_HISTOGRAM_ENUMERATION("Extensions.ExtensionUninstalled", 1, 2);
870
871  return true;
872}
873
874bool ExtensionService::IsExtensionEnabled(
875    const std::string& extension_id) const {
876  if (extensions_.Contains(extension_id) ||
877      terminated_extensions_.Contains(extension_id)) {
878    return true;
879  }
880
881  if (disabled_extensions_.Contains(extension_id) ||
882      blacklisted_extensions_.Contains(extension_id)) {
883    return false;
884  }
885
886  // If the extension hasn't been loaded yet, check the prefs for it. Assume
887  // enabled unless otherwise noted.
888  return !extension_prefs_->IsExtensionDisabled(extension_id) &&
889         !extension_prefs_->IsExternalExtensionUninstalled(extension_id);
890}
891
892bool ExtensionService::IsExternalExtensionUninstalled(
893    const std::string& extension_id) const {
894  return extension_prefs_->IsExternalExtensionUninstalled(extension_id);
895}
896
897bool ExtensionService::IsExtensionEnabledForLauncher(
898    const std::string& extension_id) const {
899  return IsExtensionEnabled(extension_id) &&
900      !GetTerminatedExtension(extension_id);
901}
902
903void ExtensionService::EnableExtension(const std::string& extension_id) {
904  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
905
906  if (IsExtensionEnabled(extension_id))
907    return;
908
909  extension_prefs_->SetExtensionState(extension_id, Extension::ENABLED);
910  extension_prefs_->ClearDisableReasons(extension_id);
911
912  const Extension* extension = disabled_extensions_.GetByID(extension_id);
913  // This can happen if sync enables an extension that is not
914  // installed yet.
915  if (!extension)
916    return;
917
918  if (IsUnacknowledgedExternalExtension(extension)) {
919    UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalExtensionEvent",
920                              EXTERNAL_EXTENSION_REENABLED,
921                              EXTERNAL_EXTENSION_BUCKET_BOUNDARY);
922    AcknowledgeExternalExtension(extension->id());
923  }
924
925  // Move it over to the enabled list.
926  extensions_.Insert(make_scoped_refptr(extension));
927  disabled_extensions_.Remove(extension->id());
928
929  NotifyExtensionLoaded(extension);
930
931  // Notify listeners that the extension was enabled.
932  content::NotificationService::current()->Notify(
933      chrome::NOTIFICATION_EXTENSION_ENABLED,
934      content::Source<Profile>(profile_),
935      content::Details<const Extension>(extension));
936
937  SyncExtensionChangeIfNeeded(*extension);
938}
939
940void ExtensionService::DisableExtension(
941    const std::string& extension_id,
942    Extension::DisableReason disable_reason) {
943  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
944
945  // The extension may have been disabled already.
946  if (!IsExtensionEnabled(extension_id))
947    return;
948
949  const Extension* extension = GetInstalledExtension(extension_id);
950  // |extension| can be NULL if sync disables an extension that is not
951  // installed yet.
952  if (extension &&
953      !system_->management_policy()->UserMayModifySettings(extension, NULL)) {
954    return;
955  }
956
957  extension_prefs_->SetExtensionState(extension_id, Extension::DISABLED);
958  extension_prefs_->AddDisableReason(extension_id, disable_reason);
959
960  int include_mask = INCLUDE_EVERYTHING & ~INCLUDE_DISABLED;
961  extension = GetExtensionById(extension_id, include_mask);
962  if (!extension)
963    return;
964
965  // Reset the background_page_ready flag
966  if (extensions::BackgroundInfo::HasBackgroundPage(extension))
967    extension_runtime_data_[extension->id()].background_page_ready = false;
968
969  // Move it over to the disabled list. Don't send a second unload notification
970  // for terminated extensions being disabled.
971  disabled_extensions_.Insert(make_scoped_refptr(extension));
972  if (extensions_.Contains(extension->id())) {
973    extensions_.Remove(extension->id());
974    NotifyExtensionUnloaded(extension, extension_misc::UNLOAD_REASON_DISABLE);
975  } else {
976    terminated_extensions_.Remove(extension->id());
977  }
978
979  SyncExtensionChangeIfNeeded(*extension);
980}
981
982void ExtensionService::GrantPermissionsAndEnableExtension(
983    const Extension* extension) {
984  GrantPermissions(extension);
985  RecordPermissionMessagesHistogram(
986      extension, "Extensions.Permissions_ReEnable");
987  extension_prefs_->SetDidExtensionEscalatePermissions(extension, false);
988  EnableExtension(extension->id());
989}
990
991void ExtensionService::GrantPermissions(const Extension* extension) {
992  CHECK(extension);
993  extensions::PermissionsUpdater perms_updater(profile());
994  perms_updater.GrantActivePermissions(extension);
995}
996
997// static
998void ExtensionService::RecordPermissionMessagesHistogram(
999    const Extension* extension, const char* histogram) {
1000  // Since this is called from multiple sources, and since the histogram macros
1001  // use statics, we need to manually lookup the histogram ourselves.
1002  base::HistogramBase* counter = base::LinearHistogram::FactoryGet(
1003      histogram,
1004      1,
1005      PermissionMessage::kEnumBoundary,
1006      PermissionMessage::kEnumBoundary + 1,
1007      base::HistogramBase::kUmaTargetedHistogramFlag);
1008
1009  PermissionMessages permissions =
1010      extensions::PermissionsData::GetPermissionMessages(extension);
1011  if (permissions.empty()) {
1012    counter->Add(PermissionMessage::kNone);
1013  } else {
1014    for (PermissionMessages::iterator it = permissions.begin();
1015         it != permissions.end(); ++it)
1016      counter->Add(it->id());
1017  }
1018}
1019
1020void ExtensionService::NotifyExtensionLoaded(const Extension* extension) {
1021  // The ChromeURLRequestContexts need to be first to know that the extension
1022  // was loaded, otherwise a race can arise where a renderer that is created
1023  // for the extension may try to load an extension URL with an extension id
1024  // that the request context doesn't yet know about. The profile is responsible
1025  // for ensuring its URLRequestContexts appropriately discover the loaded
1026  // extension.
1027  system_->RegisterExtensionWithRequestContexts(extension);
1028
1029  // Tell renderers about the new extension, unless it's a theme (renderers
1030  // don't need to know about themes).
1031  if (!extension->is_theme()) {
1032    for (content::RenderProcessHost::iterator i(
1033            content::RenderProcessHost::AllHostsIterator());
1034         !i.IsAtEnd(); i.Advance()) {
1035      content::RenderProcessHost* host = i.GetCurrentValue();
1036      Profile* host_profile =
1037          Profile::FromBrowserContext(host->GetBrowserContext());
1038      if (host_profile->GetOriginalProfile() ==
1039          profile_->GetOriginalProfile()) {
1040        std::vector<ExtensionMsg_Loaded_Params> loaded_extensions(
1041            1, ExtensionMsg_Loaded_Params(extension));
1042        host->Send(
1043            new ExtensionMsg_Loaded(loaded_extensions));
1044      }
1045    }
1046  }
1047
1048  // Tell subsystems that use the EXTENSION_LOADED notification about the new
1049  // extension.
1050  //
1051  // NOTE: It is important that this happen after notifying the renderers about
1052  // the new extensions so that if we navigate to an extension URL in
1053  // NOTIFICATION_EXTENSION_LOADED, the renderer is guaranteed to know about it.
1054  content::NotificationService::current()->Notify(
1055      chrome::NOTIFICATION_EXTENSION_LOADED,
1056      content::Source<Profile>(profile_),
1057      content::Details<const Extension>(extension));
1058
1059  // Tell a random-ass collection of other subsystems about the new extension.
1060  // TODO(aa): What should we do with all this goop? Can it move into the
1061  // relevant objects via EXTENSION_LOADED?
1062
1063  profile_->GetExtensionSpecialStoragePolicy()->
1064      GrantRightsForExtension(extension);
1065
1066  UpdateActiveExtensionsInCrashReporter();
1067
1068  // If the extension has permission to load chrome://favicon/ resources we need
1069  // to make sure that the FaviconSource is registered with the
1070  // ChromeURLDataManager.
1071  if (extensions::PermissionsData::HasHostPermission(
1072          extension, GURL(chrome::kChromeUIFaviconURL))) {
1073    FaviconSource* favicon_source = new FaviconSource(profile_,
1074                                                      FaviconSource::FAVICON);
1075    content::URLDataSource::Add(profile_, favicon_source);
1076  }
1077
1078#if !defined(OS_ANDROID)
1079  // Same for chrome://theme/ resources.
1080  if (extensions::PermissionsData::HasHostPermission(
1081          extension, GURL(chrome::kChromeUIThemeURL))) {
1082    ThemeSource* theme_source = new ThemeSource(profile_);
1083    content::URLDataSource::Add(profile_, theme_source);
1084  }
1085#endif
1086
1087  // Same for chrome://thumb/ resources.
1088  if (extensions::PermissionsData::HasHostPermission(
1089          extension, GURL(chrome::kChromeUIThumbnailURL))) {
1090    ThumbnailSource* thumbnail_source = new ThumbnailSource(profile_);
1091    content::URLDataSource::Add(profile_, thumbnail_source);
1092  }
1093
1094#if defined(ENABLE_PLUGINS)
1095  // TODO(mpcomplete): This ends up affecting all profiles. See crbug.com/80757.
1096  bool plugins_changed = false;
1097  if (extensions::PluginInfo::HasPlugins(extension)) {
1098    const extensions::PluginInfo::PluginVector* plugins =
1099      extensions::PluginInfo::GetPlugins(extension);
1100    CHECK(plugins);
1101    plugins_changed = true;
1102    for (extensions::PluginInfo::PluginVector::const_iterator plugin =
1103             plugins->begin();
1104         plugin != plugins->end(); ++plugin) {
1105      PluginService::GetInstance()->RefreshPlugins();
1106      PluginService::GetInstance()->AddExtraPluginPath(plugin->path);
1107      ChromePluginServiceFilter* filter =
1108          ChromePluginServiceFilter::GetInstance();
1109      if (plugin->is_public) {
1110        filter->RestrictPluginToProfileAndOrigin(
1111            plugin->path, profile_, GURL());
1112      } else {
1113        filter->RestrictPluginToProfileAndOrigin(
1114            plugin->path, profile_, extension->url());
1115      }
1116    }
1117  }
1118
1119  bool nacl_modules_changed = false;
1120  for (size_t i = 0; i < extension->nacl_modules().size(); ++i) {
1121    const Extension::NaClModuleInfo& module = extension->nacl_modules()[i];
1122    RegisterNaClModule(module.url, module.mime_type);
1123    nacl_modules_changed = true;
1124  }
1125
1126  if (nacl_modules_changed)
1127    UpdatePluginListWithNaClModules();
1128
1129  if (plugins_changed || nacl_modules_changed)
1130    PluginService::GetInstance()->PurgePluginListCache(profile_, false);
1131#endif  // defined(ENABLE_PLUGINS)
1132}
1133
1134void ExtensionService::NotifyExtensionUnloaded(
1135    const Extension* extension,
1136    extension_misc::UnloadedExtensionReason reason) {
1137  UnloadedExtensionInfo details(extension, reason);
1138  content::NotificationService::current()->Notify(
1139      chrome::NOTIFICATION_EXTENSION_UNLOADED,
1140      content::Source<Profile>(profile_),
1141      content::Details<UnloadedExtensionInfo>(&details));
1142
1143#if defined(ENABLE_THEMES)
1144  // If the current theme is being unloaded, tell ThemeService to revert back
1145  // to the default theme.
1146  if (reason != extension_misc::UNLOAD_REASON_UPDATE && extension->is_theme()) {
1147    ThemeService* theme_service = ThemeServiceFactory::GetForProfile(profile_);
1148    if (extension->id() == theme_service->GetThemeID())
1149      theme_service->UseDefaultTheme();
1150  }
1151#endif
1152
1153  for (content::RenderProcessHost::iterator i(
1154          content::RenderProcessHost::AllHostsIterator());
1155       !i.IsAtEnd(); i.Advance()) {
1156    content::RenderProcessHost* host = i.GetCurrentValue();
1157    Profile* host_profile =
1158        Profile::FromBrowserContext(host->GetBrowserContext());
1159    if (host_profile->GetOriginalProfile() == profile_->GetOriginalProfile())
1160      host->Send(new ExtensionMsg_Unloaded(extension->id()));
1161  }
1162
1163  system_->UnregisterExtensionWithRequestContexts(extension->id(), reason);
1164  profile_->GetExtensionSpecialStoragePolicy()->
1165      RevokeRightsForExtension(extension);
1166
1167#if defined(OS_CHROMEOS)
1168  // Revoke external file access for the extension from its file system context.
1169  // It is safe to access the extension's storage partition at this point. The
1170  // storage partition may get destroyed only after the extension gets unloaded.
1171  GURL site = extensions::ExtensionSystem::Get(profile_)->extension_service()->
1172      GetSiteForExtensionId(extension->id());
1173  fileapi::FileSystemContext* filesystem_context =
1174      BrowserContext::GetStoragePartitionForSite(profile_, site)->
1175          GetFileSystemContext();
1176  if (filesystem_context && filesystem_context->external_provider()) {
1177    filesystem_context->external_provider()->
1178        RevokeAccessForExtension(extension->id());
1179  }
1180#endif
1181
1182  UpdateActiveExtensionsInCrashReporter();
1183
1184#if defined(ENABLE_PLUGINS)
1185  bool plugins_changed = false;
1186  if (extensions::PluginInfo::HasPlugins(extension)) {
1187    const extensions::PluginInfo::PluginVector* plugins =
1188      extensions::PluginInfo::GetPlugins(extension);
1189    plugins_changed = true;
1190    for (extensions::PluginInfo::PluginVector::const_iterator plugin =
1191             plugins->begin();
1192         plugin != plugins->end(); ++plugin) {
1193      PluginService::GetInstance()->ForcePluginShutdown(plugin->path);
1194      PluginService::GetInstance()->RefreshPlugins();
1195      PluginService::GetInstance()->RemoveExtraPluginPath(plugin->path);
1196      ChromePluginServiceFilter::GetInstance()->UnrestrictPlugin(plugin->path);
1197    }
1198  }
1199
1200  bool nacl_modules_changed = false;
1201  for (size_t i = 0; i < extension->nacl_modules().size(); ++i) {
1202    const Extension::NaClModuleInfo& module = extension->nacl_modules()[i];
1203    UnregisterNaClModule(module.url);
1204    nacl_modules_changed = true;
1205  }
1206
1207  if (nacl_modules_changed)
1208    UpdatePluginListWithNaClModules();
1209
1210  if (plugins_changed || nacl_modules_changed)
1211    PluginService::GetInstance()->PurgePluginListCache(profile_, false);
1212#endif  // defined(ENABLE_PLUGINS)
1213}
1214
1215Profile* ExtensionService::profile() {
1216  return profile_;
1217}
1218
1219extensions::ExtensionPrefs* ExtensionService::extension_prefs() {
1220  return extension_prefs_;
1221}
1222
1223extensions::SettingsFrontend* ExtensionService::settings_frontend() {
1224  return settings_frontend_.get();
1225}
1226
1227extensions::ContentSettingsStore* ExtensionService::GetContentSettingsStore() {
1228  return extension_prefs()->content_settings_store();
1229}
1230
1231bool ExtensionService::is_ready() {
1232  return ready_->is_signaled();
1233}
1234
1235base::SequencedTaskRunner* ExtensionService::GetFileTaskRunner() {
1236  if (file_task_runner_)
1237    return file_task_runner_;
1238
1239  // We should be able to interrupt any part of extension install process during
1240  // shutdown. SKIP_ON_SHUTDOWN ensures that not started extension install tasks
1241  // will be ignored/deleted while we will block on started tasks.
1242  std::string token("ext_install-");
1243  token.append(profile_->GetPath().AsUTF8Unsafe());
1244  file_task_runner_ = BrowserThread::GetBlockingPool()->
1245      GetSequencedTaskRunnerWithShutdownBehavior(
1246        BrowserThread::GetBlockingPool()->GetNamedSequenceToken(token),
1247        base::SequencedWorkerPool::SKIP_ON_SHUTDOWN);
1248  return file_task_runner_;
1249}
1250
1251extensions::ExtensionUpdater* ExtensionService::updater() {
1252  return updater_.get();
1253}
1254
1255void ExtensionService::CheckManagementPolicy() {
1256  std::vector<std::string> to_be_removed;
1257
1258  // Loop through extensions list, unload installed extensions.
1259  for (ExtensionSet::const_iterator iter = extensions_.begin();
1260       iter != extensions_.end(); ++iter) {
1261    const Extension* extension = (*iter);
1262    if (!system_->management_policy()->UserMayLoad(extension, NULL))
1263      to_be_removed.push_back(extension->id());
1264  }
1265
1266  // UnloadExtension will change the extensions_ list. So, we should
1267  // call it outside the iterator loop.
1268  for (size_t i = 0; i < to_be_removed.size(); ++i)
1269    UnloadExtension(to_be_removed[i], extension_misc::UNLOAD_REASON_DISABLE);
1270}
1271
1272void ExtensionService::CheckForUpdatesSoon() {
1273  if (updater()) {
1274    if (AreAllExternalProvidersReady()) {
1275      updater()->CheckSoon();
1276    } else {
1277      // Sync can start updating before all the external providers are ready
1278      // during startup. Start the update as soon as those providers are ready,
1279      // but not before.
1280      update_once_all_providers_are_ready_ = true;
1281    }
1282  } else {
1283    LOG(WARNING) << "CheckForUpdatesSoon() called with auto-update turned off";
1284  }
1285}
1286
1287syncer::SyncMergeResult ExtensionService::MergeDataAndStartSyncing(
1288    syncer::ModelType type,
1289    const syncer::SyncDataList& initial_sync_data,
1290    scoped_ptr<syncer::SyncChangeProcessor> sync_processor,
1291    scoped_ptr<syncer::SyncErrorFactory> sync_error_factory) {
1292  CHECK(sync_processor.get());
1293  CHECK(sync_error_factory.get());
1294
1295  switch (type) {
1296    case syncer::EXTENSIONS:
1297      extension_sync_bundle_.SetupSync(sync_processor.release(),
1298                                       sync_error_factory.release(),
1299                                       initial_sync_data);
1300      break;
1301
1302    case syncer::APPS:
1303      app_sync_bundle_.SetupSync(sync_processor.release(),
1304                                 sync_error_factory.release(),
1305                                 initial_sync_data);
1306      break;
1307
1308    default:
1309      LOG(FATAL) << "Got " << type << " ModelType";
1310  }
1311
1312  // Process local extensions.
1313  // TODO(yoz): Determine whether pending extensions should be considered too.
1314  //            See crbug.com/104399.
1315  syncer::SyncDataList sync_data_list = GetAllSyncData(type);
1316  syncer::SyncChangeList sync_change_list;
1317  for (syncer::SyncDataList::const_iterator i = sync_data_list.begin();
1318       i != sync_data_list.end();
1319       ++i) {
1320    switch (type) {
1321        case syncer::EXTENSIONS:
1322          sync_change_list.push_back(
1323              extension_sync_bundle_.CreateSyncChange(*i));
1324          break;
1325        case syncer::APPS:
1326          sync_change_list.push_back(app_sync_bundle_.CreateSyncChange(*i));
1327          break;
1328      default:
1329        LOG(FATAL) << "Got " << type << " ModelType";
1330    }
1331  }
1332
1333
1334  if (type == syncer::EXTENSIONS) {
1335    extension_sync_bundle_.ProcessSyncChangeList(sync_change_list);
1336  } else if (type == syncer::APPS) {
1337    app_sync_bundle_.ProcessSyncChangeList(sync_change_list);
1338  }
1339
1340  return syncer::SyncMergeResult(type);
1341}
1342
1343void ExtensionService::StopSyncing(syncer::ModelType type) {
1344  if (type == syncer::APPS) {
1345    app_sync_bundle_.Reset();
1346  } else if (type == syncer::EXTENSIONS) {
1347    extension_sync_bundle_.Reset();
1348  }
1349}
1350
1351syncer::SyncDataList ExtensionService::GetAllSyncData(
1352    syncer::ModelType type) const {
1353  if (type == syncer::EXTENSIONS)
1354    return extension_sync_bundle_.GetAllSyncData();
1355  if (type == syncer::APPS)
1356    return app_sync_bundle_.GetAllSyncData();
1357
1358  // We should only get sync data for extensions and apps.
1359  NOTREACHED();
1360
1361  return syncer::SyncDataList();
1362}
1363
1364syncer::SyncError ExtensionService::ProcessSyncChanges(
1365    const tracked_objects::Location& from_here,
1366    const syncer::SyncChangeList& change_list) {
1367  for (syncer::SyncChangeList::const_iterator i = change_list.begin();
1368      i != change_list.end();
1369      ++i) {
1370    syncer::ModelType type = i->sync_data().GetDataType();
1371    if (type == syncer::EXTENSIONS) {
1372      extension_sync_bundle_.ProcessSyncChange(
1373          extensions::ExtensionSyncData(*i));
1374    } else if (type == syncer::APPS) {
1375      app_sync_bundle_.ProcessSyncChange(extensions::AppSyncData(*i));
1376    }
1377  }
1378
1379  extension_prefs()->extension_sorting()->FixNTPOrdinalCollisions();
1380
1381  return syncer::SyncError();
1382}
1383
1384extensions::ExtensionSyncData ExtensionService::GetExtensionSyncData(
1385    const Extension& extension) const {
1386  return extensions::ExtensionSyncData(extension,
1387                                       IsExtensionEnabled(extension.id()),
1388                                       IsIncognitoEnabled(extension.id()));
1389}
1390
1391extensions::AppSyncData ExtensionService::GetAppSyncData(
1392    const Extension& extension) const {
1393  return extensions::AppSyncData(
1394      extension,
1395      IsExtensionEnabled(extension.id()),
1396      IsIncognitoEnabled(extension.id()),
1397      extension_prefs_->extension_sorting()->GetAppLaunchOrdinal(
1398          extension.id()),
1399      extension_prefs_->extension_sorting()->GetPageOrdinal(extension.id()));
1400}
1401
1402std::vector<extensions::ExtensionSyncData>
1403  ExtensionService::GetExtensionSyncDataList() const {
1404  std::vector<extensions::ExtensionSyncData> extension_sync_list;
1405  extension_sync_bundle_.GetExtensionSyncDataListHelper(extensions_,
1406                                                        &extension_sync_list);
1407  extension_sync_bundle_.GetExtensionSyncDataListHelper(disabled_extensions_,
1408                                                        &extension_sync_list);
1409  extension_sync_bundle_.GetExtensionSyncDataListHelper(terminated_extensions_,
1410                                                        &extension_sync_list);
1411
1412  std::vector<extensions::ExtensionSyncData> pending_extensions =
1413      extension_sync_bundle_.GetPendingData();
1414  extension_sync_list.insert(extension_sync_list.begin(),
1415                             pending_extensions.begin(),
1416                             pending_extensions.end());
1417
1418  return extension_sync_list;
1419}
1420
1421std::vector<extensions::AppSyncData> ExtensionService::GetAppSyncDataList()
1422    const {
1423  std::vector<extensions::AppSyncData> app_sync_list;
1424  app_sync_bundle_.GetAppSyncDataListHelper(extensions_, &app_sync_list);
1425  app_sync_bundle_.GetAppSyncDataListHelper(disabled_extensions_,
1426                                            &app_sync_list);
1427  app_sync_bundle_.GetAppSyncDataListHelper(terminated_extensions_,
1428                                            &app_sync_list);
1429
1430  std::vector<extensions::AppSyncData> pending_apps =
1431      app_sync_bundle_.GetPendingData();
1432  app_sync_list.insert(app_sync_list.begin(),
1433                       pending_apps.begin(),
1434                       pending_apps.end());
1435
1436  return app_sync_list;
1437}
1438
1439bool ExtensionService::ProcessExtensionSyncData(
1440    const extensions::ExtensionSyncData& extension_sync_data) {
1441  if (!ProcessExtensionSyncDataHelper(extension_sync_data,
1442                                      syncer::EXTENSIONS)) {
1443    extension_sync_bundle_.AddPendingExtension(extension_sync_data.id(),
1444                                               extension_sync_data);
1445    CheckForUpdatesSoon();
1446    return false;
1447  }
1448
1449  return true;
1450}
1451
1452bool ExtensionService::ProcessAppSyncData(
1453    const extensions::AppSyncData& app_sync_data) {
1454  const std::string& id = app_sync_data.id();
1455
1456  if (app_sync_data.app_launch_ordinal().IsValid() &&
1457      app_sync_data.page_ordinal().IsValid()) {
1458    extension_prefs_->extension_sorting()->SetAppLaunchOrdinal(
1459        id,
1460        app_sync_data.app_launch_ordinal());
1461    extension_prefs_->extension_sorting()->SetPageOrdinal(
1462        id,
1463        app_sync_data.page_ordinal());
1464  }
1465
1466  if (!ProcessExtensionSyncDataHelper(app_sync_data.extension_sync_data(),
1467                                      syncer::APPS)) {
1468    app_sync_bundle_.AddPendingApp(id, app_sync_data);
1469    CheckForUpdatesSoon();
1470    return false;
1471  }
1472
1473  return true;
1474}
1475
1476bool ExtensionService::IsCorrectSyncType(const Extension& extension,
1477                                         syncer::ModelType type) const {
1478  if (type == syncer::EXTENSIONS &&
1479      extension.GetSyncType() == Extension::SYNC_TYPE_EXTENSION) {
1480    return true;
1481  }
1482
1483  if (type == syncer::APPS &&
1484      extension.GetSyncType() == Extension::SYNC_TYPE_APP) {
1485    return true;
1486  }
1487
1488  return false;
1489}
1490
1491bool ExtensionService::ProcessExtensionSyncDataHelper(
1492    const extensions::ExtensionSyncData& extension_sync_data,
1493    syncer::ModelType type) {
1494  const std::string& id = extension_sync_data.id();
1495  const Extension* extension = GetInstalledExtension(id);
1496
1497  // TODO(bolms): we should really handle this better.  The particularly bad
1498  // case is where an app becomes an extension or vice versa, and we end up with
1499  // a zombie extension that won't go away.
1500  if (extension && !IsCorrectSyncType(*extension, type))
1501    return true;
1502
1503  // Handle uninstalls first.
1504  if (extension_sync_data.uninstalled()) {
1505    std::string error;
1506    if (!UninstallExtensionHelper(this, id)) {
1507      LOG(WARNING) << "Could not uninstall extension " << id
1508                   << " for sync";
1509    }
1510    return true;
1511  }
1512
1513  // Extension from sync was uninstalled by the user as external extensions.
1514  // Honor user choice and skip installation/enabling.
1515  if (IsExternalExtensionUninstalled(id)) {
1516    LOG(WARNING) << "Extension with id " << id
1517                 << " from sync was uninstalled as external extension";
1518    return true;
1519  }
1520
1521  // Set user settings.
1522  // If the extension has been disabled from sync, it may not have
1523  // been installed yet, so we don't know if the disable reason was a
1524  // permissions increase.  That will be updated once CheckPermissionsIncrease
1525  // is called for it.
1526  if (extension_sync_data.enabled())
1527    EnableExtension(id);
1528  else
1529    DisableExtension(id, Extension::DISABLE_UNKNOWN_FROM_SYNC);
1530
1531  // We need to cache some version information here because setting the
1532  // incognito flag invalidates the |extension| pointer (it reloads the
1533  // extension).
1534  bool extension_installed = (extension != NULL);
1535  int result = extension ?
1536      extension->version()->CompareTo(extension_sync_data.version()) : 0;
1537  SetIsIncognitoEnabled(id, extension_sync_data.incognito_enabled());
1538  extension = NULL;  // No longer safe to use.
1539
1540  if (extension_installed) {
1541    // If the extension is already installed, check if it's outdated.
1542    if (result < 0) {
1543      // Extension is outdated.
1544      return false;
1545    }
1546  } else {
1547    // TODO(akalin): Replace silent update with a list of enabled
1548    // permissions.
1549    const bool kInstallSilently = true;
1550
1551    CHECK(type == syncer::EXTENSIONS || type == syncer::APPS);
1552    ExtensionFilter filter =
1553        (type == syncer::APPS) ? IsSyncableApp : IsSyncableExtension;
1554
1555    if (!pending_extension_manager()->AddFromSync(
1556            id,
1557            extension_sync_data.update_url(),
1558            filter,
1559            kInstallSilently)) {
1560      LOG(WARNING) << "Could not add pending extension for " << id;
1561      // This means that the extension is already pending installation, with a
1562      // non-INTERNAL location.  Add to pending_sync_data, even though it will
1563      // never be removed (we'll never install a syncable version of the
1564      // extension), so that GetAllSyncData() continues to send it.
1565    }
1566    // Track pending extensions so that we can return them in GetAllSyncData().
1567    return false;
1568  }
1569
1570  return true;
1571}
1572
1573bool ExtensionService::IsIncognitoEnabled(
1574    const std::string& extension_id) const {
1575  const Extension* extension = GetInstalledExtension(extension_id);
1576  if (extension && !extension->can_be_incognito_enabled())
1577    return false;
1578  // If this is an existing component extension we always allow it to
1579  // work in incognito mode.
1580  if (extension && extension->location() == Manifest::COMPONENT)
1581    return true;
1582
1583  // Check the prefs.
1584  return extension_prefs_->IsIncognitoEnabled(extension_id);
1585}
1586
1587void ExtensionService::SetIsIncognitoEnabled(
1588    const std::string& extension_id, bool enabled) {
1589  const Extension* extension = GetInstalledExtension(extension_id);
1590  if (extension && !extension->can_be_incognito_enabled())
1591    return;
1592  if (extension && extension->location() == Manifest::COMPONENT) {
1593    // This shouldn't be called for component extensions unless they are
1594    // syncable.
1595    DCHECK(extension->IsSyncable());
1596
1597    // If we are here, make sure the we aren't trying to change the value.
1598    DCHECK_EQ(enabled, IsIncognitoEnabled(extension_id));
1599
1600    return;
1601  }
1602
1603  // Broadcast unloaded and loaded events to update browser state. Only bother
1604  // if the value changed and the extension is actually enabled, since there is
1605  // no UI otherwise.
1606  bool old_enabled = extension_prefs_->IsIncognitoEnabled(extension_id);
1607  if (enabled == old_enabled)
1608    return;
1609
1610  extension_prefs_->SetIsIncognitoEnabled(extension_id, enabled);
1611
1612  bool extension_is_enabled = extensions_.Contains(extension_id);
1613
1614  // When we reload the extension the ID may be invalidated if we've passed it
1615  // by const ref everywhere. Make a copy to be safe.
1616  std::string id = extension_id;
1617  if (extension_is_enabled)
1618    ReloadExtension(id);
1619
1620  // Reloading the extension invalidates the |extension| pointer.
1621  extension = GetInstalledExtension(id);
1622  if (extension)
1623    SyncExtensionChangeIfNeeded(*extension);
1624}
1625
1626bool ExtensionService::CanCrossIncognito(const Extension* extension) const {
1627  // We allow the extension to see events and data from another profile iff it
1628  // uses "spanning" behavior and it has incognito access. "split" mode
1629  // extensions only see events for a matching profile.
1630  CHECK(extension);
1631  return IsIncognitoEnabled(extension->id()) &&
1632         !extensions::IncognitoInfo::IsSplitMode(extension);
1633}
1634
1635bool ExtensionService::CanLoadInIncognito(const Extension* extension) const {
1636  if (extension->is_hosted_app())
1637    return true;
1638  // Packaged apps and regular extensions need to be enabled specifically for
1639  // incognito (and split mode should be set).
1640  return extensions::IncognitoInfo::IsSplitMode(extension) &&
1641         IsIncognitoEnabled(extension->id());
1642}
1643
1644void ExtensionService::OnExtensionMoved(
1645    const std::string& moved_extension_id,
1646    const std::string& predecessor_extension_id,
1647    const std::string& successor_extension_id) {
1648  extension_prefs_->extension_sorting()->OnExtensionMoved(
1649      moved_extension_id,
1650      predecessor_extension_id,
1651      successor_extension_id);
1652
1653  const Extension* extension = GetInstalledExtension(moved_extension_id);
1654  if (extension)
1655    SyncExtensionChangeIfNeeded(*extension);
1656}
1657
1658bool ExtensionService::AllowFileAccess(const Extension* extension) const {
1659  return (CommandLine::ForCurrentProcess()->HasSwitch(
1660              switches::kDisableExtensionsFileAccessCheck) ||
1661          extension_prefs_->AllowFileAccess(extension->id()));
1662}
1663
1664void ExtensionService::SetAllowFileAccess(const Extension* extension,
1665                                          bool allow) {
1666  // Reload to update browser state. Only bother if the value changed and the
1667  // extension is actually enabled, since there is no UI otherwise.
1668  bool old_allow = AllowFileAccess(extension);
1669  if (allow == old_allow)
1670    return;
1671
1672  extension_prefs_->SetAllowFileAccess(extension->id(), allow);
1673
1674  bool extension_is_enabled = extensions_.Contains(extension->id());
1675  if (extension_is_enabled)
1676    ReloadExtension(extension->id());
1677}
1678
1679// Some extensions will autoupdate themselves externally from Chrome.  These
1680// are typically part of some larger client application package.  To support
1681// these, the extension will register its location in the the preferences file
1682// (and also, on Windows, in the registry) and this code will periodically
1683// check that location for a .crx file, which it will then install locally if
1684// a new version is available.
1685// Errors are reported through ExtensionErrorReporter. Succcess is not
1686// reported.
1687void ExtensionService::CheckForExternalUpdates() {
1688  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1689
1690  // Note that this installation is intentionally silent (since it didn't
1691  // go through the front-end).  Extensions that are registered in this
1692  // way are effectively considered 'pre-bundled', and so implicitly
1693  // trusted.  In general, if something has HKLM or filesystem access,
1694  // they could install an extension manually themselves anyway.
1695
1696  // Ask each external extension provider to give us a call back for each
1697  // extension they know about. See OnExternalExtension(File|UpdateUrl)Found.
1698  extensions::ProviderCollection::const_iterator i;
1699  for (i = external_extension_providers_.begin();
1700       i != external_extension_providers_.end(); ++i) {
1701    extensions::ExternalProviderInterface* provider = i->get();
1702    provider->VisitRegisteredExtension();
1703  }
1704
1705  // Do any required work that we would have done after completion of all
1706  // providers.
1707  if (external_extension_providers_.empty()) {
1708    OnAllExternalProvidersReady();
1709  }
1710}
1711
1712void ExtensionService::OnExternalProviderReady(
1713    const extensions::ExternalProviderInterface* provider) {
1714  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1715  CHECK(provider->IsReady());
1716
1717  // An external provider has finished loading.  We only take action
1718  // if all of them are finished. So we check them first.
1719  if (AreAllExternalProvidersReady())
1720    OnAllExternalProvidersReady();
1721}
1722
1723bool ExtensionService::AreAllExternalProvidersReady() const {
1724  extensions::ProviderCollection::const_iterator i;
1725  for (i = external_extension_providers_.begin();
1726       i != external_extension_providers_.end(); ++i) {
1727    if (!i->get()->IsReady())
1728      return false;
1729  }
1730  return true;
1731}
1732
1733void ExtensionService::OnAllExternalProvidersReady() {
1734  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1735  base::TimeDelta elapsed = base::Time::Now() - profile_->GetStartTime();
1736  UMA_HISTOGRAM_TIMES("Extension.ExternalProvidersReadyAfter", elapsed);
1737
1738  // Install any pending extensions.
1739  if (update_once_all_providers_are_ready_ && updater()) {
1740    update_once_all_providers_are_ready_ = false;
1741    updater()->CheckNow(extensions::ExtensionUpdater::CheckParams());
1742  }
1743
1744  // Uninstall all the unclaimed extensions.
1745  scoped_ptr<extensions::ExtensionPrefs::ExtensionsInfo> extensions_info(
1746      extension_prefs_->GetInstalledExtensionsInfo());
1747  for (size_t i = 0; i < extensions_info->size(); ++i) {
1748    ExtensionInfo* info = extensions_info->at(i).get();
1749    if (Manifest::IsExternalLocation(info->extension_location))
1750      CheckExternalUninstall(info->extension_id);
1751  }
1752  IdentifyAlertableExtensions();
1753}
1754
1755void ExtensionService::IdentifyAlertableExtensions() {
1756  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1757
1758  // Build up the lists of extensions that require acknowledgment. If this is
1759  // the first time, grandfather extensions that would have caused
1760  // notification.
1761  extension_error_ui_.reset(ExtensionErrorUI::Create(this));
1762
1763  bool did_show_alert = false;
1764  if (PopulateExtensionErrorUI(extension_error_ui_.get())) {
1765    if (!is_first_run_) {
1766      CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1767      did_show_alert = extension_error_ui_->ShowErrorInBubbleView();
1768    } else {
1769      // First run. Just acknowledge all the extensions, silently, by
1770      // shortcutting the display of the UI and going straight to the
1771      // callback for pressing the Accept button.
1772      HandleExtensionAlertAccept();
1773    }
1774  }
1775
1776  UpdateExternalExtensionAlert();
1777
1778  if (!did_show_alert)
1779    extension_error_ui_.reset();
1780}
1781
1782bool ExtensionService::PopulateExtensionErrorUI(
1783    ExtensionErrorUI* extension_error_ui) {
1784  bool needs_alert = false;
1785
1786  // Extensions that are blacklisted.
1787  for (ExtensionSet::const_iterator it = blacklisted_extensions_.begin();
1788       it != blacklisted_extensions_.end(); ++it) {
1789    std::string id = (*it)->id();
1790    if (!extension_prefs_->IsBlacklistedExtensionAcknowledged(id)) {
1791      extension_error_ui->AddBlacklistedExtension(id);
1792      needs_alert = true;
1793    }
1794  }
1795
1796  for (ExtensionSet::const_iterator iter = extensions_.begin();
1797       iter != extensions_.end(); ++iter) {
1798    const Extension* e = *iter;
1799
1800    // Extensions disabled by policy. Note: this no longer includes blacklisted
1801    // extensions, though we still show the same UI.
1802    if (!system_->management_policy()->UserMayLoad(e, NULL)) {
1803      if (!extension_prefs_->IsBlacklistedExtensionAcknowledged(e->id())) {
1804        extension_error_ui->AddBlacklistedExtension(e->id());
1805        needs_alert = true;
1806      }
1807    }
1808  }
1809
1810  return needs_alert;
1811}
1812
1813void ExtensionService::HandleExtensionAlertClosed() {
1814  const ExtensionIdSet* extension_ids =
1815      extension_error_ui_->get_blacklisted_extension_ids();
1816  for (ExtensionIdSet::const_iterator iter = extension_ids->begin();
1817       iter != extension_ids->end(); ++iter) {
1818    extension_prefs_->AcknowledgeBlacklistedExtension(*iter);
1819  }
1820  extension_error_ui_.reset();
1821}
1822
1823void ExtensionService::HandleExtensionAlertAccept() {
1824  extension_error_ui_->Close();
1825}
1826
1827void ExtensionService::AcknowledgeExternalExtension(const std::string& id) {
1828  extension_prefs_->AcknowledgeExternalExtension(id);
1829  UpdateExternalExtensionAlert();
1830}
1831
1832bool ExtensionService::IsUnacknowledgedExternalExtension(
1833    const Extension* extension) {
1834  if (!FeatureSwitch::prompt_for_external_extensions()->IsEnabled())
1835    return false;
1836
1837  return (Manifest::IsExternalLocation(extension->location()) &&
1838          !extension_prefs_->IsExternalExtensionAcknowledged(extension->id()) &&
1839          !(extension_prefs_->GetDisableReasons(extension->id()) &
1840                Extension::DISABLE_SIDELOAD_WIPEOUT));
1841}
1842
1843void ExtensionService::HandleExtensionAlertDetails() {
1844  extension_error_ui_->ShowExtensions();
1845  // ShowExtensions may cause the error UI to close synchronously, e.g. if it
1846  // causes a navigation.
1847  if (extension_error_ui_)
1848    extension_error_ui_->Close();
1849}
1850
1851void ExtensionService::UpdateExternalExtensionAlert() {
1852  if (!FeatureSwitch::prompt_for_external_extensions()->IsEnabled())
1853    return;
1854
1855  const Extension* extension = NULL;
1856  for (ExtensionSet::const_iterator iter = disabled_extensions_.begin();
1857       iter != disabled_extensions_.end(); ++iter) {
1858    const Extension* e = *iter;
1859    if (IsUnacknowledgedExternalExtension(e)) {
1860      extension = e;
1861      break;
1862    }
1863  }
1864
1865  if (extension) {
1866    if (!extensions::HasExternalInstallError(this)) {
1867      if (extension_prefs_->IncrementAcknowledgePromptCount(extension->id()) >
1868              kMaxExtensionAcknowledgePromptCount) {
1869        // Stop prompting for this extension, and check if there's another
1870        // one that needs prompting.
1871        extension_prefs_->AcknowledgeExternalExtension(extension->id());
1872        UpdateExternalExtensionAlert();
1873        UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalExtensionEvent",
1874                                  EXTERNAL_EXTENSION_IGNORED,
1875                                  EXTERNAL_EXTENSION_BUCKET_BOUNDARY);
1876        return;
1877      }
1878      if (is_first_run_)
1879        extension_prefs_->SetExternalInstallFirstRun(extension->id());
1880      // first_run is true if the extension was installed during a first run
1881      // (even if it's post-first run now).
1882      bool first_run = extension_prefs_->IsExternalInstallFirstRun(
1883          extension->id());
1884      extensions::AddExternalInstallError(this, extension, first_run);
1885    }
1886  } else {
1887    extensions::RemoveExternalInstallError(this);
1888  }
1889}
1890
1891void ExtensionService::UnloadExtension(
1892    const std::string& extension_id,
1893    extension_misc::UnloadedExtensionReason reason) {
1894  // Make sure the extension gets deleted after we return from this function.
1895  int include_mask = INCLUDE_EVERYTHING & ~INCLUDE_TERMINATED;
1896  scoped_refptr<const Extension> extension(
1897      GetExtensionById(extension_id, include_mask));
1898
1899  // This method can be called via PostTask, so the extension may have been
1900  // unloaded by the time this runs.
1901  if (!extension) {
1902    // In case the extension may have crashed/uninstalled. Allow the profile to
1903    // clean up its RequestContexts.
1904    system_->UnregisterExtensionWithRequestContexts(extension_id, reason);
1905    return;
1906  }
1907
1908  // If uninstalling let RuntimeEventRouter know.
1909  if (reason == extension_misc::UNLOAD_REASON_UNINSTALL)
1910    extensions::RuntimeEventRouter::OnExtensionUninstalled(
1911        profile_, extension_id);
1912
1913  // Keep information about the extension so that we can reload it later
1914  // even if it's not permanently installed.
1915  unloaded_extension_paths_[extension->id()] = extension->path();
1916
1917  // Clean up if the extension is meant to be enabled after a reload.
1918  reloading_extensions_.erase(extension->id());
1919
1920  // Clean up runtime data.
1921  extension_runtime_data_.erase(extension_id);
1922
1923  if (disabled_extensions_.Contains(extension->id())) {
1924    UnloadedExtensionInfo details(extension, reason);
1925    details.already_disabled = true;
1926    disabled_extensions_.Remove(extension->id());
1927    content::NotificationService::current()->Notify(
1928        chrome::NOTIFICATION_EXTENSION_UNLOADED,
1929        content::Source<Profile>(profile_),
1930        content::Details<UnloadedExtensionInfo>(&details));
1931    // Make sure the profile cleans up its RequestContexts when an already
1932    // disabled extension is unloaded (since they are also tracking the disabled
1933    // extensions).
1934    system_->UnregisterExtensionWithRequestContexts(extension_id, reason);
1935    return;
1936  }
1937
1938  // Remove the extension from our list.
1939  extensions_.Remove(extension->id());
1940
1941  NotifyExtensionUnloaded(extension.get(), reason);
1942}
1943
1944void ExtensionService::UnloadAllExtensions() {
1945  profile_->GetExtensionSpecialStoragePolicy()->RevokeRightsForAllExtensions();
1946
1947  extensions_.Clear();
1948  disabled_extensions_.Clear();
1949  terminated_extensions_.Clear();
1950  extension_runtime_data_.clear();
1951
1952  // TODO(erikkay) should there be a notification for this?  We can't use
1953  // EXTENSION_UNLOADED since that implies that the extension has been disabled
1954  // or uninstalled, and UnloadAll is just part of shutdown.
1955}
1956
1957void ExtensionService::ReloadExtensions() {
1958  UnloadAllExtensions();
1959  component_loader_->LoadAll();
1960  extensions::InstalledLoader(this).LoadAllExtensions();
1961  // Don't call SetReadyAndNotifyListeners() since tests call this multiple
1962  // times.
1963}
1964
1965void ExtensionService::GarbageCollectExtensions() {
1966  if (extension_prefs_->pref_service()->ReadOnly())
1967    return;
1968
1969  if (pending_extension_manager()->HasPendingExtensions()) {
1970    // Don't garbage collect while there are pending installations, which may
1971    // be using the temporary installation directory. Try to garbage collect
1972    // again later.
1973    base::MessageLoop::current()->PostDelayedTask(
1974        FROM_HERE,
1975        base::Bind(&ExtensionService::GarbageCollectExtensions, AsWeakPtr()),
1976        base::TimeDelta::FromSeconds(kGarbageCollectRetryDelay));
1977    return;
1978  }
1979
1980  scoped_ptr<extensions::ExtensionPrefs::ExtensionsInfo> info(
1981      extension_prefs_->GetInstalledExtensionsInfo());
1982
1983  std::multimap<std::string, base::FilePath> extension_paths;
1984  for (size_t i = 0; i < info->size(); ++i)
1985    extension_paths.insert(std::make_pair(info->at(i)->extension_id,
1986                                          info->at(i)->extension_path));
1987
1988  info = extension_prefs_->GetAllDelayedInstallInfo();
1989  for (size_t i = 0; i < info->size(); ++i)
1990    extension_paths.insert(std::make_pair(info->at(i)->extension_id,
1991                                          info->at(i)->extension_path));
1992
1993  if (!GetFileTaskRunner()->PostTask(
1994          FROM_HERE,
1995          base::Bind(
1996              &extension_file_util::GarbageCollectExtensions,
1997              install_directory_,
1998              extension_paths))) {
1999    NOTREACHED();
2000  }
2001
2002#if defined(ENABLE_THEMES)
2003  // Also garbage-collect themes.  We check |profile_| to be
2004  // defensive; in the future, we may call GarbageCollectExtensions()
2005  // from somewhere other than Init() (e.g., in a timer).
2006  if (profile_) {
2007    ThemeServiceFactory::GetForProfile(profile_)->RemoveUnusedThemes();
2008  }
2009#endif
2010}
2011
2012void ExtensionService::SyncExtensionChangeIfNeeded(const Extension& extension) {
2013  if (app_sync_bundle_.HandlesApp(extension)) {
2014    app_sync_bundle_.SyncChangeIfNeeded(extension);
2015  } else if (extension_sync_bundle_.HandlesExtension(extension)) {
2016    extension_sync_bundle_.SyncChangeIfNeeded(extension);
2017  }
2018}
2019
2020void ExtensionService::SetReadyAndNotifyListeners() {
2021  ready_->Signal();
2022  content::NotificationService::current()->Notify(
2023      chrome::NOTIFICATION_EXTENSIONS_READY,
2024      content::Source<Profile>(profile_),
2025      content::NotificationService::NoDetails());
2026}
2027
2028void ExtensionService::OnLoadedInstalledExtensions() {
2029  if (updater_)
2030    updater_->Start();
2031
2032  OnBlacklistUpdated();
2033}
2034
2035void ExtensionService::AddExtension(const Extension* extension) {
2036  // TODO(jstritar): We may be able to get rid of this branch by overriding the
2037  // default extension state to DISABLED when the --disable-extensions flag
2038  // is set (http://crbug.com/29067).
2039  if (!extensions_enabled() &&
2040      !extension->is_theme() &&
2041      extension->location() != Manifest::COMPONENT &&
2042      !Manifest::IsExternalLocation(extension->location())) {
2043    return;
2044  }
2045
2046  bool is_extension_upgrade = false;
2047  if (const Extension* old = GetInstalledExtension(extension->id())) {
2048    is_extension_upgrade = true;
2049    DCHECK_NE(extension, old);
2050    // Other than for unpacked extensions, CrxInstaller should have guaranteed
2051    // that we aren't downgrading.
2052    if (!Manifest::IsUnpackedLocation(extension->location()))
2053      CHECK_GE(extension->version()->CompareTo(*(old->version())), 0);
2054  }
2055  SetBeingUpgraded(extension, is_extension_upgrade);
2056
2057  // The extension is now loaded, remove its data from unloaded extension map.
2058  unloaded_extension_paths_.erase(extension->id());
2059
2060  // If a terminated extension is loaded, remove it from the terminated list.
2061  UntrackTerminatedExtension(extension->id());
2062
2063  // If the extension was disabled for a reload, then enable it.
2064  bool reloading = reloading_extensions_.erase(extension->id()) > 0;
2065
2066  // Check if the extension's privileges have changed and mark the
2067  // extension disabled if necessary.
2068  CheckPermissionsIncrease(extension, is_extension_upgrade);
2069
2070  if (is_extension_upgrade && !reloading) {
2071    // To upgrade an extension in place, unload the old one and then load the
2072    // new one.  ReloadExtension disables the extension, which is sufficient.
2073    UnloadExtension(extension->id(), extension_misc::UNLOAD_REASON_UPDATE);
2074  }
2075
2076  if (extension_prefs_->IsExtensionBlacklisted(extension->id())) {
2077    // Only prefs is checked for the blacklist. We rely on callers to check the
2078    // blacklist before calling into here, e.g. CrxInstaller checks before
2079    // installation, we check when loading installed extensions.
2080    blacklisted_extensions_.Insert(extension);
2081  } else if (!reloading &&
2082             extension_prefs_->IsExtensionDisabled(extension->id())) {
2083    disabled_extensions_.Insert(extension);
2084    SyncExtensionChangeIfNeeded(*extension);
2085    content::NotificationService::current()->Notify(
2086        chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED,
2087        content::Source<Profile>(profile_),
2088        content::Details<const Extension>(extension));
2089
2090    // Show the extension disabled error if a permissions increase was the
2091    // only reason it was disabled.
2092    if (extension_prefs_->GetDisableReasons(extension->id()) ==
2093        Extension::DISABLE_PERMISSIONS_INCREASE) {
2094      extensions::AddExtensionDisabledError(this, extension);
2095    }
2096  } else if (reloading) {
2097    // Replace the old extension with the new version.
2098    CHECK(!disabled_extensions_.Insert(extension));
2099    EnableExtension(extension->id());
2100    DoPostLoadTasks(extension);
2101  } else {
2102    // All apps that are displayed in the launcher are ordered by their ordinals
2103    // so we must ensure they have valid ordinals.
2104    if (extension->RequiresSortOrdinal()) {
2105      if (!extension->ShouldDisplayInNewTabPage()) {
2106        extension_prefs_->extension_sorting()->MarkExtensionAsHidden(
2107            extension->id());
2108      }
2109      extension_prefs_->extension_sorting()->EnsureValidOrdinals(
2110          extension->id(), syncer::StringOrdinal());
2111    }
2112
2113    extensions_.Insert(extension);
2114    SyncExtensionChangeIfNeeded(*extension);
2115    NotifyExtensionLoaded(extension);
2116    DoPostLoadTasks(extension);
2117  }
2118  SetBeingUpgraded(extension, false);
2119}
2120
2121void ExtensionService::AddComponentExtension(const Extension* extension) {
2122  const std::string old_version_string(
2123      extension_prefs_->GetVersionString(extension->id()));
2124  const Version old_version(old_version_string);
2125
2126  if (!old_version.IsValid() || !old_version.Equals(*extension->version())) {
2127    VLOG(1) << "Component extension " << extension->name() << " ("
2128        << extension->id() << ") installing/upgrading from '"
2129        << old_version_string << "' to " << extension->version()->GetString();
2130
2131    AddNewOrUpdatedExtension(extension,
2132                             Extension::ENABLED_COMPONENT,
2133                             syncer::StringOrdinal());
2134    return;
2135  }
2136
2137  AddExtension(extension);
2138}
2139
2140void ExtensionService::UpdateActivePermissions(const Extension* extension) {
2141  // If the extension has used the optional permissions API, it will have a
2142  // custom set of active permissions defined in the extension prefs. Here,
2143  // we update the extension's active permissions based on the prefs.
2144  scoped_refptr<PermissionSet> active_permissions =
2145      extension_prefs()->GetActivePermissions(extension->id());
2146
2147  if (active_permissions) {
2148    // We restrict the active permissions to be within the bounds defined in the
2149    // extension's manifest.
2150    //  a) active permissions must be a subset of optional + default permissions
2151    //  b) active permissions must contains all default permissions
2152    scoped_refptr<PermissionSet> total_permissions =
2153        PermissionSet::CreateUnion(
2154            extensions::PermissionsData::GetRequiredPermissions(extension),
2155            extensions::PermissionsData::GetOptionalPermissions(extension));
2156
2157    // Make sure the active permissions contain no more than optional + default.
2158    scoped_refptr<PermissionSet> adjusted_active =
2159        PermissionSet::CreateIntersection(
2160            total_permissions.get(), active_permissions.get());
2161
2162    // Make sure the active permissions contain the default permissions.
2163    adjusted_active = PermissionSet::CreateUnion(
2164        extensions::PermissionsData::GetRequiredPermissions(extension),
2165        adjusted_active.get());
2166
2167    extensions::PermissionsUpdater perms_updater(profile());
2168    perms_updater.UpdateActivePermissions(extension, adjusted_active);
2169  }
2170}
2171
2172void ExtensionService::CheckPermissionsIncrease(const Extension* extension,
2173                                                bool is_extension_upgrade) {
2174  UpdateActivePermissions(extension);
2175
2176  // We keep track of all permissions the user has granted each extension.
2177  // This allows extensions to gracefully support backwards compatibility
2178  // by including unknown permissions in their manifests. When the user
2179  // installs the extension, only the recognized permissions are recorded.
2180  // When the unknown permissions become recognized (e.g., through browser
2181  // upgrade), we can prompt the user to accept these new permissions.
2182  // Extensions can also silently upgrade to less permissions, and then
2183  // silently upgrade to a version that adds these permissions back.
2184  //
2185  // For example, pretend that Chrome 10 includes a permission "omnibox"
2186  // for an API that adds suggestions to the omnibox. An extension can
2187  // maintain backwards compatibility while still having "omnibox" in the
2188  // manifest. If a user installs the extension on Chrome 9, the browser
2189  // will record the permissions it recognized, not including "omnibox."
2190  // When upgrading to Chrome 10, "omnibox" will be recognized and Chrome
2191  // will disable the extension and prompt the user to approve the increase
2192  // in privileges. The extension could then release a new version that
2193  // removes the "omnibox" permission. When the user upgrades, Chrome will
2194  // still remember that "omnibox" had been granted, so that if the
2195  // extension once again includes "omnibox" in an upgrade, the extension
2196  // can upgrade without requiring this user's approval.
2197  int disable_reasons = extension_prefs_->GetDisableReasons(extension->id());
2198
2199  bool auto_grant_permission =
2200      (!is_extension_upgrade && extension->was_installed_by_default()) ||
2201      chrome::IsRunningInForcedAppMode();
2202  // Silently grant all active permissions to default apps only on install.
2203  // After install they should behave like other apps.
2204  // Silently grant all active permissions to apps install in kiosk mode on both
2205  // install and update.
2206  if (auto_grant_permission)
2207    GrantPermissions(extension);
2208
2209  bool is_privilege_increase = false;
2210  // We only need to compare the granted permissions to the current permissions
2211  // if the extension is not allowed to silently increase its permissions.
2212  if (!extensions::PermissionsData::CanSilentlyIncreasePermissions(extension) &&
2213      !auto_grant_permission) {
2214    // Add all the recognized permissions if the granted permissions list
2215    // hasn't been initialized yet.
2216    scoped_refptr<PermissionSet> granted_permissions =
2217        extension_prefs_->GetGrantedPermissions(extension->id());
2218    CHECK(granted_permissions.get());
2219
2220    // Here, we check if an extension's privileges have increased in a manner
2221    // that requires the user's approval. This could occur because the browser
2222    // upgraded and recognized additional privileges, or an extension upgrades
2223    // to a version that requires additional privileges.
2224    is_privilege_increase =
2225        granted_permissions->HasLessPrivilegesThan(
2226            extension->GetActivePermissions());
2227  }
2228
2229  if (is_extension_upgrade) {
2230    // If the extension was already disabled, suppress any alerts for becoming
2231    // disabled on permissions increase.
2232    bool previously_disabled =
2233        extension_prefs_->IsExtensionDisabled(extension->id());
2234    // Legacy disabled extensions do not have a disable reason. Infer that if
2235    // there was no permission increase, it was likely disabled by the user.
2236    if (previously_disabled && disable_reasons == Extension::DISABLE_NONE &&
2237        !extension_prefs_->DidExtensionEscalatePermissions(extension->id())) {
2238      disable_reasons |= Extension::DISABLE_USER_ACTION;
2239    }
2240    // Extensions that came to us disabled from sync need a similar inference,
2241    // except based on the new version's permissions.
2242    if (previously_disabled &&
2243        disable_reasons == Extension::DISABLE_UNKNOWN_FROM_SYNC) {
2244      // Remove the DISABLE_UNKNOWN_FROM_SYNC reason.
2245      extension_prefs_->ClearDisableReasons(extension->id());
2246      if (!is_privilege_increase)
2247        disable_reasons |= Extension::DISABLE_USER_ACTION;
2248    }
2249    disable_reasons &= ~Extension::DISABLE_UNKNOWN_FROM_SYNC;
2250  }
2251
2252  // Extension has changed permissions significantly. Disable it. A
2253  // notification should be sent by the caller.
2254  if (is_privilege_increase) {
2255    disable_reasons |= Extension::DISABLE_PERMISSIONS_INCREASE;
2256    if (!extension_prefs_->DidExtensionEscalatePermissions(extension->id())) {
2257      RecordPermissionMessagesHistogram(
2258          extension, "Extensions.Permissions_AutoDisable");
2259    }
2260    extension_prefs_->SetExtensionState(extension->id(), Extension::DISABLED);
2261    extension_prefs_->SetDidExtensionEscalatePermissions(extension, true);
2262  }
2263  if (disable_reasons != Extension::DISABLE_NONE) {
2264    extension_prefs_->AddDisableReason(
2265        extension->id(),
2266        static_cast<Extension::DisableReason>(disable_reasons));
2267  }
2268}
2269
2270void ExtensionService::UpdateActiveExtensionsInCrashReporter() {
2271  std::set<std::string> extension_ids;
2272  for (ExtensionSet::const_iterator iter = extensions_.begin();
2273       iter != extensions_.end(); ++iter) {
2274    const Extension* extension = *iter;
2275    if (!extension->is_theme() && extension->location() != Manifest::COMPONENT)
2276      extension_ids.insert(extension->id());
2277  }
2278
2279  child_process_logging::SetActiveExtensions(extension_ids);
2280}
2281
2282void ExtensionService::ScheduleLaunchOnLoad(const std::string& extension_id) {
2283  on_load_events_[extension_id] = EVENT_LAUNCHED;
2284}
2285
2286void ExtensionService::OnExtensionInstalled(
2287    const Extension* extension,
2288    const syncer::StringOrdinal& page_ordinal,
2289    bool has_requirement_errors,
2290    bool wait_for_idle) {
2291  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2292
2293  const std::string& id = extension->id();
2294  bool initial_enable = ShouldEnableOnInstall(extension);
2295  const extensions::PendingExtensionInfo* pending_extension_info = NULL;
2296  if ((pending_extension_info = pending_extension_manager()->GetById(id))) {
2297    if (!pending_extension_info->ShouldAllowInstall(*extension)) {
2298      pending_extension_manager()->Remove(id);
2299
2300      LOG(WARNING) << "ShouldAllowInstall() returned false for "
2301                   << id << " of type " << extension->GetType()
2302                   << " and update URL "
2303                   << extensions::ManifestURL::GetUpdateURL(extension).spec()
2304                   << "; not installing";
2305
2306      content::NotificationService::current()->Notify(
2307          chrome::NOTIFICATION_EXTENSION_INSTALL_NOT_ALLOWED,
2308          content::Source<Profile>(profile_),
2309          content::Details<const Extension>(extension));
2310
2311      // Delete the extension directory since we're not going to
2312      // load it.
2313      if (!GetFileTaskRunner()->PostTask(
2314              FROM_HERE,
2315              base::Bind(&extension_file_util::DeleteFile,
2316                         extension->path(), true))) {
2317        NOTREACHED();
2318      }
2319      return;
2320    }
2321
2322    pending_extension_manager()->Remove(id);
2323  } else {
2324    // We explicitly want to re-enable an uninstalled external
2325    // extension; if we're here, that means the user is manually
2326    // installing the extension.
2327    if (IsExternalExtensionUninstalled(id)) {
2328      initial_enable = true;
2329    }
2330  }
2331
2332  // Unsupported requirements overrides the management policy.
2333  if (has_requirement_errors) {
2334    initial_enable = false;
2335    extension_prefs_->AddDisableReason(
2336        id, Extension::DISABLE_UNSUPPORTED_REQUIREMENT);
2337  // If the extension was disabled because of unsupported requirements but
2338  // now supports all requirements after an update and there are not other
2339  // disable reasons, enable it.
2340  } else if (extension_prefs_->GetDisableReasons(id) ==
2341      Extension::DISABLE_UNSUPPORTED_REQUIREMENT) {
2342    initial_enable = true;
2343    extension_prefs_->ClearDisableReasons(id);
2344  }
2345
2346  if (!GetInstalledExtension(extension->id())) {
2347    UMA_HISTOGRAM_ENUMERATION("Extensions.InstallType",
2348                              extension->GetType(), 100);
2349    UMA_HISTOGRAM_ENUMERATION("Extensions.InstallSource",
2350                              extension->location(), Manifest::NUM_LOCATIONS);
2351    RecordPermissionMessagesHistogram(
2352        extension, "Extensions.Permissions_Install");
2353  } else {
2354    UMA_HISTOGRAM_ENUMERATION("Extensions.UpdateType",
2355                              extension->GetType(), 100);
2356    UMA_HISTOGRAM_ENUMERATION("Extensions.UpdateSource",
2357                              extension->location(), Manifest::NUM_LOCATIONS);
2358  }
2359
2360  // Certain extension locations are specific enough that we can
2361  // auto-acknowledge any extension that came from one of them.
2362  if (extension->location() == Manifest::EXTERNAL_POLICY_DOWNLOAD)
2363    AcknowledgeExternalExtension(extension->id());
2364  const Extension::State initial_state =
2365      initial_enable ? Extension::ENABLED : Extension::DISABLED;
2366  if (ShouldDelayExtensionUpdate(id, wait_for_idle)) {
2367    extension_prefs_->SetDelayedInstallInfo(extension, initial_state,
2368                                            page_ordinal);
2369
2370    // Transfer ownership of |extension|.
2371    delayed_updates_for_idle_.Insert(extension);
2372
2373    // Notify extension of available update.
2374    extensions::RuntimeEventRouter::DispatchOnUpdateAvailableEvent(
2375        profile_, id, extension->manifest()->value());
2376
2377    // Notify observers that app update is available.
2378    FOR_EACH_OBSERVER(extensions::UpdateObserver, update_observers_,
2379                      OnAppUpdateAvailable(extension->id()));
2380    return;
2381  }
2382
2383  if (installs_delayed()) {
2384    extension_prefs_->SetDelayedInstallInfo(extension, initial_state,
2385                                            page_ordinal);
2386    delayed_installs_.Insert(extension);
2387  } else {
2388    AddNewOrUpdatedExtension(extension, initial_state, page_ordinal);
2389  }
2390}
2391
2392void ExtensionService::AddNewOrUpdatedExtension(
2393    const Extension* extension,
2394    Extension::State initial_state,
2395    const syncer::StringOrdinal& page_ordinal) {
2396  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2397
2398  extension_prefs_->OnExtensionInstalled(
2399      extension,
2400      initial_state,
2401      page_ordinal);
2402
2403  FinishInstallation(extension);
2404}
2405
2406void ExtensionService::MaybeFinishDelayedInstallation(
2407    const std::string& extension_id) {
2408  // Check if the extension already got updated.
2409  if (!delayed_updates_for_idle_.Contains(extension_id))
2410    return;
2411  // Check if the extension is idle.
2412  if (!IsExtensionIdle(extension_id))
2413    return;
2414
2415  FinishDelayedInstallation(extension_id);
2416}
2417
2418void ExtensionService::FinishDelayedInstallation(
2419    const std::string& extension_id) {
2420  scoped_refptr<const Extension> extension(
2421      GetPendingExtensionUpdate(extension_id));
2422  CHECK(extension);
2423  delayed_updates_for_idle_.Remove(extension_id);
2424
2425  if (!extension_prefs_->FinishDelayedInstallInfo(extension_id))
2426    NOTREACHED();
2427
2428  FinishInstallation(extension);
2429}
2430
2431void ExtensionService::FinishInstallation(const Extension* extension) {
2432  const extensions::Extension* existing_extension =
2433      GetInstalledExtension(extension->id());
2434  bool is_update = false;
2435  std::string old_name;
2436  if (existing_extension) {
2437    is_update = true;
2438    old_name = existing_extension->name();
2439  }
2440  extensions::InstalledExtensionInfo details(extension, is_update, old_name);
2441  content::NotificationService::current()->Notify(
2442      chrome::NOTIFICATION_EXTENSION_INSTALLED,
2443      content::Source<Profile>(profile_),
2444      content::Details<const extensions::InstalledExtensionInfo>(&details));
2445
2446  bool unacknowledged_external = IsUnacknowledgedExternalExtension(extension);
2447
2448  // Unpacked extensions default to allowing file access, but if that has been
2449  // overridden, don't reset the value.
2450  if (Manifest::ShouldAlwaysAllowFileAccess(extension->location()) &&
2451      !extension_prefs_->HasAllowFileAccessSetting(extension->id())) {
2452    extension_prefs_->SetAllowFileAccess(extension->id(), true);
2453  }
2454
2455  AddExtension(extension);
2456
2457#if defined(ENABLE_THEMES)
2458  // We do this here since AddExtension() is always called on browser startup,
2459  // and we only really care about the last theme installed.
2460  // If that ever changes and we have to move this code somewhere
2461  // else, it should be somewhere that's not in the startup path.
2462  if (extension->is_theme() && extensions_.GetByID(extension->id())) {
2463    DCHECK_EQ(extensions_.GetByID(extension->id()), extension);
2464    // Now that the theme extension is visible from outside the
2465    // ExtensionService, notify the ThemeService about the
2466    // newly-installed theme.
2467    ThemeServiceFactory::GetForProfile(profile_)->SetTheme(extension);
2468  }
2469#endif
2470
2471  // If this is a new external extension that was disabled, alert the user
2472  // so he can reenable it. We do this last so that it has already been
2473  // added to our list of extensions.
2474  if (unacknowledged_external) {
2475    UpdateExternalExtensionAlert();
2476    UMA_HISTOGRAM_ENUMERATION("Extensions.ExternalExtensionEvent",
2477                              EXTERNAL_EXTENSION_INSTALLED,
2478                              EXTERNAL_EXTENSION_BUCKET_BOUNDARY);
2479  }
2480}
2481
2482const Extension* ExtensionService::GetPendingExtensionUpdate(
2483    const std::string& id) const {
2484  return delayed_updates_for_idle_.GetByID(id);
2485}
2486
2487void ExtensionService::TrackTerminatedExtension(const Extension* extension) {
2488  if (!terminated_extensions_.Contains(extension->id()))
2489    terminated_extensions_.Insert(make_scoped_refptr(extension));
2490
2491  UnloadExtension(extension->id(), extension_misc::UNLOAD_REASON_TERMINATE);
2492}
2493
2494void ExtensionService::UntrackTerminatedExtension(const std::string& id) {
2495  std::string lowercase_id = StringToLowerASCII(id);
2496  terminated_extensions_.Remove(lowercase_id);
2497}
2498
2499const Extension* ExtensionService::GetTerminatedExtension(
2500    const std::string& id) const {
2501  return GetExtensionById(id, INCLUDE_TERMINATED);
2502}
2503
2504const Extension* ExtensionService::GetInstalledExtension(
2505    const std::string& id) const {
2506  int include_mask = INCLUDE_ENABLED |
2507                     INCLUDE_DISABLED |
2508                     INCLUDE_TERMINATED |
2509                     INCLUDE_BLACKLISTED;
2510  return GetExtensionById(id, include_mask);
2511}
2512
2513bool ExtensionService::ExtensionBindingsAllowed(const GURL& url) {
2514  // Allow bindings for all packaged extensions and component hosted apps.
2515  const Extension* extension = extensions_.GetExtensionOrAppByURL(
2516      ExtensionURLInfo(url));
2517  return extension && (!extension->is_hosted_app() ||
2518                       extension->location() == Manifest::COMPONENT);
2519}
2520
2521bool ExtensionService::ShouldBlockUrlInBrowserTab(GURL* url) {
2522  const Extension* extension = extensions_.GetExtensionOrAppByURL(
2523      ExtensionURLInfo(*url));
2524  if (extension && extension->is_platform_app()) {
2525    *url = GURL(chrome::kExtensionInvalidRequestURL);
2526    return true;
2527  }
2528
2529  return false;
2530}
2531
2532bool ExtensionService::OnExternalExtensionFileFound(
2533         const std::string& id,
2534         const Version* version,
2535         const base::FilePath& path,
2536         Manifest::Location location,
2537         int creation_flags,
2538         bool mark_acknowledged) {
2539  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
2540  CHECK(Extension::IdIsValid(id));
2541  if (extension_prefs_->IsExternalExtensionUninstalled(id))
2542    return false;
2543
2544  // Before even bothering to unpack, check and see if we already have this
2545  // version. This is important because these extensions are going to get
2546  // installed on every startup.
2547  const Extension* existing = GetExtensionById(id, true);
2548
2549  if (existing) {
2550    // The default apps will have the location set as INTERNAL. Since older
2551    // default apps are installed as EXTERNAL, we override them. However, if the
2552    // app is already installed as internal, then do the version check.
2553    // TODO(grv) : Remove after Q1-2013.
2554    bool is_default_apps_migration =
2555        (location == Manifest::INTERNAL &&
2556         Manifest::IsExternalLocation(existing->location()));
2557
2558    if (!is_default_apps_migration) {
2559      DCHECK(version);
2560
2561      switch (existing->version()->CompareTo(*version)) {
2562        case -1:  // existing version is older, we should upgrade
2563          break;
2564        case 0:  // existing version is same, do nothing
2565          return false;
2566        case 1:  // existing version is newer, uh-oh
2567          LOG(WARNING) << "Found external version of extension " << id
2568                       << "that is older than current version. Current version "
2569                       << "is: " << existing->VersionString() << ". New "
2570                       << "version is: " << version->GetString()
2571                       << ". Keeping current version.";
2572          return false;
2573      }
2574    }
2575  }
2576
2577  // If the extension is already pending, don't start an install.
2578  if (!pending_extension_manager()->AddFromExternalFile(
2579          id, location, *version)) {
2580    return false;
2581  }
2582
2583  // no client (silent install)
2584  scoped_refptr<CrxInstaller> installer(CrxInstaller::Create(this, NULL));
2585  installer->set_install_source(location);
2586  installer->set_expected_id(id);
2587  installer->set_expected_version(*version);
2588  installer->set_install_cause(extension_misc::INSTALL_CAUSE_EXTERNAL_FILE);
2589  installer->set_creation_flags(creation_flags);
2590#if defined(OS_CHROMEOS)
2591  extensions::InstallLimiter::Get(profile_)->Add(installer, path);
2592#else
2593  installer->InstallCrx(path);
2594#endif
2595
2596  // Depending on the source, a new external extension might not need a user
2597  // notification on installation. For such extensions, mark them acknowledged
2598  // now to suppress the notification.
2599  if (mark_acknowledged)
2600    AcknowledgeExternalExtension(id);
2601
2602  return true;
2603}
2604
2605void ExtensionService::ReportExtensionLoadError(
2606    const base::FilePath& extension_path,
2607    const std::string &error,
2608    bool be_noisy) {
2609  content::NotificationService::current()->Notify(
2610      chrome::NOTIFICATION_EXTENSION_LOAD_ERROR,
2611      content::Source<Profile>(profile_),
2612      content::Details<const std::string>(&error));
2613
2614  std::string path_str = UTF16ToUTF8(extension_path.LossyDisplayName());
2615  string16 message = UTF8ToUTF16(base::StringPrintf(
2616      "Could not load extension from '%s'. %s",
2617      path_str.c_str(), error.c_str()));
2618  ExtensionErrorReporter::GetInstance()->ReportError(message, be_noisy);
2619}
2620
2621void ExtensionService::DidCreateRenderViewForBackgroundPage(
2622    extensions::ExtensionHost* host) {
2623  OrphanedDevTools::iterator iter =
2624      orphaned_dev_tools_.find(host->extension_id());
2625  if (iter == orphaned_dev_tools_.end())
2626    return;
2627
2628  DevToolsAgentHost::ConnectRenderViewHost(iter->second,
2629                                           host->render_view_host());
2630  orphaned_dev_tools_.erase(iter);
2631}
2632
2633void ExtensionService::Observe(int type,
2634                               const content::NotificationSource& source,
2635                               const content::NotificationDetails& details) {
2636  switch (type) {
2637    case chrome::NOTIFICATION_APP_TERMINATING:
2638      // Shutdown has started. Don't start any more extension installs.
2639      // (We cannot use ExtensionService::Shutdown() for this because it
2640      // happens too late in browser teardown.)
2641      browser_terminating_ = true;
2642      break;
2643    case chrome::NOTIFICATION_EXTENSION_PROCESS_TERMINATED: {
2644      if (profile_ !=
2645          content::Source<Profile>(source).ptr()->GetOriginalProfile()) {
2646        break;
2647      }
2648
2649      extensions::ExtensionHost* host =
2650          content::Details<extensions::ExtensionHost>(details).ptr();
2651
2652      // Mark the extension as terminated and Unload it. We want it to
2653      // be in a consistent state: either fully working or not loaded
2654      // at all, but never half-crashed.  We do it in a PostTask so
2655      // that other handlers of this notification will still have
2656      // access to the Extension and ExtensionHost.
2657      base::MessageLoop::current()->PostTask(
2658          FROM_HERE,
2659          base::Bind(
2660              &ExtensionService::TrackTerminatedExtension,
2661              AsWeakPtr(),
2662              host->extension()));
2663      break;
2664    }
2665    case content::NOTIFICATION_RENDERER_PROCESS_CREATED: {
2666      content::RenderProcessHost* process =
2667          content::Source<content::RenderProcessHost>(source).ptr();
2668      Profile* host_profile =
2669          Profile::FromBrowserContext(process->GetBrowserContext());
2670      if (!profile_->IsSameProfile(host_profile->GetOriginalProfile()))
2671          break;
2672
2673      // Extensions need to know the channel for API restrictions.
2674      process->Send(new ExtensionMsg_SetChannel(
2675          extensions::Feature::GetCurrentChannel()));
2676
2677      // Valid extension function names, used to setup bindings in renderer.
2678      std::vector<std::string> function_names;
2679      ExtensionFunctionDispatcher::GetAllFunctionNames(&function_names);
2680      process->Send(new ExtensionMsg_SetFunctionNames(function_names));
2681
2682      // Scripting whitelist. This is modified by tests and must be communicated
2683      // to renderers.
2684      process->Send(new ExtensionMsg_SetScriptingWhitelist(
2685          *Extension::GetScriptingWhitelist()));
2686
2687      // Loaded extensions.
2688      std::vector<ExtensionMsg_Loaded_Params> loaded_extensions;
2689      for (ExtensionSet::const_iterator iter = extensions_.begin();
2690           iter != extensions_.end(); ++iter) {
2691        // Renderers don't need to know about themes.
2692        if (!(*iter)->is_theme())
2693          loaded_extensions.push_back(ExtensionMsg_Loaded_Params(*iter));
2694      }
2695      process->Send(new ExtensionMsg_Loaded(loaded_extensions));
2696      break;
2697    }
2698    case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: {
2699      content::RenderProcessHost* process =
2700          content::Source<content::RenderProcessHost>(source).ptr();
2701      Profile* host_profile =
2702          Profile::FromBrowserContext(process->GetBrowserContext());
2703      if (!profile_->IsSameProfile(host_profile->GetOriginalProfile()))
2704          break;
2705
2706      process_map_.RemoveAllFromProcess(process->GetID());
2707      BrowserThread::PostTask(
2708          BrowserThread::IO, FROM_HERE,
2709          base::Bind(&ExtensionInfoMap::UnregisterAllExtensionsInProcess,
2710                     system_->info_map(),
2711                     process->GetID()));
2712      break;
2713    }
2714    case chrome::NOTIFICATION_IMPORT_FINISHED: {
2715      InitAfterImport();
2716      break;
2717    }
2718    case chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED: {
2719      extensions::ExtensionHost* host =
2720          content::Details<extensions::ExtensionHost>(details).ptr();
2721      std::string extension_id = host->extension_id();
2722      if (delayed_updates_for_idle_.Contains(extension_id)) {
2723        // We were waiting for this extension to become idle, it now might have,
2724        // so maybe finish installation.
2725        base::MessageLoop::current()->PostDelayedTask(
2726            FROM_HERE,
2727            base::Bind(&ExtensionService::MaybeFinishDelayedInstallation,
2728                       AsWeakPtr(), extension_id),
2729            base::TimeDelta::FromSeconds(kUpdateIdleDelay));
2730      }
2731      break;
2732    }
2733    case chrome::NOTIFICATION_UPGRADE_RECOMMENDED: {
2734      // Notify extensions that chrome update is available.
2735      extensions::RuntimeEventRouter::DispatchOnBrowserUpdateAvailableEvent(
2736          profile_);
2737
2738      // Notify observers that chrome update is available.
2739      FOR_EACH_OBSERVER(extensions::UpdateObserver, update_observers_,
2740                        OnChromeUpdateAvailable());
2741      break;
2742    }
2743
2744    default:
2745      NOTREACHED() << "Unexpected notification type.";
2746  }
2747}
2748
2749void ExtensionService::OnExtensionInstallPrefChanged() {
2750  IdentifyAlertableExtensions();
2751  CheckManagementPolicy();
2752}
2753
2754bool ExtensionService::HasApps() const {
2755  return !GetAppIds().empty();
2756}
2757
2758ExtensionIdSet ExtensionService::GetAppIds() const {
2759  ExtensionIdSet result;
2760  for (ExtensionSet::const_iterator it = extensions_.begin();
2761       it != extensions_.end(); ++it) {
2762    if ((*it)->is_app() && (*it)->location() != Manifest::COMPONENT)
2763      result.insert((*it)->id());
2764  }
2765
2766  return result;
2767}
2768
2769bool ExtensionService::IsBackgroundPageReady(const Extension* extension) const {
2770  if (!extensions::BackgroundInfo::HasPersistentBackgroundPage(extension))
2771    return true;
2772  ExtensionRuntimeDataMap::const_iterator it =
2773      extension_runtime_data_.find(extension->id());
2774  return it == extension_runtime_data_.end() ? false :
2775                                               it->second.background_page_ready;
2776}
2777
2778void ExtensionService::SetBackgroundPageReady(const Extension* extension) {
2779  DCHECK(extensions::BackgroundInfo::HasBackgroundPage(extension));
2780  extension_runtime_data_[extension->id()].background_page_ready = true;
2781  content::NotificationService::current()->Notify(
2782      chrome::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY,
2783      content::Source<const Extension>(extension),
2784      content::NotificationService::NoDetails());
2785}
2786
2787void ExtensionService::InspectBackgroundPage(const Extension* extension) {
2788  DCHECK(extension);
2789
2790  ExtensionProcessManager* pm = system_->process_manager();
2791  extensions::LazyBackgroundTaskQueue* queue =
2792      system_->lazy_background_task_queue();
2793
2794  extensions::ExtensionHost* host =
2795      pm->GetBackgroundHostForExtension(extension->id());
2796  if (host) {
2797    InspectExtensionHost(host);
2798  } else {
2799    queue->AddPendingTask(
2800        profile_, extension->id(),
2801        base::Bind(&ExtensionService::InspectExtensionHost,
2802                    base::Unretained(this)));
2803  }
2804}
2805
2806bool ExtensionService::IsBeingUpgraded(const Extension* extension) const {
2807  ExtensionRuntimeDataMap::const_iterator it =
2808      extension_runtime_data_.find(extension->id());
2809  return it == extension_runtime_data_.end() ? false :
2810                                               it->second.being_upgraded;
2811}
2812
2813void ExtensionService::SetBeingUpgraded(const Extension* extension,
2814                                        bool value) {
2815  extension_runtime_data_[extension->id()].being_upgraded = value;
2816}
2817
2818bool ExtensionService::HasUsedWebRequest(const Extension* extension) const {
2819  ExtensionRuntimeDataMap::const_iterator it =
2820      extension_runtime_data_.find(extension->id());
2821  return it == extension_runtime_data_.end() ? false :
2822                                               it->second.has_used_webrequest;
2823}
2824
2825void ExtensionService::SetHasUsedWebRequest(const Extension* extension,
2826                                            bool value) {
2827  extension_runtime_data_[extension->id()].has_used_webrequest = value;
2828}
2829
2830void ExtensionService::RegisterNaClModule(const GURL& url,
2831                                          const std::string& mime_type) {
2832  NaClModuleInfo info;
2833  info.url = url;
2834  info.mime_type = mime_type;
2835
2836  DCHECK(FindNaClModule(url) == nacl_module_list_.end());
2837  nacl_module_list_.push_front(info);
2838}
2839
2840void ExtensionService::UnregisterNaClModule(const GURL& url) {
2841  NaClModuleInfoList::iterator iter = FindNaClModule(url);
2842  DCHECK(iter != nacl_module_list_.end());
2843  nacl_module_list_.erase(iter);
2844}
2845
2846void ExtensionService::UpdatePluginListWithNaClModules() {
2847  // An extension has been added which has a nacl_module component, which means
2848  // there is a MIME type that module wants to handle, so we need to add that
2849  // MIME type to plugins which handle NaCl modules in order to allow the
2850  // individual modules to handle these types.
2851  base::FilePath path;
2852  if (!PathService::Get(chrome::FILE_NACL_PLUGIN, &path))
2853    return;
2854  const content::PepperPluginInfo* pepper_info =
2855      PluginService::GetInstance()->GetRegisteredPpapiPluginInfo(path);
2856  if (!pepper_info)
2857    return;
2858
2859  std::vector<webkit::WebPluginMimeType>::const_iterator mime_iter;
2860  // Check each MIME type the plugins handle for the NaCl MIME type.
2861  for (mime_iter = pepper_info->mime_types.begin();
2862       mime_iter != pepper_info->mime_types.end(); ++mime_iter) {
2863    if (mime_iter->mime_type == kNaClPluginMimeType) {
2864      // This plugin handles "application/x-nacl".
2865
2866      PluginService::GetInstance()->
2867          UnregisterInternalPlugin(pepper_info->path);
2868
2869      webkit::WebPluginInfo info = pepper_info->ToWebPluginInfo();
2870
2871      for (ExtensionService::NaClModuleInfoList::const_iterator iter =
2872          nacl_module_list_.begin();
2873          iter != nacl_module_list_.end(); ++iter) {
2874        // Add the MIME type specified in the extension to this NaCl plugin,
2875        // With an extra "nacl" argument to specify the location of the NaCl
2876        // manifest file.
2877        webkit::WebPluginMimeType mime_type_info;
2878        mime_type_info.mime_type = iter->mime_type;
2879        mime_type_info.additional_param_names.push_back(UTF8ToUTF16("nacl"));
2880        mime_type_info.additional_param_values.push_back(
2881            UTF8ToUTF16(iter->url.spec()));
2882        info.mime_types.push_back(mime_type_info);
2883      }
2884
2885      PluginService::GetInstance()->RefreshPlugins();
2886      PluginService::GetInstance()->RegisterInternalPlugin(info, true);
2887      // This plugin has been modified, no need to check the rest of its
2888      // types, but continue checking other plugins.
2889      break;
2890    }
2891  }
2892}
2893
2894ExtensionService::NaClModuleInfoList::iterator
2895    ExtensionService::FindNaClModule(const GURL& url) {
2896  for (NaClModuleInfoList::iterator iter = nacl_module_list_.begin();
2897       iter != nacl_module_list_.end(); ++iter) {
2898    if (iter->url == url)
2899      return iter;
2900  }
2901  return nacl_module_list_.end();
2902}
2903
2904void ExtensionService::DoPostLoadTasks(const Extension* extension) {
2905  std::map<std::string, int>::iterator it =
2906      on_load_events_.find(extension->id());
2907  if (it == on_load_events_.end())
2908    return;
2909
2910  int events_to_fire = it->second;
2911  extensions::LazyBackgroundTaskQueue* queue =
2912      system_->lazy_background_task_queue();
2913  if (queue->ShouldEnqueueTask(profile(), extension)) {
2914    if (events_to_fire & EVENT_LAUNCHED)
2915      queue->AddPendingTask(profile(), extension->id(),
2916                            base::Bind(&ExtensionService::LaunchApplication));
2917    if (events_to_fire & EVENT_RESTARTED) {
2918      queue->AddPendingTask(profile(), extension->id(),
2919                            base::Bind(&ExtensionService::RestartApplication));
2920    }
2921  }
2922
2923  on_load_events_.erase(it);
2924}
2925
2926// static
2927void ExtensionService::LaunchApplication(
2928    extensions::ExtensionHost* extension_host) {
2929  if (!extension_host)
2930    return;
2931
2932#if !defined(OS_ANDROID)
2933  extensions::LaunchPlatformApp(extension_host->profile(),
2934                                extension_host->extension(),
2935                                NULL, base::FilePath());
2936#endif
2937}
2938
2939// static
2940void ExtensionService::RestartApplication(
2941    extensions::ExtensionHost* extension_host) {
2942  if (!extension_host)
2943    return;
2944
2945#if !defined(OS_ANDROID)
2946  extensions::RestartPlatformApp(
2947      extension_host->profile(), extension_host->extension());
2948#endif
2949}
2950
2951bool ExtensionService::HasShellWindows(const std::string& extension_id) {
2952  const Extension* current_extension = GetExtensionById(extension_id, false);
2953  return current_extension && current_extension->is_platform_app() &&
2954      !extensions::ShellWindowRegistry::Get(profile_)->
2955          GetShellWindowsForApp(extension_id).empty();
2956}
2957
2958void ExtensionService::InspectExtensionHost(
2959    extensions::ExtensionHost* host) {
2960  if (host)
2961    DevToolsWindow::OpenDevToolsWindow(host->render_view_host());
2962}
2963
2964bool ExtensionService::ShouldEnableOnInstall(const Extension* extension) {
2965  // Extensions installed by policy can't be disabled. So even if a previous
2966  // installation disabled the extension, make sure it is now enabled.
2967  if (system_->management_policy()->MustRemainEnabled(extension, NULL))
2968    return true;
2969
2970  if (extension_prefs_->IsExtensionDisabled(extension->id()))
2971    return false;
2972
2973  if (FeatureSwitch::prompt_for_external_extensions()->IsEnabled()) {
2974    // External extensions are initially disabled. We prompt the user before
2975    // enabling them. Hosted apps are excepted because they are not dangerous
2976    // (they need to be launched by the user anyway).
2977    if (extension->GetType() != Manifest::TYPE_HOSTED_APP &&
2978        Manifest::IsExternalLocation(extension->location()) &&
2979        !extension_prefs_->IsExternalExtensionAcknowledged(extension->id())) {
2980      return false;
2981    }
2982  }
2983
2984  return true;
2985}
2986
2987bool ExtensionService::IsExtensionIdle(const std::string& extension_id) const {
2988  ExtensionProcessManager* process_manager = system_->process_manager();
2989  DCHECK(process_manager);
2990  extensions::ExtensionHost* host =
2991      process_manager->GetBackgroundHostForExtension(extension_id);
2992  if (host)
2993    return false;
2994  return process_manager->GetRenderViewHostsForExtension(extension_id).empty();
2995}
2996
2997bool ExtensionService::ShouldDelayExtensionUpdate(
2998    const std::string& extension_id,
2999    bool wait_for_idle) const {
3000  const char kOnUpdateAvailableEvent[] = "runtime.onUpdateAvailable";
3001
3002  // If delayed updates are globally disabled, or just for this extension,
3003  // don't delay.
3004  if (!install_updates_when_idle_ || !wait_for_idle)
3005    return false;
3006
3007  const Extension* old = GetInstalledExtension(extension_id);
3008  // If there is no old extension, this is not an update, so don't delay.
3009  if (!old)
3010    return false;
3011
3012  if (extensions::BackgroundInfo::HasPersistentBackgroundPage(old)) {
3013    // Delay installation if the extension listens for the onUpdateAvailable
3014    // event.
3015    return system_->event_router()->ExtensionHasEventListener(
3016        extension_id, kOnUpdateAvailableEvent);
3017  } else {
3018    // Delay installation if the extension is not idle.
3019    return !IsExtensionIdle(extension_id);
3020  }
3021}
3022
3023void ExtensionService::GarbageCollectIsolatedStorage() {
3024  scoped_ptr<base::hash_set<base::FilePath> > active_paths(
3025      new base::hash_set<base::FilePath>());
3026  for (ExtensionSet::const_iterator it = extensions_.begin();
3027       it != extensions_.end(); ++it) {
3028    if (extensions::AppIsolationInfo::HasIsolatedStorage(*it)) {
3029      active_paths->insert(
3030          BrowserContext::GetStoragePartitionForSite(
3031              profile_,
3032              GetSiteForExtensionId((*it)->id()))->GetPath());
3033    }
3034  }
3035
3036  DCHECK(!installs_delayed());
3037  set_installs_delayed(true);
3038  BrowserContext::GarbageCollectStoragePartitions(
3039      profile_, active_paths.Pass(),
3040      base::Bind(&ExtensionService::OnGarbageCollectIsolatedStorageFinished,
3041                 AsWeakPtr()));
3042}
3043
3044void ExtensionService::OnGarbageCollectIsolatedStorageFinished() {
3045  set_installs_delayed(false);
3046  for (ExtensionSet::const_iterator it = delayed_installs_.begin();
3047       it != delayed_installs_.end();
3048       ++it) {
3049    FinishDelayedInstallation((*it)->id());
3050  }
3051  for (ExtensionSet::const_iterator it = delayed_updates_for_idle_.begin();
3052       it != delayed_updates_for_idle_.end();
3053       ++it) {
3054    MaybeFinishDelayedInstallation((*it)->id());
3055  }
3056  delayed_installs_.Clear();
3057}
3058
3059void ExtensionService::OnNeedsToGarbageCollectIsolatedStorage() {
3060  extension_prefs_->SetNeedsStorageGarbageCollection(true);
3061}
3062
3063void ExtensionService::OnBlacklistUpdated() {
3064  blacklist_->GetBlacklistedIDs(
3065      GenerateInstalledExtensionsSet()->GetIDs(),
3066      base::Bind(&ExtensionService::ManageBlacklist,
3067                 AsWeakPtr(),
3068                 blacklisted_extensions_.GetIDs()));
3069}
3070
3071void ExtensionService::ManageBlacklist(
3072    const std::set<std::string>& old_blacklisted_ids,
3073    const std::set<std::string>& new_blacklisted_ids) {
3074  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3075
3076  std::set<std::string> no_longer_blacklisted;
3077  std::set_difference(old_blacklisted_ids.begin(), old_blacklisted_ids.end(),
3078                      new_blacklisted_ids.begin(), new_blacklisted_ids.end(),
3079                      std::inserter(no_longer_blacklisted,
3080                                    no_longer_blacklisted.begin()));
3081  std::set<std::string> not_yet_blacklisted;
3082  std::set_difference(new_blacklisted_ids.begin(), new_blacklisted_ids.end(),
3083                      old_blacklisted_ids.begin(), old_blacklisted_ids.end(),
3084                      std::inserter(not_yet_blacklisted,
3085                                    not_yet_blacklisted.begin()));
3086
3087  for (std::set<std::string>::iterator it = no_longer_blacklisted.begin();
3088       it != no_longer_blacklisted.end(); ++it) {
3089    scoped_refptr<const Extension> extension =
3090        blacklisted_extensions_.GetByID(*it);
3091    DCHECK(extension);
3092    if (!extension)
3093      continue;
3094    blacklisted_extensions_.Remove(*it);
3095    AddExtension(extension);
3096    UMA_HISTOGRAM_ENUMERATION("ExtensionBlacklist.UnblacklistInstalled",
3097                              extension->location(), Manifest::NUM_LOCATIONS);
3098  }
3099
3100  for (std::set<std::string>::iterator it = not_yet_blacklisted.begin();
3101       it != not_yet_blacklisted.end(); ++it) {
3102    scoped_refptr<const Extension> extension = GetInstalledExtension(*it);
3103    DCHECK(extension);
3104    if (!extension)
3105      continue;
3106    blacklisted_extensions_.Insert(extension);
3107    UnloadExtension(*it, extension_misc::UNLOAD_REASON_BLACKLIST);
3108    UMA_HISTOGRAM_ENUMERATION("ExtensionBlacklist.BlacklistInstalled",
3109                              extension->location(), Manifest::NUM_LOCATIONS);
3110  }
3111
3112  IdentifyAlertableExtensions();
3113}
3114
3115void ExtensionService::AddUpdateObserver(extensions::UpdateObserver* observer) {
3116  update_observers_.AddObserver(observer);
3117}
3118
3119void ExtensionService::RemoveUpdateObserver(
3120    extensions::UpdateObserver* observer) {
3121  update_observers_.RemoveObserver(observer);
3122}
3123