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