management_api.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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/api/management/management_api.h"
6
7#include <map>
8#include <string>
9#include <vector>
10
11#include "base/basictypes.h"
12#include "base/bind.h"
13#include "base/json/json_writer.h"
14#include "base/lazy_instance.h"
15#include "base/logging.h"
16#include "base/memory/linked_ptr.h"
17#include "base/memory/scoped_ptr.h"
18#include "base/metrics/histogram.h"
19#include "base/strings/string_number_conversions.h"
20#include "base/strings/string_util.h"
21#include "base/strings/utf_string_conversions.h"
22#include "chrome/browser/chrome_notification_types.h"
23#include "chrome/browser/extensions/api/management/management_api_constants.h"
24#include "chrome/browser/extensions/extension_service.h"
25#include "chrome/browser/extensions/extension_uninstall_dialog.h"
26#include "chrome/browser/extensions/launch_util.h"
27#include "chrome/browser/profiles/profile.h"
28#include "chrome/browser/ui/extensions/application_launch.h"
29#include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
30#include "chrome/common/chrome_utility_messages.h"
31#include "chrome/common/extensions/api/management.h"
32#include "chrome/common/extensions/extension_constants.h"
33#include "chrome/common/extensions/extension_icon_set.h"
34#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
35#include "chrome/common/extensions/manifest_handlers/icons_handler.h"
36#include "chrome/common/extensions/manifest_url_handler.h"
37#include "content/public/browser/notification_details.h"
38#include "content/public/browser/notification_source.h"
39#include "content/public/browser/utility_process_host.h"
40#include "content/public/browser/utility_process_host_client.h"
41#include "extensions/browser/event_router.h"
42#include "extensions/browser/extension_registry.h"
43#include "extensions/browser/extension_system.h"
44#include "extensions/browser/management_policy.h"
45#include "extensions/common/constants.h"
46#include "extensions/common/error_utils.h"
47#include "extensions/common/extension.h"
48#include "extensions/common/manifest_handlers/offline_enabled_info.h"
49#include "extensions/common/permissions/permission_set.h"
50#include "extensions/common/permissions/permissions_data.h"
51#include "extensions/common/url_pattern.h"
52
53#if !defined(OS_ANDROID)
54#include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h"
55#endif
56
57using base::IntToString;
58using content::BrowserThread;
59using content::UtilityProcessHost;
60using content::UtilityProcessHostClient;
61
62namespace keys = extension_management_api_constants;
63
64namespace extensions {
65
66namespace management = api::management;
67
68namespace {
69
70typedef std::vector<linked_ptr<management::ExtensionInfo> > ExtensionInfoList;
71typedef std::vector<linked_ptr<management::IconInfo> > IconInfoList;
72
73enum AutoConfirmForTest {
74  DO_NOT_SKIP = 0,
75  PROCEED,
76  ABORT
77};
78
79AutoConfirmForTest auto_confirm_for_test = DO_NOT_SKIP;
80
81std::vector<std::string> CreateWarningsList(const Extension* extension) {
82  std::vector<std::string> warnings_list;
83  PermissionMessages warnings =
84      PermissionsData::GetPermissionMessages(extension);
85  for (PermissionMessages::const_iterator iter = warnings.begin();
86       iter != warnings.end(); ++iter) {
87    warnings_list.push_back(base::UTF16ToUTF8(iter->message()));
88  }
89
90  return warnings_list;
91}
92
93scoped_ptr<management::ExtensionInfo> CreateExtensionInfo(
94    const Extension& extension,
95    ExtensionSystem* system) {
96  scoped_ptr<management::ExtensionInfo> info(new management::ExtensionInfo());
97  ExtensionService* service = system->extension_service();
98
99  info->id = extension.id();
100  info->name = extension.name();
101  info->short_name = extension.short_name();
102  info->enabled = service->IsExtensionEnabled(info->id);
103  info->offline_enabled = OfflineEnabledInfo::IsOfflineEnabled(&extension);
104  info->version = extension.VersionString();
105  info->description = extension.description();
106  info->options_url = ManifestURL::GetOptionsPage(&extension).spec();
107  info->homepage_url.reset(new std::string(
108      ManifestURL::GetHomepageURL(&extension).spec()));
109  info->may_disable = system->management_policy()->
110      UserMayModifySettings(&extension, NULL);
111  info->is_app = extension.is_app();
112  if (info->is_app) {
113    if (extension.is_legacy_packaged_app())
114      info->type = management::ExtensionInfo::TYPE_LEGACY_PACKAGED_APP;
115    else if (extension.is_hosted_app())
116      info->type = management::ExtensionInfo::TYPE_HOSTED_APP;
117    else
118      info->type = management::ExtensionInfo::TYPE_PACKAGED_APP;
119  } else if (extension.is_theme()) {
120    info->type = management::ExtensionInfo::TYPE_THEME;
121  } else {
122    info->type = management::ExtensionInfo::TYPE_EXTENSION;
123  }
124
125  if (info->enabled) {
126    info->disabled_reason = management::ExtensionInfo::DISABLED_REASON_NONE;
127  } else {
128    ExtensionPrefs* prefs = service->extension_prefs();
129    if (prefs->DidExtensionEscalatePermissions(extension.id())) {
130      info->disabled_reason =
131          management::ExtensionInfo::DISABLED_REASON_PERMISSIONS_INCREASE;
132    } else {
133      info->disabled_reason =
134          management::ExtensionInfo::DISABLED_REASON_UNKNOWN;
135    }
136  }
137
138  if (!ManifestURL::GetUpdateURL(&extension).is_empty()) {
139    info->update_url.reset(new std::string(
140        ManifestURL::GetUpdateURL(&extension).spec()));
141  }
142
143  if (extension.is_app()) {
144    info->app_launch_url.reset(new std::string(
145        AppLaunchInfo::GetFullLaunchURL(&extension).spec()));
146  }
147
148  const ExtensionIconSet::IconMap& icons =
149      IconsInfo::GetIcons(&extension).map();
150  if (!icons.empty()) {
151    info->icons.reset(new IconInfoList());
152    ExtensionIconSet::IconMap::const_iterator icon_iter;
153    for (icon_iter = icons.begin(); icon_iter != icons.end(); ++icon_iter) {
154      management::IconInfo* icon_info = new management::IconInfo();
155      icon_info->size = icon_iter->first;
156      GURL url = ExtensionIconSource::GetIconURL(
157          &extension, icon_info->size, ExtensionIconSet::MATCH_EXACTLY, false,
158          NULL);
159      icon_info->url = url.spec();
160      info->icons->push_back(make_linked_ptr<management::IconInfo>(icon_info));
161    }
162  }
163
164  const std::set<std::string> perms =
165      extension.GetActivePermissions()->GetAPIsAsStrings();
166  if (!perms.empty()) {
167    std::set<std::string>::const_iterator perms_iter;
168    for (perms_iter = perms.begin(); perms_iter != perms.end(); ++perms_iter)
169      info->permissions.push_back(*perms_iter);
170  }
171
172  if (!extension.is_hosted_app()) {
173    // Skip host permissions for hosted apps.
174    const URLPatternSet host_perms =
175        extension.GetActivePermissions()->explicit_hosts();
176    if (!host_perms.is_empty()) {
177      for (URLPatternSet::const_iterator iter = host_perms.begin();
178           iter != host_perms.end(); ++iter) {
179        info->host_permissions.push_back(iter->GetAsString());
180      }
181    }
182  }
183
184  switch (extension.location()) {
185    case Manifest::INTERNAL:
186      info->install_type = management::ExtensionInfo::INSTALL_TYPE_NORMAL;
187      break;
188    case Manifest::UNPACKED:
189    case Manifest::COMMAND_LINE:
190      info->install_type = management::ExtensionInfo::INSTALL_TYPE_DEVELOPMENT;
191      break;
192    case Manifest::EXTERNAL_PREF:
193    case Manifest::EXTERNAL_REGISTRY:
194    case Manifest::EXTERNAL_PREF_DOWNLOAD:
195      info->install_type = management::ExtensionInfo::INSTALL_TYPE_SIDELOAD;
196      break;
197    case Manifest::EXTERNAL_POLICY:
198    case Manifest::EXTERNAL_POLICY_DOWNLOAD:
199      info->install_type = management::ExtensionInfo::INSTALL_TYPE_ADMIN;
200      break;
201    case Manifest::NUM_LOCATIONS:
202      NOTREACHED();
203    case Manifest::INVALID_LOCATION:
204    case Manifest::COMPONENT:
205    case Manifest::EXTERNAL_COMPONENT:
206      info->install_type = management::ExtensionInfo::INSTALL_TYPE_OTHER;
207      break;
208  }
209
210  return info.Pass();
211}
212
213void AddExtensionInfo(const ExtensionSet& extensions,
214                            ExtensionSystem* system,
215                            ExtensionInfoList* extension_list) {
216  for (ExtensionSet::const_iterator iter = extensions.begin();
217       iter != extensions.end(); ++iter) {
218    const Extension& extension = *iter->get();
219
220    if (extension.ShouldNotBeVisible())
221      continue;  // Skip built-in extensions/apps.
222
223    extension_list->push_back(make_linked_ptr<management::ExtensionInfo>(
224        CreateExtensionInfo(extension, system).release()));
225  }
226}
227
228} // namespace
229
230ExtensionService* ManagementFunction::service() {
231  return GetProfile()->GetExtensionService();
232}
233
234ExtensionService* AsyncManagementFunction::service() {
235  return GetProfile()->GetExtensionService();
236}
237
238bool ManagementGetAllFunction::RunImpl() {
239  ExtensionInfoList extensions;
240  ExtensionRegistry* registry = ExtensionRegistry::Get(GetProfile());
241  ExtensionSystem* system = ExtensionSystem::Get(GetProfile());
242
243  AddExtensionInfo(registry->enabled_extensions(), system, &extensions);
244  AddExtensionInfo(registry->disabled_extensions(), system, &extensions);
245  AddExtensionInfo(registry->terminated_extensions(), system, &extensions);
246
247  results_ = management::GetAll::Results::Create(extensions);
248  return true;
249}
250
251bool ManagementGetFunction::RunImpl() {
252  scoped_ptr<management::Get::Params> params(
253      management::Get::Params::Create(*args_));
254  EXTENSION_FUNCTION_VALIDATE(params.get());
255
256  const Extension* extension = service()->GetExtensionById(params->id, true);
257  if (!extension) {
258    error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError,
259                                                     params->id);
260    return false;
261  }
262
263  scoped_ptr<management::ExtensionInfo> info =
264      CreateExtensionInfo(*extension, ExtensionSystem::Get(GetProfile()));
265  results_ = management::Get::Results::Create(*info);
266
267  return true;
268}
269
270bool ManagementGetPermissionWarningsByIdFunction::RunImpl() {
271  scoped_ptr<management::GetPermissionWarningsById::Params> params(
272      management::GetPermissionWarningsById::Params::Create(*args_));
273  EXTENSION_FUNCTION_VALIDATE(params.get());
274
275  const Extension* extension = service()->GetExtensionById(params->id, true);
276  if (!extension) {
277    error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError,
278                                                     params->id);
279    return false;
280  }
281
282  std::vector<std::string> warnings = CreateWarningsList(extension);
283  results_ = management::GetPermissionWarningsById::Results::Create(warnings);
284  return true;
285}
286
287namespace {
288
289// This class helps ManagementGetPermissionWarningsByManifestFunction manage
290// sending manifest JSON strings to the utility process for parsing.
291class SafeManifestJSONParser : public UtilityProcessHostClient {
292 public:
293  SafeManifestJSONParser(
294      ManagementGetPermissionWarningsByManifestFunction* client,
295      const std::string& manifest)
296      : client_(client),
297        manifest_(manifest) {}
298
299  void Start() {
300    CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
301    BrowserThread::PostTask(
302        BrowserThread::IO,
303        FROM_HERE,
304        base::Bind(&SafeManifestJSONParser::StartWorkOnIOThread, this));
305  }
306
307  void StartWorkOnIOThread() {
308    CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
309    UtilityProcessHost* host = UtilityProcessHost::Create(
310        this, base::MessageLoopProxy::current().get());
311    host->Send(new ChromeUtilityMsg_ParseJSON(manifest_));
312  }
313
314  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
315    bool handled = true;
316    IPC_BEGIN_MESSAGE_MAP(SafeManifestJSONParser, message)
317      IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Succeeded,
318                          OnJSONParseSucceeded)
319      IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Failed,
320                          OnJSONParseFailed)
321      IPC_MESSAGE_UNHANDLED(handled = false)
322    IPC_END_MESSAGE_MAP()
323    return handled;
324  }
325
326  void OnJSONParseSucceeded(const base::ListValue& wrapper) {
327    CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
328    const base::Value* value = NULL;
329    CHECK(wrapper.Get(0, &value));
330    if (value->IsType(base::Value::TYPE_DICTIONARY))
331      parsed_manifest_.reset(
332          static_cast<const base::DictionaryValue*>(value)->DeepCopy());
333    else
334      error_ = keys::kManifestParseError;
335
336    BrowserThread::PostTask(
337        BrowserThread::UI,
338        FROM_HERE,
339        base::Bind(&SafeManifestJSONParser::ReportResultFromUIThread, this));
340  }
341
342  void OnJSONParseFailed(const std::string& error) {
343    CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
344    error_ = error;
345    BrowserThread::PostTask(
346        BrowserThread::UI,
347        FROM_HERE,
348        base::Bind(&SafeManifestJSONParser::ReportResultFromUIThread, this));
349  }
350
351  void ReportResultFromUIThread() {
352    CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
353    if (error_.empty() && parsed_manifest_.get())
354      client_->OnParseSuccess(parsed_manifest_.Pass());
355    else
356      client_->OnParseFailure(error_);
357  }
358
359 private:
360  virtual ~SafeManifestJSONParser() {}
361
362  // The client who we'll report results back to.
363  ManagementGetPermissionWarningsByManifestFunction* client_;
364
365  // Data to parse.
366  std::string manifest_;
367
368  // Results of parsing.
369  scoped_ptr<base::DictionaryValue> parsed_manifest_;
370
371  std::string error_;
372};
373
374}  // namespace
375
376bool ManagementGetPermissionWarningsByManifestFunction::RunImpl() {
377  scoped_ptr<management::GetPermissionWarningsByManifest::Params> params(
378      management::GetPermissionWarningsByManifest::Params::Create(*args_));
379  EXTENSION_FUNCTION_VALIDATE(params.get());
380
381  scoped_refptr<SafeManifestJSONParser> parser =
382      new SafeManifestJSONParser(this, params->manifest_str);
383  parser->Start();
384
385  // Matched with a Release() in OnParseSuccess/Failure().
386  AddRef();
387
388  // Response is sent async in OnParseSuccess/Failure().
389  return true;
390}
391
392void ManagementGetPermissionWarningsByManifestFunction::OnParseSuccess(
393    scoped_ptr<base::DictionaryValue> parsed_manifest) {
394  CHECK(parsed_manifest.get());
395
396  scoped_refptr<Extension> extension = Extension::Create(
397      base::FilePath(), Manifest::INVALID_LOCATION, *parsed_manifest,
398      Extension::NO_FLAGS, &error_);
399  if (!extension.get()) {
400    OnParseFailure(keys::kExtensionCreateError);
401    return;
402  }
403
404  std::vector<std::string> warnings = CreateWarningsList(extension.get());
405  results_ =
406      management::GetPermissionWarningsByManifest::Results::Create(warnings);
407  SendResponse(true);
408
409  // Matched with AddRef() in RunImpl().
410  Release();
411}
412
413void ManagementGetPermissionWarningsByManifestFunction::OnParseFailure(
414    const std::string& error) {
415  error_ = error;
416  SendResponse(false);
417
418  // Matched with AddRef() in RunImpl().
419  Release();
420}
421
422bool ManagementLaunchAppFunction::RunImpl() {
423  scoped_ptr<management::LaunchApp::Params> params(
424      management::LaunchApp::Params::Create(*args_));
425  EXTENSION_FUNCTION_VALIDATE(params.get());
426  const Extension* extension = service()->GetExtensionById(params->id, true);
427  if (!extension) {
428    error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError,
429                                                     params->id);
430    return false;
431  }
432  if (!extension->is_app()) {
433    error_ = ErrorUtils::FormatErrorMessage(keys::kNotAnAppError,
434                                                     params->id);
435    return false;
436  }
437
438  // Look at prefs to find the right launch container.
439  // If the user has not set a preference, the default launch value will be
440  // returned.
441  LaunchContainer launch_container =
442      GetLaunchContainer(service()->extension_prefs(), extension);
443  OpenApplication(AppLaunchParams(
444      GetProfile(), extension, launch_container, NEW_FOREGROUND_TAB));
445#if !defined(OS_ANDROID)
446  CoreAppLauncherHandler::RecordAppLaunchType(
447      extension_misc::APP_LAUNCH_EXTENSION_API,
448      extension->GetType());
449#endif
450
451  return true;
452}
453
454ManagementSetEnabledFunction::ManagementSetEnabledFunction() {
455}
456
457ManagementSetEnabledFunction::~ManagementSetEnabledFunction() {
458}
459
460bool ManagementSetEnabledFunction::RunImpl() {
461  scoped_ptr<management::SetEnabled::Params> params(
462      management::SetEnabled::Params::Create(*args_));
463  EXTENSION_FUNCTION_VALIDATE(params.get());
464
465  extension_id_ = params->id;
466
467  const Extension* extension = service()->GetInstalledExtension(extension_id_);
468  if (!extension || extension->ShouldNotBeVisible()) {
469    error_ = ErrorUtils::FormatErrorMessage(
470        keys::kNoExtensionError, extension_id_);
471    return false;
472  }
473
474  const ManagementPolicy* policy =
475      ExtensionSystem::Get(GetProfile())->management_policy();
476  if (!policy->UserMayModifySettings(extension, NULL) ||
477      (!params->enabled && policy->MustRemainEnabled(extension, NULL)) ||
478      (params->enabled && policy->MustRemainDisabled(extension, NULL, NULL))) {
479    error_ = ErrorUtils::FormatErrorMessage(
480        keys::kUserCantModifyError, extension_id_);
481    return false;
482  }
483
484  bool currently_enabled = service()->IsExtensionEnabled(extension_id_);
485
486  if (!currently_enabled && params->enabled) {
487    ExtensionPrefs* prefs = service()->extension_prefs();
488    if (prefs->DidExtensionEscalatePermissions(extension_id_)) {
489      if (!user_gesture()) {
490        error_ = keys::kGestureNeededForEscalationError;
491        return false;
492      }
493      AddRef(); // Matched in InstallUIProceed/InstallUIAbort
494      install_prompt_.reset(
495          new ExtensionInstallPrompt(GetAssociatedWebContents()));
496      install_prompt_->ConfirmReEnable(this, extension);
497      return true;
498    }
499    service()->EnableExtension(extension_id_);
500  } else if (currently_enabled && !params->enabled) {
501    service()->DisableExtension(extension_id_, Extension::DISABLE_USER_ACTION);
502  }
503
504  BrowserThread::PostTask(
505      BrowserThread::UI,
506      FROM_HERE,
507      base::Bind(&ManagementSetEnabledFunction::SendResponse, this, true));
508
509  return true;
510}
511
512void ManagementSetEnabledFunction::InstallUIProceed() {
513  service()->EnableExtension(extension_id_);
514  SendResponse(true);
515  Release();
516}
517
518void ManagementSetEnabledFunction::InstallUIAbort(bool user_initiated) {
519  error_ = keys::kUserDidNotReEnableError;
520  SendResponse(false);
521  Release();
522}
523
524ManagementUninstallFunctionBase::ManagementUninstallFunctionBase() {
525}
526
527ManagementUninstallFunctionBase::~ManagementUninstallFunctionBase() {
528}
529
530bool ManagementUninstallFunctionBase::Uninstall(
531    const std::string& extension_id,
532    bool show_confirm_dialog) {
533  extension_id_ = extension_id;
534  const Extension* extension = service()->GetExtensionById(extension_id_, true);
535  if (!extension || extension->ShouldNotBeVisible()) {
536    error_ = ErrorUtils::FormatErrorMessage(
537        keys::kNoExtensionError, extension_id_);
538    return false;
539  }
540
541  if (!ExtensionSystem::Get(GetProfile())
542           ->management_policy()
543           ->UserMayModifySettings(extension, NULL)) {
544    error_ = ErrorUtils::FormatErrorMessage(
545        keys::kUserCantModifyError, extension_id_);
546    return false;
547  }
548
549  if (auto_confirm_for_test == DO_NOT_SKIP) {
550    if (show_confirm_dialog) {
551      AddRef(); // Balanced in ExtensionUninstallAccepted/Canceled
552      extension_uninstall_dialog_.reset(ExtensionUninstallDialog::Create(
553          GetProfile(), GetCurrentBrowser(), this));
554      extension_uninstall_dialog_->ConfirmUninstall(extension);
555    } else {
556      Finish(true);
557    }
558  } else {
559    Finish(auto_confirm_for_test == PROCEED);
560  }
561
562  return true;
563}
564
565// static
566void ManagementUninstallFunctionBase::SetAutoConfirmForTest(
567    bool should_proceed) {
568  auto_confirm_for_test = should_proceed ? PROCEED : ABORT;
569}
570
571void ManagementUninstallFunctionBase::Finish(bool should_uninstall) {
572  if (should_uninstall) {
573    bool success = service()->UninstallExtension(
574        extension_id_,
575        false, /* external uninstall */
576        NULL);
577
578    // TODO set error_ if !success
579    SendResponse(success);
580  } else {
581    error_ = ErrorUtils::FormatErrorMessage(
582        keys::kUninstallCanceledError, extension_id_);
583    SendResponse(false);
584  }
585
586}
587
588void ManagementUninstallFunctionBase::ExtensionUninstallAccepted() {
589  Finish(true);
590  Release();
591}
592
593void ManagementUninstallFunctionBase::ExtensionUninstallCanceled() {
594  Finish(false);
595  Release();
596}
597
598ManagementUninstallFunction::ManagementUninstallFunction() {
599}
600
601ManagementUninstallFunction::~ManagementUninstallFunction() {
602}
603
604bool ManagementUninstallFunction::RunImpl() {
605  scoped_ptr<management::Uninstall::Params> params(
606      management::Uninstall::Params::Create(*args_));
607  EXTENSION_FUNCTION_VALIDATE(extension_);
608  EXTENSION_FUNCTION_VALIDATE(params.get());
609
610  bool show_confirm_dialog = true;
611  // By default confirmation dialog isn't shown when uninstalling self, but this
612  // can be overridden with showConfirmDialog.
613  if (params->id == extension_->id()) {
614    show_confirm_dialog = params->options.get() &&
615                          params->options->show_confirm_dialog.get() &&
616                          *params->options->show_confirm_dialog;
617  }
618  if (show_confirm_dialog && !user_gesture()) {
619    error_ = keys::kGestureNeededForUninstallError;
620    return false;
621  }
622  return Uninstall(params->id, show_confirm_dialog);
623}
624
625ManagementUninstallSelfFunction::ManagementUninstallSelfFunction() {
626}
627
628ManagementUninstallSelfFunction::~ManagementUninstallSelfFunction() {
629}
630
631bool ManagementUninstallSelfFunction::RunImpl() {
632  scoped_ptr<management::UninstallSelf::Params> params(
633      management::UninstallSelf::Params::Create(*args_));
634  EXTENSION_FUNCTION_VALIDATE(params.get());
635
636  bool show_confirm_dialog = false;
637  if (params->options.get() && params->options->show_confirm_dialog.get())
638    show_confirm_dialog = *params->options->show_confirm_dialog;
639  return Uninstall(extension_->id(), show_confirm_dialog);
640}
641
642ManagementEventRouter::ManagementEventRouter(Profile* profile)
643    : profile_(profile) {
644  int types[] = {
645    chrome::NOTIFICATION_EXTENSION_INSTALLED,
646    chrome::NOTIFICATION_EXTENSION_UNINSTALLED,
647    chrome::NOTIFICATION_EXTENSION_LOADED,
648    chrome::NOTIFICATION_EXTENSION_UNLOADED
649  };
650
651  CHECK(registrar_.IsEmpty());
652  for (size_t i = 0; i < arraysize(types); i++) {
653    registrar_.Add(this,
654                   types[i],
655                   content::Source<Profile>(profile_));
656  }
657}
658
659ManagementEventRouter::~ManagementEventRouter() {}
660
661void ManagementEventRouter::Observe(
662    int type,
663    const content::NotificationSource& source,
664    const content::NotificationDetails& details) {
665  const char* event_name = NULL;
666  const Extension* extension = NULL;
667  Profile* profile = content::Source<Profile>(source).ptr();
668  CHECK(profile);
669  CHECK(profile_->IsSameProfile(profile));
670
671  switch (type) {
672    case chrome::NOTIFICATION_EXTENSION_INSTALLED:
673      event_name = management::OnInstalled::kEventName;
674      extension =
675          content::Details<const InstalledExtensionInfo>(details)->extension;
676      break;
677    case chrome::NOTIFICATION_EXTENSION_UNINSTALLED:
678      event_name = management::OnUninstalled::kEventName;
679      extension = content::Details<const Extension>(details).ptr();
680      break;
681    case chrome::NOTIFICATION_EXTENSION_LOADED:
682      event_name = management::OnEnabled::kEventName;
683      extension = content::Details<const Extension>(details).ptr();
684      break;
685    case chrome::NOTIFICATION_EXTENSION_UNLOADED:
686      event_name = management::OnDisabled::kEventName;
687      extension =
688          content::Details<const UnloadedExtensionInfo>(details)->extension;
689      break;
690    default:
691      NOTREACHED();
692      return;
693  }
694  DCHECK(event_name);
695  DCHECK(extension);
696
697  if (extension->ShouldNotBeVisible())
698    return; // Don't dispatch events for built-in extensions.
699
700  scoped_ptr<base::ListValue> args(new base::ListValue());
701  if (event_name == management::OnUninstalled::kEventName) {
702    args->Append(new base::StringValue(extension->id()));
703  } else {
704    scoped_ptr<management::ExtensionInfo> info = CreateExtensionInfo(
705        *extension, ExtensionSystem::Get(profile));
706    args->Append(info->ToValue().release());
707  }
708
709  scoped_ptr<Event> event(new Event(event_name, args.Pass()));
710  ExtensionSystem::Get(profile)->event_router()->BroadcastEvent(event.Pass());
711}
712
713ManagementAPI::ManagementAPI(Profile* profile)
714    : profile_(profile) {
715  ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
716      this, management::OnInstalled::kEventName);
717  ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
718      this, management::OnUninstalled::kEventName);
719  ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
720      this, management::OnEnabled::kEventName);
721  ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
722      this, management::OnDisabled::kEventName);
723}
724
725ManagementAPI::~ManagementAPI() {
726}
727
728void ManagementAPI::Shutdown() {
729  ExtensionSystem::Get(profile_)->event_router()->UnregisterObserver(this);
730}
731
732static base::LazyInstance<ProfileKeyedAPIFactory<ManagementAPI> >
733g_factory = LAZY_INSTANCE_INITIALIZER;
734
735// static
736ProfileKeyedAPIFactory<ManagementAPI>* ManagementAPI::GetFactoryInstance() {
737  return g_factory.Pointer();
738}
739
740void ManagementAPI::OnListenerAdded(const EventListenerInfo& details) {
741  management_event_router_.reset(new ManagementEventRouter(profile_));
742  ExtensionSystem::Get(profile_)->event_router()->UnregisterObserver(this);
743}
744
745}  // namespace extensions
746