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