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