1// Copyright 2014 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_system_impl.h"
6
7#include "base/base_switches.h"
8#include "base/bind.h"
9#include "base/command_line.h"
10#include "base/files/file_path.h"
11#include "base/memory/weak_ptr.h"
12#include "base/metrics/field_trial.h"
13#include "base/metrics/histogram.h"
14#include "base/strings/string_tokenizer.h"
15#include "base/strings/string_util.h"
16#include "chrome/browser/browser_process.h"
17#include "chrome/browser/content_settings/cookie_settings.h"
18#include "chrome/browser/extensions/blacklist.h"
19#include "chrome/browser/extensions/component_loader.h"
20#include "chrome/browser/extensions/declarative_user_script_master.h"
21#include "chrome/browser/extensions/error_console/error_console.h"
22#include "chrome/browser/extensions/extension_error_reporter.h"
23#include "chrome/browser/extensions/extension_management.h"
24#include "chrome/browser/extensions/extension_service.h"
25#include "chrome/browser/extensions/extension_system_factory.h"
26#include "chrome/browser/extensions/extension_util.h"
27#include "chrome/browser/extensions/extension_warning_badge_service.h"
28#include "chrome/browser/extensions/install_verifier.h"
29#include "chrome/browser/extensions/navigation_observer.h"
30#include "chrome/browser/extensions/shared_module_service.h"
31#include "chrome/browser/extensions/shared_user_script_master.h"
32#include "chrome/browser/extensions/state_store_notification_observer.h"
33#include "chrome/browser/extensions/unpacked_installer.h"
34#include "chrome/browser/profiles/profile.h"
35#include "chrome/browser/profiles/profile_manager.h"
36#include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
37#include "chrome/common/chrome_switches.h"
38#include "chrome/common/chrome_version_info.h"
39#include "chrome/common/extensions/extension_constants.h"
40#include "chrome/common/extensions/extension_file_util.h"
41#include "chrome/common/extensions/features/feature_channel.h"
42#include "chrome/common/extensions/manifest_url_handler.h"
43#include "content/public/browser/browser_thread.h"
44#include "content/public/browser/url_data_source.h"
45#include "extensions/browser/content_verifier.h"
46#include "extensions/browser/content_verifier_delegate.h"
47#include "extensions/browser/event_router.h"
48#include "extensions/browser/extension_pref_store.h"
49#include "extensions/browser/extension_pref_value_map.h"
50#include "extensions/browser/extension_pref_value_map_factory.h"
51#include "extensions/browser/extension_prefs.h"
52#include "extensions/browser/extension_registry.h"
53#include "extensions/browser/info_map.h"
54#include "extensions/browser/lazy_background_task_queue.h"
55#include "extensions/browser/management_policy.h"
56#include "extensions/browser/process_manager.h"
57#include "extensions/browser/quota_service.h"
58#include "extensions/browser/runtime_data.h"
59#include "extensions/browser/state_store.h"
60#include "extensions/browser/warning_service.h"
61#include "extensions/browser/warning_set.h"
62#include "extensions/common/constants.h"
63#include "extensions/common/extension.h"
64#include "extensions/common/extension_urls.h"
65#include "extensions/common/manifest.h"
66#include "net/base/escape.h"
67
68#if defined(ENABLE_NOTIFICATIONS)
69#include "chrome/browser/notifications/desktop_notification_service.h"
70#include "chrome/browser/notifications/desktop_notification_service_factory.h"
71#include "ui/message_center/notifier_settings.h"
72#endif
73
74#if defined(OS_CHROMEOS)
75#include "chrome/browser/app_mode/app_mode_utils.h"
76#include "chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.h"
77#include "chrome/browser/chromeos/policy/device_local_account.h"
78#include "chrome/browser/extensions/extension_assets_manager_chromeos.h"
79#include "chromeos/chromeos_switches.h"
80#include "chromeos/login/login_state.h"
81#include "components/user_manager/user.h"
82#include "components/user_manager/user_manager.h"
83#endif
84
85using content::BrowserThread;
86
87namespace {
88
89const char kContentVerificationExperimentName[] =
90    "ExtensionContentVerification";
91
92}  // namespace
93
94namespace extensions {
95
96//
97// ExtensionSystemImpl::Shared
98//
99
100ExtensionSystemImpl::Shared::Shared(Profile* profile)
101    : profile_(profile) {
102}
103
104ExtensionSystemImpl::Shared::~Shared() {
105}
106
107void ExtensionSystemImpl::Shared::InitPrefs() {
108  lazy_background_task_queue_.reset(new LazyBackgroundTaskQueue(profile_));
109  event_router_.reset(new EventRouter(profile_, ExtensionPrefs::Get(profile_)));
110  // Two state stores. The latter, which contains declarative rules, must be
111  // loaded immediately so that the rules are ready before we issue network
112  // requests.
113  state_store_.reset(new StateStore(
114      profile_,
115      profile_->GetPath().AppendASCII(extensions::kStateStoreName),
116      true));
117  state_store_notification_observer_.reset(
118      new StateStoreNotificationObserver(state_store_.get()));
119
120  rules_store_.reset(new StateStore(
121      profile_,
122      profile_->GetPath().AppendASCII(extensions::kRulesStoreName),
123      false));
124
125  blacklist_.reset(new Blacklist(ExtensionPrefs::Get(profile_)));
126
127#if defined(OS_CHROMEOS)
128  const user_manager::User* user =
129      user_manager::UserManager::Get()->GetActiveUser();
130  policy::DeviceLocalAccount::Type device_local_account_type;
131  if (user && policy::IsDeviceLocalAccountUser(user->email(),
132                                               &device_local_account_type)) {
133    device_local_account_management_policy_provider_.reset(
134        new chromeos::DeviceLocalAccountManagementPolicyProvider(
135            device_local_account_type));
136  }
137#endif  // defined(OS_CHROMEOS)
138}
139
140void ExtensionSystemImpl::Shared::RegisterManagementPolicyProviders() {
141  management_policy_->RegisterProvider(
142      ExtensionManagementFactory::GetForBrowserContext(profile_)
143          ->GetProvider());
144
145#if defined(OS_CHROMEOS)
146  if (device_local_account_management_policy_provider_) {
147    management_policy_->RegisterProvider(
148        device_local_account_management_policy_provider_.get());
149  }
150#endif  // defined(OS_CHROMEOS)
151
152  management_policy_->RegisterProvider(install_verifier_.get());
153}
154
155namespace {
156
157class ContentVerifierDelegateImpl : public ContentVerifierDelegate {
158 public:
159  explicit ContentVerifierDelegateImpl(ExtensionService* service)
160      : service_(service->AsWeakPtr()), default_mode_(GetDefaultMode()) {}
161
162  virtual ~ContentVerifierDelegateImpl() {}
163
164  virtual Mode ShouldBeVerified(const Extension& extension) OVERRIDE {
165#if defined(OS_CHROMEOS)
166    if (ExtensionAssetsManagerChromeOS::IsSharedInstall(&extension))
167      return ContentVerifierDelegate::ENFORCE_STRICT;
168#endif
169
170    if (!extension.is_extension() && !extension.is_legacy_packaged_app())
171      return ContentVerifierDelegate::NONE;
172    if (!Manifest::IsAutoUpdateableLocation(extension.location()))
173      return ContentVerifierDelegate::NONE;
174
175    if (!ManifestURL::UpdatesFromGallery(&extension)) {
176      // It's possible that the webstore update url was overridden for testing
177      // so also consider extensions with the default (production) update url
178      // to be from the store as well.
179      GURL default_webstore_url = extension_urls::GetDefaultWebstoreUpdateUrl();
180      if (ManifestURL::GetUpdateURL(&extension) != default_webstore_url)
181        return ContentVerifierDelegate::NONE;
182    }
183
184    return default_mode_;
185  }
186
187  virtual const ContentVerifierKey& PublicKey() OVERRIDE {
188    static ContentVerifierKey key(
189        extension_misc::kWebstoreSignaturesPublicKey,
190        extension_misc::kWebstoreSignaturesPublicKeySize);
191    return key;
192  }
193
194  virtual GURL GetSignatureFetchUrl(const std::string& extension_id,
195                                    const base::Version& version) OVERRIDE {
196    // TODO(asargent) Factor out common code from the extension updater's
197    // ManifestFetchData class that can be shared for use here.
198    std::vector<std::string> parts;
199    parts.push_back("uc");
200    parts.push_back("installsource=signature");
201    parts.push_back("id=" + extension_id);
202    parts.push_back("v=" + version.GetString());
203    std::string x_value =
204        net::EscapeQueryParamValue(JoinString(parts, "&"), true);
205    std::string query = "response=redirect&x=" + x_value;
206
207    GURL base_url = extension_urls::GetWebstoreUpdateUrl();
208    GURL::Replacements replacements;
209    replacements.SetQuery(query.c_str(), url::Component(0, query.length()));
210    return base_url.ReplaceComponents(replacements);
211  }
212
213  virtual std::set<base::FilePath> GetBrowserImagePaths(
214      const extensions::Extension* extension) OVERRIDE {
215    return extension_file_util::GetBrowserImagePaths(extension);
216  }
217
218  virtual void VerifyFailed(const std::string& extension_id,
219                            ContentVerifyJob::FailureReason reason) OVERRIDE {
220    if (!service_)
221      return;
222    ExtensionRegistry* registry = ExtensionRegistry::Get(service_->profile());
223    const Extension* extension =
224        registry->GetExtensionById(extension_id, ExtensionRegistry::ENABLED);
225    if (!extension)
226      return;
227    Mode mode = ShouldBeVerified(*extension);
228    if (mode >= ContentVerifierDelegate::ENFORCE) {
229      service_->DisableExtension(extension_id, Extension::DISABLE_CORRUPTED);
230      ExtensionPrefs::Get(service_->profile())
231          ->IncrementCorruptedDisableCount();
232      UMA_HISTOGRAM_BOOLEAN("Extensions.CorruptExtensionBecameDisabled", true);
233      UMA_HISTOGRAM_ENUMERATION("Extensions.CorruptExtensionDisabledReason",
234          reason, ContentVerifyJob::FAILURE_REASON_MAX);
235    } else if (!ContainsKey(would_be_disabled_ids_, extension_id)) {
236      UMA_HISTOGRAM_BOOLEAN("Extensions.CorruptExtensionWouldBeDisabled", true);
237      would_be_disabled_ids_.insert(extension_id);
238    }
239  }
240
241  static Mode GetDefaultMode() {
242    base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
243
244    Mode experiment_value = NONE;
245    const std::string group = base::FieldTrialList::FindFullName(
246        kContentVerificationExperimentName);
247    if (group == "EnforceStrict")
248      experiment_value = ContentVerifierDelegate::ENFORCE_STRICT;
249    else if (group == "Enforce")
250      experiment_value = ContentVerifierDelegate::ENFORCE;
251    else if (group == "Bootstrap")
252      experiment_value = ContentVerifierDelegate::BOOTSTRAP;
253
254    // The field trial value that normally comes from the server can be
255    // overridden on the command line, which we don't want to allow since
256    // malware can set chrome command line flags. There isn't currently a way
257    // to find out what the server-provided value is in this case, so we
258    // conservatively default to the strictest mode if we detect our experiment
259    // name being overridden.
260    if (command_line->HasSwitch(switches::kForceFieldTrials)) {
261      std::string forced_trials =
262          command_line->GetSwitchValueASCII(switches::kForceFieldTrials);
263      if (forced_trials.find(kContentVerificationExperimentName) !=
264              std::string::npos)
265        experiment_value = ContentVerifierDelegate::ENFORCE_STRICT;
266    }
267
268    Mode cmdline_value = NONE;
269    if (command_line->HasSwitch(switches::kExtensionContentVerification)) {
270      std::string switch_value = command_line->GetSwitchValueASCII(
271          switches::kExtensionContentVerification);
272      if (switch_value == switches::kExtensionContentVerificationBootstrap)
273        cmdline_value = ContentVerifierDelegate::BOOTSTRAP;
274      else if (switch_value == switches::kExtensionContentVerificationEnforce)
275        cmdline_value = ContentVerifierDelegate::ENFORCE;
276      else if (switch_value ==
277              switches::kExtensionContentVerificationEnforceStrict)
278        cmdline_value = ContentVerifierDelegate::ENFORCE_STRICT;
279      else
280        // If no value was provided (or the wrong one), just default to enforce.
281        cmdline_value = ContentVerifierDelegate::ENFORCE;
282    }
283
284    // We don't want to allow the command-line flags to eg disable enforcement
285    // if the experiment group says it should be on, or malware may just modify
286    // the command line flags. So return the more restrictive of the 2 values.
287    return std::max(experiment_value, cmdline_value);
288  }
289
290 private:
291  base::WeakPtr<ExtensionService> service_;
292  ContentVerifierDelegate::Mode default_mode_;
293
294  // For reporting metrics in BOOTSTRAP mode, when an extension would be
295  // disabled if content verification was in ENFORCE mode.
296  std::set<std::string> would_be_disabled_ids_;
297
298  DISALLOW_COPY_AND_ASSIGN(ContentVerifierDelegateImpl);
299};
300
301}  // namespace
302
303void ExtensionSystemImpl::Shared::Init(bool extensions_enabled) {
304  const CommandLine* command_line = CommandLine::ForCurrentProcess();
305
306  navigation_observer_.reset(new NavigationObserver(profile_));
307
308  bool allow_noisy_errors = !command_line->HasSwitch(switches::kNoErrorDialogs);
309  ExtensionErrorReporter::Init(allow_noisy_errors);
310
311  shared_user_script_master_.reset(new SharedUserScriptMaster(profile_));
312
313  // ExtensionService depends on RuntimeData.
314  runtime_data_.reset(new RuntimeData(ExtensionRegistry::Get(profile_)));
315
316  bool autoupdate_enabled = !profile_->IsGuestSession();
317#if defined(OS_CHROMEOS)
318  if (!extensions_enabled)
319    autoupdate_enabled = false;
320#endif
321  extension_service_.reset(new ExtensionService(
322      profile_,
323      CommandLine::ForCurrentProcess(),
324      profile_->GetPath().AppendASCII(extensions::kInstallDirectoryName),
325      ExtensionPrefs::Get(profile_),
326      blacklist_.get(),
327      autoupdate_enabled,
328      extensions_enabled,
329      &ready_));
330
331  // These services must be registered before the ExtensionService tries to
332  // load any extensions.
333  {
334    install_verifier_.reset(
335        new InstallVerifier(ExtensionPrefs::Get(profile_), profile_));
336    install_verifier_->Init();
337    content_verifier_ = new ContentVerifier(
338        profile_, new ContentVerifierDelegateImpl(extension_service_.get()));
339    ContentVerifierDelegate::Mode mode =
340        ContentVerifierDelegateImpl::GetDefaultMode();
341#if defined(OS_CHROMEOS)
342    mode = std::max(mode, ContentVerifierDelegate::BOOTSTRAP);
343#endif
344    if (mode >= ContentVerifierDelegate::BOOTSTRAP)
345      content_verifier_->Start();
346    info_map()->SetContentVerifier(content_verifier_.get());
347
348    management_policy_.reset(new ManagementPolicy);
349    RegisterManagementPolicyProviders();
350  }
351
352  bool skip_session_extensions = false;
353#if defined(OS_CHROMEOS)
354  // Skip loading session extensions if we are not in a user session.
355  skip_session_extensions = !chromeos::LoginState::Get()->IsUserLoggedIn();
356  if (chrome::IsRunningInForcedAppMode()) {
357    extension_service_->component_loader()->
358        AddDefaultComponentExtensionsForKioskMode(skip_session_extensions);
359  } else {
360    extension_service_->component_loader()->AddDefaultComponentExtensions(
361        skip_session_extensions);
362  }
363#else
364  extension_service_->component_loader()->AddDefaultComponentExtensions(
365      skip_session_extensions);
366#endif
367  if (command_line->HasSwitch(switches::kLoadComponentExtension)) {
368    CommandLine::StringType path_list = command_line->GetSwitchValueNative(
369        switches::kLoadComponentExtension);
370    base::StringTokenizerT<CommandLine::StringType,
371        CommandLine::StringType::const_iterator> t(path_list,
372                                                   FILE_PATH_LITERAL(","));
373    while (t.GetNext()) {
374      // Load the component extension manifest synchronously.
375      // Blocking the UI thread is acceptable here since
376      // this flag designated for developers.
377      base::ThreadRestrictions::ScopedAllowIO allow_io;
378      extension_service_->component_loader()->AddOrReplace(
379          base::FilePath(t.token()));
380    }
381  }
382  extension_service_->Init();
383
384  // Make the chrome://extension-icon/ resource available.
385  content::URLDataSource::Add(profile_, new ExtensionIconSource(profile_));
386
387  warning_service_.reset(new WarningService(profile_));
388  extension_warning_badge_service_.reset(
389      new ExtensionWarningBadgeService(profile_));
390  warning_service_->AddObserver(
391      extension_warning_badge_service_.get());
392  error_console_.reset(new ErrorConsole(profile_));
393  quota_service_.reset(new QuotaService);
394
395  if (extensions_enabled) {
396    // Load any extensions specified with --load-extension.
397    // TODO(yoz): Seems like this should move into ExtensionService::Init.
398    // But maybe it's no longer important.
399    if (command_line->HasSwitch(switches::kLoadExtension)) {
400      CommandLine::StringType path_list = command_line->GetSwitchValueNative(
401          switches::kLoadExtension);
402      base::StringTokenizerT<CommandLine::StringType,
403          CommandLine::StringType::const_iterator> t(path_list,
404                                                     FILE_PATH_LITERAL(","));
405      while (t.GetNext()) {
406        std::string extension_id;
407        UnpackedInstaller::Create(extension_service_.get())->
408            LoadFromCommandLine(base::FilePath(t.token()), &extension_id);
409      }
410    }
411  }
412}
413
414void ExtensionSystemImpl::Shared::Shutdown() {
415  if (warning_service_) {
416    warning_service_->RemoveObserver(
417        extension_warning_badge_service_.get());
418  }
419  if (content_verifier_.get())
420    content_verifier_->Shutdown();
421  if (extension_service_)
422    extension_service_->Shutdown();
423}
424
425StateStore* ExtensionSystemImpl::Shared::state_store() {
426  return state_store_.get();
427}
428
429StateStore* ExtensionSystemImpl::Shared::rules_store() {
430  return rules_store_.get();
431}
432
433ExtensionService* ExtensionSystemImpl::Shared::extension_service() {
434  return extension_service_.get();
435}
436
437RuntimeData* ExtensionSystemImpl::Shared::runtime_data() {
438  return runtime_data_.get();
439}
440
441ManagementPolicy* ExtensionSystemImpl::Shared::management_policy() {
442  return management_policy_.get();
443}
444
445SharedUserScriptMaster*
446ExtensionSystemImpl::Shared::shared_user_script_master() {
447  return shared_user_script_master_.get();
448}
449
450InfoMap* ExtensionSystemImpl::Shared::info_map() {
451  if (!extension_info_map_.get())
452    extension_info_map_ = new InfoMap();
453  return extension_info_map_.get();
454}
455
456LazyBackgroundTaskQueue*
457    ExtensionSystemImpl::Shared::lazy_background_task_queue() {
458  return lazy_background_task_queue_.get();
459}
460
461EventRouter* ExtensionSystemImpl::Shared::event_router() {
462  return event_router_.get();
463}
464
465WarningService* ExtensionSystemImpl::Shared::warning_service() {
466  return warning_service_.get();
467}
468
469Blacklist* ExtensionSystemImpl::Shared::blacklist() {
470  return blacklist_.get();
471}
472
473ErrorConsole* ExtensionSystemImpl::Shared::error_console() {
474  return error_console_.get();
475}
476
477InstallVerifier* ExtensionSystemImpl::Shared::install_verifier() {
478  return install_verifier_.get();
479}
480
481QuotaService* ExtensionSystemImpl::Shared::quota_service() {
482  return quota_service_.get();
483}
484
485ContentVerifier* ExtensionSystemImpl::Shared::content_verifier() {
486  return content_verifier_.get();
487}
488
489DeclarativeUserScriptMaster*
490ExtensionSystemImpl::Shared::GetDeclarativeUserScriptMasterByExtension(
491    const ExtensionId& extension_id) {
492  DCHECK(ready().is_signaled());
493  DeclarativeUserScriptMaster* master = NULL;
494  for (ScopedVector<DeclarativeUserScriptMaster>::iterator it =
495           declarative_user_script_masters_.begin();
496       it != declarative_user_script_masters_.end();
497       ++it) {
498    if ((*it)->extension_id() == extension_id) {
499      master = *it;
500      break;
501    }
502  }
503  if (!master) {
504    master = new DeclarativeUserScriptMaster(profile_, extension_id);
505    declarative_user_script_masters_.push_back(master);
506  }
507  return master;
508}
509
510//
511// ExtensionSystemImpl
512//
513
514ExtensionSystemImpl::ExtensionSystemImpl(Profile* profile)
515    : profile_(profile) {
516  shared_ = ExtensionSystemSharedFactory::GetForBrowserContext(profile);
517
518  if (profile->IsOffTheRecord()) {
519    process_manager_.reset(ProcessManager::Create(profile));
520  } else {
521    shared_->InitPrefs();
522  }
523}
524
525ExtensionSystemImpl::~ExtensionSystemImpl() {
526}
527
528void ExtensionSystemImpl::Shutdown() {
529  process_manager_.reset();
530}
531
532void ExtensionSystemImpl::InitForRegularProfile(bool extensions_enabled) {
533  DCHECK(!profile_->IsOffTheRecord());
534  if (shared_user_script_master() || extension_service())
535    return;  // Already initialized.
536
537  // The InfoMap needs to be created before the ProcessManager.
538  shared_->info_map();
539
540  process_manager_.reset(ProcessManager::Create(profile_));
541
542  shared_->Init(extensions_enabled);
543}
544
545ExtensionService* ExtensionSystemImpl::extension_service() {
546  return shared_->extension_service();
547}
548
549RuntimeData* ExtensionSystemImpl::runtime_data() {
550  return shared_->runtime_data();
551}
552
553ManagementPolicy* ExtensionSystemImpl::management_policy() {
554  return shared_->management_policy();
555}
556
557SharedUserScriptMaster* ExtensionSystemImpl::shared_user_script_master() {
558  return shared_->shared_user_script_master();
559}
560
561ProcessManager* ExtensionSystemImpl::process_manager() {
562  return process_manager_.get();
563}
564
565StateStore* ExtensionSystemImpl::state_store() {
566  return shared_->state_store();
567}
568
569StateStore* ExtensionSystemImpl::rules_store() {
570  return shared_->rules_store();
571}
572
573InfoMap* ExtensionSystemImpl::info_map() { return shared_->info_map(); }
574
575LazyBackgroundTaskQueue* ExtensionSystemImpl::lazy_background_task_queue() {
576  return shared_->lazy_background_task_queue();
577}
578
579EventRouter* ExtensionSystemImpl::event_router() {
580  return shared_->event_router();
581}
582
583WarningService* ExtensionSystemImpl::warning_service() {
584  return shared_->warning_service();
585}
586
587Blacklist* ExtensionSystemImpl::blacklist() {
588  return shared_->blacklist();
589}
590
591const OneShotEvent& ExtensionSystemImpl::ready() const {
592  return shared_->ready();
593}
594
595ErrorConsole* ExtensionSystemImpl::error_console() {
596  return shared_->error_console();
597}
598
599InstallVerifier* ExtensionSystemImpl::install_verifier() {
600  return shared_->install_verifier();
601}
602
603QuotaService* ExtensionSystemImpl::quota_service() {
604  return shared_->quota_service();
605}
606
607ContentVerifier* ExtensionSystemImpl::content_verifier() {
608  return shared_->content_verifier();
609}
610
611scoped_ptr<ExtensionSet> ExtensionSystemImpl::GetDependentExtensions(
612    const Extension* extension) {
613  return extension_service()->shared_module_service()->GetDependentExtensions(
614      extension);
615}
616
617DeclarativeUserScriptMaster*
618ExtensionSystemImpl::GetDeclarativeUserScriptMasterByExtension(
619    const ExtensionId& extension_id) {
620  return shared_->GetDeclarativeUserScriptMasterByExtension(extension_id);
621}
622
623void ExtensionSystemImpl::RegisterExtensionWithRequestContexts(
624    const Extension* extension) {
625  base::Time install_time;
626  if (extension->location() != Manifest::COMPONENT) {
627    install_time = ExtensionPrefs::Get(profile_)->
628        GetInstallTime(extension->id());
629  }
630  bool incognito_enabled = util::IsIncognitoEnabled(extension->id(), profile_);
631
632  bool notifications_disabled = false;
633#if defined(ENABLE_NOTIFICATIONS)
634  message_center::NotifierId notifier_id(
635      message_center::NotifierId::APPLICATION,
636      extension->id());
637
638  DesktopNotificationService* notification_service =
639      DesktopNotificationServiceFactory::GetForProfile(profile_);
640  notifications_disabled =
641      !notification_service->IsNotifierEnabled(notifier_id);
642#endif
643
644  BrowserThread::PostTask(
645      BrowserThread::IO, FROM_HERE,
646      base::Bind(&InfoMap::AddExtension, info_map(),
647                 make_scoped_refptr(extension), install_time,
648                 incognito_enabled, notifications_disabled));
649}
650
651void ExtensionSystemImpl::UnregisterExtensionWithRequestContexts(
652    const std::string& extension_id,
653    const UnloadedExtensionInfo::Reason reason) {
654  BrowserThread::PostTask(
655      BrowserThread::IO,
656      FROM_HERE,
657      base::Bind(&InfoMap::RemoveExtension, info_map(), extension_id, reason));
658}
659
660}  // namespace extensions
661