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