Home | History | Annotate | Download | only in management
      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/core_app_launcher_handler.h"
     52 #endif
     53 
     54 using base::IntToString;
     55 using content::BrowserThread;
     56 using content::UtilityProcessHost;
     57 using content::UtilityProcessHostClient;
     58 
     59 namespace keys = extension_management_api_constants;
     60 
     61 namespace extensions {
     62 
     63 namespace events = event_names;
     64 namespace management = api::management;
     65 
     66 namespace {
     67 
     68 typedef std::vector<linked_ptr<management::ExtensionInfo> > ExtensionInfoList;
     69 typedef std::vector<linked_ptr<management::IconInfo> > IconInfoList;
     70 
     71 enum AutoConfirmForTest {
     72   DO_NOT_SKIP = 0,
     73   PROCEED,
     74   ABORT
     75 };
     76 
     77 AutoConfirmForTest auto_confirm_for_test = DO_NOT_SKIP;
     78 
     79 std::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 
     91 scoped_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 
    205 void 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.ShouldNotBeVisible())
    213       continue;  // Skip built-in extensions/apps.
    214 
    215     extension_list->push_back(make_linked_ptr<management::ExtensionInfo>(
    216         CreateExtensionInfo(extension, system).release()));
    217   }
    218 }
    219 
    220 } // namespace
    221 
    222 ExtensionService* ManagementFunction::service() {
    223   return profile()->GetExtensionService();
    224 }
    225 
    226 ExtensionService* AsyncManagementFunction::service() {
    227   return profile()->GetExtensionService();
    228 }
    229 
    230 bool 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 
    242 bool 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 
    261 bool 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 
    278 namespace {
    279 
    280 // This class helps ManagementGetPermissionWarningsByManifestFunction manage
    281 // sending manifest JSON strings to the utility process for parsing.
    282 class 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 
    368 bool 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 
    384 void 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 
    405 void ManagementGetPermissionWarningsByManifestFunction::OnParseFailure(
    406     const std::string& error) {
    407   error_ = error;
    408   SendResponse(false);
    409 
    410   // Matched with AddRef() in RunImpl().
    411   Release();
    412 }
    413 
    414 bool 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   CoreAppLauncherHandler::RecordAppLaunchType(
    441       extension_misc::APP_LAUNCH_EXTENSION_API,
    442       extension->GetType());
    443 #endif
    444 
    445   return true;
    446 }
    447 
    448 ManagementSetEnabledFunction::ManagementSetEnabledFunction() {
    449 }
    450 
    451 ManagementSetEnabledFunction::~ManagementSetEnabledFunction() {
    452 }
    453 
    454 bool 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 || extension->ShouldNotBeVisible()) {
    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 
    504 void ManagementSetEnabledFunction::InstallUIProceed() {
    505   service()->EnableExtension(extension_id_);
    506   SendResponse(true);
    507   Release();
    508 }
    509 
    510 void ManagementSetEnabledFunction::InstallUIAbort(bool user_initiated) {
    511   error_ = keys::kUserDidNotReEnableError;
    512   SendResponse(false);
    513   Release();
    514 }
    515 
    516 ManagementUninstallFunctionBase::ManagementUninstallFunctionBase() {
    517 }
    518 
    519 ManagementUninstallFunctionBase::~ManagementUninstallFunctionBase() {
    520 }
    521 
    522 bool 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 || extension->ShouldNotBeVisible()) {
    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
    557 void ManagementUninstallFunctionBase::SetAutoConfirmForTest(
    558     bool should_proceed) {
    559   auto_confirm_for_test = should_proceed ? PROCEED : ABORT;
    560 }
    561 
    562 void 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 
    579 void ManagementUninstallFunctionBase::ExtensionUninstallAccepted() {
    580   Finish(true);
    581   Release();
    582 }
    583 
    584 void ManagementUninstallFunctionBase::ExtensionUninstallCanceled() {
    585   Finish(false);
    586   Release();
    587 }
    588 
    589 ManagementUninstallFunction::ManagementUninstallFunction() {
    590 }
    591 
    592 ManagementUninstallFunction::~ManagementUninstallFunction() {
    593 }
    594 
    595 bool 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 
    607 ManagementUninstallSelfFunction::ManagementUninstallSelfFunction() {
    608 }
    609 
    610 ManagementUninstallSelfFunction::~ManagementUninstallSelfFunction() {
    611 }
    612 
    613 bool 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 
    624 ManagementEventRouter::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 
    641 ManagementEventRouter::~ManagementEventRouter() {}
    642 
    643 void 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   if (extension->ShouldNotBeVisible())
    680     return; // Don't dispatch events for built-in extensions.
    681 
    682   scoped_ptr<base::ListValue> args(new base::ListValue());
    683   if (event_name == events::kOnExtensionUninstalled) {
    684     args->Append(Value::CreateStringValue(extension->id()));
    685   } else {
    686     scoped_ptr<management::ExtensionInfo> info = CreateExtensionInfo(
    687         *extension, ExtensionSystem::Get(profile));
    688     args->Append(info->ToValue().release());
    689   }
    690 
    691   scoped_ptr<Event> event(new Event(event_name, args.Pass()));
    692   ExtensionSystem::Get(profile)->event_router()->BroadcastEvent(event.Pass());
    693 }
    694 
    695 ManagementAPI::ManagementAPI(Profile* profile)
    696     : profile_(profile) {
    697   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
    698       this, events::kOnExtensionInstalled);
    699   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
    700       this, events::kOnExtensionUninstalled);
    701   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
    702       this, events::kOnExtensionEnabled);
    703   ExtensionSystem::Get(profile_)->event_router()->RegisterObserver(
    704       this, events::kOnExtensionDisabled);
    705 }
    706 
    707 ManagementAPI::~ManagementAPI() {
    708 }
    709 
    710 void ManagementAPI::Shutdown() {
    711   ExtensionSystem::Get(profile_)->event_router()->UnregisterObserver(this);
    712 }
    713 
    714 static base::LazyInstance<ProfileKeyedAPIFactory<ManagementAPI> >
    715 g_factory = LAZY_INSTANCE_INITIALIZER;
    716 
    717 // static
    718 ProfileKeyedAPIFactory<ManagementAPI>* ManagementAPI::GetFactoryInstance() {
    719   return &g_factory.Get();
    720 }
    721 
    722 void ManagementAPI::OnListenerAdded(const EventListenerInfo& details) {
    723   management_event_router_.reset(new ManagementEventRouter(profile_));
    724   ExtensionSystem::Get(profile_)->event_router()->UnregisterObserver(this);
    725 }
    726 
    727 }  // namespace extensions
    728