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 <string>
      8 #include <vector>
      9 
     10 #include "base/basictypes.h"
     11 #include "base/bind.h"
     12 #include "base/json/json_writer.h"
     13 #include "base/lazy_instance.h"
     14 #include "base/logging.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/extensions/api/management/management_api_constants.h"
     22 #include "chrome/browser/extensions/extension_service.h"
     23 #include "chrome/browser/extensions/extension_ui_util.h"
     24 #include "chrome/browser/extensions/extension_uninstall_dialog.h"
     25 #include "chrome/browser/extensions/extension_util.h"
     26 #include "chrome/browser/extensions/launch_util.h"
     27 #include "chrome/browser/extensions/window_controller.h"
     28 #include "chrome/browser/favicon/favicon_service_factory.h"
     29 #include "chrome/browser/profiles/profile.h"
     30 #include "chrome/browser/ui/browser_dialogs.h"
     31 #include "chrome/browser/ui/browser_finder.h"
     32 #include "chrome/browser/ui/browser_window.h"
     33 #include "chrome/browser/ui/extensions/application_launch.h"
     34 #include "chrome/browser/ui/webui/extensions/extension_icon_source.h"
     35 #include "chrome/browser/ui/webui/ntp/core_app_launcher_handler.h"
     36 #include "chrome/common/extensions/api/management.h"
     37 #include "chrome/common/extensions/chrome_utility_extensions_messages.h"
     38 #include "chrome/common/extensions/extension_constants.h"
     39 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
     40 #include "chrome/common/extensions/manifest_url_handler.h"
     41 #include "content/public/browser/utility_process_host.h"
     42 #include "content/public/browser/utility_process_host_client.h"
     43 #include "extensions/browser/event_router.h"
     44 #include "extensions/browser/extension_prefs.h"
     45 #include "extensions/browser/extension_registry.h"
     46 #include "extensions/browser/extension_system.h"
     47 #include "extensions/browser/management_policy.h"
     48 #include "extensions/browser/uninstall_reason.h"
     49 #include "extensions/common/constants.h"
     50 #include "extensions/common/error_utils.h"
     51 #include "extensions/common/extension.h"
     52 #include "extensions/common/extension_icon_set.h"
     53 #include "extensions/common/manifest_handlers/icons_handler.h"
     54 #include "extensions/common/manifest_handlers/offline_enabled_info.h"
     55 #include "extensions/common/manifest_handlers/options_page_info.h"
     56 #include "extensions/common/permissions/permission_set.h"
     57 #include "extensions/common/permissions/permissions_data.h"
     58 #include "extensions/common/url_pattern.h"
     59 
     60 using base::IntToString;
     61 using content::BrowserThread;
     62 using content::UtilityProcessHost;
     63 using content::UtilityProcessHostClient;
     64 
     65 namespace keys = extension_management_api_constants;
     66 
     67 namespace extensions {
     68 
     69 namespace management = api::management;
     70 
     71 namespace {
     72 
     73 typedef std::vector<linked_ptr<management::ExtensionInfo> > ExtensionInfoList;
     74 typedef std::vector<linked_ptr<management::IconInfo> > IconInfoList;
     75 
     76 enum AutoConfirmForTest {
     77   DO_NOT_SKIP = 0,
     78   PROCEED,
     79   ABORT
     80 };
     81 
     82 AutoConfirmForTest auto_confirm_for_test = DO_NOT_SKIP;
     83 
     84 std::vector<std::string> CreateWarningsList(const Extension* extension) {
     85   std::vector<std::string> warnings_list;
     86   PermissionMessages warnings =
     87       extension->permissions_data()->GetPermissionMessages();
     88   for (PermissionMessages::const_iterator iter = warnings.begin();
     89        iter != warnings.end(); ++iter) {
     90     warnings_list.push_back(base::UTF16ToUTF8(iter->message()));
     91   }
     92 
     93   return warnings_list;
     94 }
     95 
     96 std::vector<management::LaunchType> GetAvailableLaunchTypes(
     97     const Extension& extension) {
     98   std::vector<management::LaunchType> launch_type_list;
     99   if (extension.is_platform_app()) {
    100     launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_WINDOW);
    101     return launch_type_list;
    102   }
    103 
    104   launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_REGULAR_TAB);
    105 
    106 #if !defined(OS_MACOSX)
    107   launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_WINDOW);
    108 #endif
    109 
    110   if (!util::IsStreamlinedHostedAppsEnabled()) {
    111     launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_AS_PINNED_TAB);
    112     launch_type_list.push_back(management::LAUNCH_TYPE_OPEN_FULL_SCREEN);
    113   }
    114   return launch_type_list;
    115 }
    116 
    117 scoped_ptr<management::ExtensionInfo> CreateExtensionInfo(
    118     const Extension& extension,
    119     ExtensionSystem* system) {
    120   scoped_ptr<management::ExtensionInfo> info(new management::ExtensionInfo());
    121   ExtensionService* service = system->extension_service();
    122 
    123   info->id = extension.id();
    124   info->name = extension.name();
    125   info->short_name = extension.short_name();
    126   info->enabled = service->IsExtensionEnabled(info->id);
    127   info->offline_enabled = OfflineEnabledInfo::IsOfflineEnabled(&extension);
    128   info->version = extension.VersionString();
    129   info->description = extension.description();
    130   info->options_url = OptionsPageInfo::GetOptionsPage(&extension).spec();
    131   info->homepage_url.reset(new std::string(
    132       ManifestURL::GetHomepageURL(&extension).spec()));
    133   info->may_disable = system->management_policy()->
    134       UserMayModifySettings(&extension, NULL);
    135   info->is_app = extension.is_app();
    136   if (info->is_app) {
    137     if (extension.is_legacy_packaged_app())
    138       info->type = management::ExtensionInfo::TYPE_LEGACY_PACKAGED_APP;
    139     else if (extension.is_hosted_app())
    140       info->type = management::ExtensionInfo::TYPE_HOSTED_APP;
    141     else
    142       info->type = management::ExtensionInfo::TYPE_PACKAGED_APP;
    143   } else if (extension.is_theme()) {
    144     info->type = management::ExtensionInfo::TYPE_THEME;
    145   } else {
    146     info->type = management::ExtensionInfo::TYPE_EXTENSION;
    147   }
    148 
    149   if (info->enabled) {
    150     info->disabled_reason = management::ExtensionInfo::DISABLED_REASON_NONE;
    151   } else {
    152     ExtensionPrefs* prefs = ExtensionPrefs::Get(service->profile());
    153     if (prefs->DidExtensionEscalatePermissions(extension.id())) {
    154       info->disabled_reason =
    155           management::ExtensionInfo::DISABLED_REASON_PERMISSIONS_INCREASE;
    156     } else {
    157       info->disabled_reason =
    158           management::ExtensionInfo::DISABLED_REASON_UNKNOWN;
    159     }
    160   }
    161 
    162   if (!ManifestURL::GetUpdateURL(&extension).is_empty()) {
    163     info->update_url.reset(new std::string(
    164         ManifestURL::GetUpdateURL(&extension).spec()));
    165   }
    166 
    167   if (extension.is_app()) {
    168     info->app_launch_url.reset(new std::string(
    169         AppLaunchInfo::GetFullLaunchURL(&extension).spec()));
    170   }
    171 
    172   const ExtensionIconSet::IconMap& icons =
    173       IconsInfo::GetIcons(&extension).map();
    174   if (!icons.empty()) {
    175     info->icons.reset(new IconInfoList());
    176     ExtensionIconSet::IconMap::const_iterator icon_iter;
    177     for (icon_iter = icons.begin(); icon_iter != icons.end(); ++icon_iter) {
    178       management::IconInfo* icon_info = new management::IconInfo();
    179       icon_info->size = icon_iter->first;
    180       GURL url = ExtensionIconSource::GetIconURL(
    181           &extension, icon_info->size, ExtensionIconSet::MATCH_EXACTLY, false,
    182           NULL);
    183       icon_info->url = url.spec();
    184       info->icons->push_back(make_linked_ptr<management::IconInfo>(icon_info));
    185     }
    186   }
    187 
    188   const std::set<std::string> perms =
    189       extension.permissions_data()->active_permissions()->GetAPIsAsStrings();
    190   if (!perms.empty()) {
    191     std::set<std::string>::const_iterator perms_iter;
    192     for (perms_iter = perms.begin(); perms_iter != perms.end(); ++perms_iter)
    193       info->permissions.push_back(*perms_iter);
    194   }
    195 
    196   if (!extension.is_hosted_app()) {
    197     // Skip host permissions for hosted apps.
    198     const URLPatternSet host_perms =
    199         extension.permissions_data()->active_permissions()->explicit_hosts();
    200     if (!host_perms.is_empty()) {
    201       for (URLPatternSet::const_iterator iter = host_perms.begin();
    202            iter != host_perms.end(); ++iter) {
    203         info->host_permissions.push_back(iter->GetAsString());
    204       }
    205     }
    206   }
    207 
    208   switch (extension.location()) {
    209     case Manifest::INTERNAL:
    210       info->install_type = management::ExtensionInfo::INSTALL_TYPE_NORMAL;
    211       break;
    212     case Manifest::UNPACKED:
    213     case Manifest::COMMAND_LINE:
    214       info->install_type = management::ExtensionInfo::INSTALL_TYPE_DEVELOPMENT;
    215       break;
    216     case Manifest::EXTERNAL_PREF:
    217     case Manifest::EXTERNAL_REGISTRY:
    218     case Manifest::EXTERNAL_PREF_DOWNLOAD:
    219       info->install_type = management::ExtensionInfo::INSTALL_TYPE_SIDELOAD;
    220       break;
    221     case Manifest::EXTERNAL_POLICY:
    222     case Manifest::EXTERNAL_POLICY_DOWNLOAD:
    223       info->install_type = management::ExtensionInfo::INSTALL_TYPE_ADMIN;
    224       break;
    225     case Manifest::NUM_LOCATIONS:
    226       NOTREACHED();
    227     case Manifest::INVALID_LOCATION:
    228     case Manifest::COMPONENT:
    229     case Manifest::EXTERNAL_COMPONENT:
    230       info->install_type = management::ExtensionInfo::INSTALL_TYPE_OTHER;
    231       break;
    232   }
    233 
    234   info->launch_type = management::LAUNCH_TYPE_NONE;
    235   if (extension.is_app()) {
    236     LaunchType launch_type;
    237     if (extension.is_platform_app()) {
    238       launch_type = LAUNCH_TYPE_WINDOW;
    239     } else {
    240       launch_type =
    241           GetLaunchType(ExtensionPrefs::Get(service->profile()), &extension);
    242     }
    243 
    244     switch (launch_type) {
    245       case LAUNCH_TYPE_PINNED:
    246         info->launch_type = management::LAUNCH_TYPE_OPEN_AS_PINNED_TAB;
    247         break;
    248       case LAUNCH_TYPE_REGULAR:
    249         info->launch_type = management::LAUNCH_TYPE_OPEN_AS_REGULAR_TAB;
    250         break;
    251       case LAUNCH_TYPE_FULLSCREEN:
    252         info->launch_type = management::LAUNCH_TYPE_OPEN_FULL_SCREEN;
    253         break;
    254       case LAUNCH_TYPE_WINDOW:
    255         info->launch_type = management::LAUNCH_TYPE_OPEN_AS_WINDOW;
    256         break;
    257       case LAUNCH_TYPE_INVALID:
    258       case NUM_LAUNCH_TYPES:
    259         NOTREACHED();
    260     }
    261 
    262     info->available_launch_types.reset(new std::vector<management::LaunchType>(
    263         GetAvailableLaunchTypes(extension)));
    264   }
    265 
    266   return info.Pass();
    267 }
    268 
    269 void AddExtensionInfo(const ExtensionSet& extensions,
    270                             ExtensionSystem* system,
    271                             ExtensionInfoList* extension_list,
    272                             content::BrowserContext* context) {
    273   for (ExtensionSet::const_iterator iter = extensions.begin();
    274        iter != extensions.end(); ++iter) {
    275     const Extension& extension = *iter->get();
    276 
    277     if (ui_util::ShouldNotBeVisible(&extension, context))
    278       continue;  // Skip built-in extensions/apps.
    279 
    280     extension_list->push_back(make_linked_ptr<management::ExtensionInfo>(
    281         CreateExtensionInfo(extension, system).release()));
    282   }
    283 }
    284 
    285 }  // namespace
    286 
    287 ExtensionService* ManagementFunction::service() {
    288   return ExtensionSystem::Get(GetProfile())->extension_service();
    289 }
    290 
    291 ExtensionService* AsyncManagementFunction::service() {
    292   return ExtensionSystem::Get(GetProfile())->extension_service();
    293 }
    294 
    295 bool ManagementGetAllFunction::RunSync() {
    296   ExtensionInfoList extensions;
    297   ExtensionRegistry* registry = ExtensionRegistry::Get(GetProfile());
    298   ExtensionSystem* system = ExtensionSystem::Get(GetProfile());
    299 
    300   AddExtensionInfo(registry->enabled_extensions(),
    301                    system, &extensions, browser_context());
    302   AddExtensionInfo(registry->disabled_extensions(),
    303                    system, &extensions, browser_context());
    304   AddExtensionInfo(registry->terminated_extensions(),
    305                    system, &extensions, browser_context());
    306 
    307   results_ = management::GetAll::Results::Create(extensions);
    308   return true;
    309 }
    310 
    311 bool ManagementGetFunction::RunSync() {
    312   scoped_ptr<management::Get::Params> params(
    313       management::Get::Params::Create(*args_));
    314   EXTENSION_FUNCTION_VALIDATE(params.get());
    315 
    316   const Extension* extension = service()->GetExtensionById(params->id, true);
    317   if (!extension) {
    318     error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError,
    319                                                      params->id);
    320     return false;
    321   }
    322 
    323   scoped_ptr<management::ExtensionInfo> info =
    324       CreateExtensionInfo(*extension, ExtensionSystem::Get(GetProfile()));
    325   results_ = management::Get::Results::Create(*info);
    326 
    327   return true;
    328 }
    329 
    330 bool ManagementGetSelfFunction::RunSync() {
    331   scoped_ptr<management::ExtensionInfo> info =
    332       CreateExtensionInfo(*extension_, ExtensionSystem::Get(GetProfile()));
    333   results_ = management::Get::Results::Create(*info);
    334 
    335   return true;
    336 }
    337 
    338 bool ManagementGetPermissionWarningsByIdFunction::RunSync() {
    339   scoped_ptr<management::GetPermissionWarningsById::Params> params(
    340       management::GetPermissionWarningsById::Params::Create(*args_));
    341   EXTENSION_FUNCTION_VALIDATE(params.get());
    342 
    343   const Extension* extension = service()->GetExtensionById(params->id, true);
    344   if (!extension) {
    345     error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError,
    346                                                      params->id);
    347     return false;
    348   }
    349 
    350   std::vector<std::string> warnings = CreateWarningsList(extension);
    351   results_ = management::GetPermissionWarningsById::Results::Create(warnings);
    352   return true;
    353 }
    354 
    355 namespace {
    356 
    357 // This class helps ManagementGetPermissionWarningsByManifestFunction manage
    358 // sending manifest JSON strings to the utility process for parsing.
    359 class SafeManifestJSONParser : public UtilityProcessHostClient {
    360  public:
    361   SafeManifestJSONParser(
    362       ManagementGetPermissionWarningsByManifestFunction* client,
    363       const std::string& manifest)
    364       : client_(client),
    365         manifest_(manifest) {}
    366 
    367   void Start() {
    368     CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    369     BrowserThread::PostTask(
    370         BrowserThread::IO,
    371         FROM_HERE,
    372         base::Bind(&SafeManifestJSONParser::StartWorkOnIOThread, this));
    373   }
    374 
    375   void StartWorkOnIOThread() {
    376     CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    377     UtilityProcessHost* host = UtilityProcessHost::Create(
    378         this, base::MessageLoopProxy::current().get());
    379     host->Send(new ChromeUtilityMsg_ParseJSON(manifest_));
    380   }
    381 
    382   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
    383     bool handled = true;
    384     IPC_BEGIN_MESSAGE_MAP(SafeManifestJSONParser, message)
    385       IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Succeeded,
    386                           OnJSONParseSucceeded)
    387       IPC_MESSAGE_HANDLER(ChromeUtilityHostMsg_ParseJSON_Failed,
    388                           OnJSONParseFailed)
    389       IPC_MESSAGE_UNHANDLED(handled = false)
    390     IPC_END_MESSAGE_MAP()
    391     return handled;
    392   }
    393 
    394   void OnJSONParseSucceeded(const base::ListValue& wrapper) {
    395     CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    396     const base::Value* value = NULL;
    397     CHECK(wrapper.Get(0, &value));
    398     if (value->IsType(base::Value::TYPE_DICTIONARY))
    399       parsed_manifest_.reset(
    400           static_cast<const base::DictionaryValue*>(value)->DeepCopy());
    401     else
    402       error_ = keys::kManifestParseError;
    403 
    404     BrowserThread::PostTask(
    405         BrowserThread::UI,
    406         FROM_HERE,
    407         base::Bind(&SafeManifestJSONParser::ReportResultFromUIThread, this));
    408   }
    409 
    410   void OnJSONParseFailed(const std::string& error) {
    411     CHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    412     error_ = error;
    413     BrowserThread::PostTask(
    414         BrowserThread::UI,
    415         FROM_HERE,
    416         base::Bind(&SafeManifestJSONParser::ReportResultFromUIThread, this));
    417   }
    418 
    419   void ReportResultFromUIThread() {
    420     CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    421     if (error_.empty() && parsed_manifest_.get())
    422       client_->OnParseSuccess(parsed_manifest_.Pass());
    423     else
    424       client_->OnParseFailure(error_);
    425   }
    426 
    427  private:
    428   virtual ~SafeManifestJSONParser() {}
    429 
    430   // The client who we'll report results back to.
    431   ManagementGetPermissionWarningsByManifestFunction* client_;
    432 
    433   // Data to parse.
    434   std::string manifest_;
    435 
    436   // Results of parsing.
    437   scoped_ptr<base::DictionaryValue> parsed_manifest_;
    438 
    439   std::string error_;
    440 };
    441 
    442 }  // namespace
    443 
    444 bool ManagementGetPermissionWarningsByManifestFunction::RunAsync() {
    445   scoped_ptr<management::GetPermissionWarningsByManifest::Params> params(
    446       management::GetPermissionWarningsByManifest::Params::Create(*args_));
    447   EXTENSION_FUNCTION_VALIDATE(params.get());
    448 
    449   scoped_refptr<SafeManifestJSONParser> parser =
    450       new SafeManifestJSONParser(this, params->manifest_str);
    451   parser->Start();
    452 
    453   // Matched with a Release() in OnParseSuccess/Failure().
    454   AddRef();
    455 
    456   // Response is sent async in OnParseSuccess/Failure().
    457   return true;
    458 }
    459 
    460 void ManagementGetPermissionWarningsByManifestFunction::OnParseSuccess(
    461     scoped_ptr<base::DictionaryValue> parsed_manifest) {
    462   CHECK(parsed_manifest.get());
    463 
    464   scoped_refptr<Extension> extension = Extension::Create(
    465       base::FilePath(), Manifest::INVALID_LOCATION, *parsed_manifest,
    466       Extension::NO_FLAGS, &error_);
    467   if (!extension.get()) {
    468     OnParseFailure(keys::kExtensionCreateError);
    469     return;
    470   }
    471 
    472   std::vector<std::string> warnings = CreateWarningsList(extension.get());
    473   results_ =
    474       management::GetPermissionWarningsByManifest::Results::Create(warnings);
    475   SendResponse(true);
    476 
    477   // Matched with AddRef() in RunAsync().
    478   Release();
    479 }
    480 
    481 void ManagementGetPermissionWarningsByManifestFunction::OnParseFailure(
    482     const std::string& error) {
    483   error_ = error;
    484   SendResponse(false);
    485 
    486   // Matched with AddRef() in RunAsync().
    487   Release();
    488 }
    489 
    490 bool ManagementLaunchAppFunction::RunSync() {
    491   scoped_ptr<management::LaunchApp::Params> params(
    492       management::LaunchApp::Params::Create(*args_));
    493   EXTENSION_FUNCTION_VALIDATE(params.get());
    494   const Extension* extension = service()->GetExtensionById(params->id, true);
    495   if (!extension) {
    496     error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError,
    497                                                      params->id);
    498     return false;
    499   }
    500   if (!extension->is_app()) {
    501     error_ = ErrorUtils::FormatErrorMessage(keys::kNotAnAppError,
    502                                                      params->id);
    503     return false;
    504   }
    505 
    506   // Look at prefs to find the right launch container.
    507   // If the user has not set a preference, the default launch value will be
    508   // returned.
    509   LaunchContainer launch_container =
    510       GetLaunchContainer(ExtensionPrefs::Get(GetProfile()), extension);
    511   OpenApplication(AppLaunchParams(
    512       GetProfile(), extension, launch_container, NEW_FOREGROUND_TAB));
    513   CoreAppLauncherHandler::RecordAppLaunchType(
    514       extension_misc::APP_LAUNCH_EXTENSION_API,
    515       extension->GetType());
    516 
    517   return true;
    518 }
    519 
    520 ManagementSetEnabledFunction::ManagementSetEnabledFunction() {
    521 }
    522 
    523 ManagementSetEnabledFunction::~ManagementSetEnabledFunction() {
    524 }
    525 
    526 bool ManagementSetEnabledFunction::RunAsync() {
    527   scoped_ptr<management::SetEnabled::Params> params(
    528       management::SetEnabled::Params::Create(*args_));
    529   EXTENSION_FUNCTION_VALIDATE(params.get());
    530 
    531   extension_id_ = params->id;
    532 
    533   const Extension* extension =
    534       ExtensionRegistry::Get(GetProfile())
    535           ->GetExtensionById(extension_id_, ExtensionRegistry::EVERYTHING);
    536   if (!extension || ui_util::ShouldNotBeVisible(extension, browser_context())) {
    537     error_ = ErrorUtils::FormatErrorMessage(
    538         keys::kNoExtensionError, extension_id_);
    539     return false;
    540   }
    541 
    542   const ManagementPolicy* policy =
    543       ExtensionSystem::Get(GetProfile())->management_policy();
    544   if (!policy->UserMayModifySettings(extension, NULL) ||
    545       (!params->enabled && policy->MustRemainEnabled(extension, NULL)) ||
    546       (params->enabled && policy->MustRemainDisabled(extension, NULL, NULL))) {
    547     error_ = ErrorUtils::FormatErrorMessage(
    548         keys::kUserCantModifyError, extension_id_);
    549     return false;
    550   }
    551 
    552   bool currently_enabled = service()->IsExtensionEnabled(extension_id_);
    553 
    554   if (!currently_enabled && params->enabled) {
    555     ExtensionPrefs* prefs = ExtensionPrefs::Get(GetProfile());
    556     if (prefs->DidExtensionEscalatePermissions(extension_id_)) {
    557       if (!user_gesture()) {
    558         error_ = keys::kGestureNeededForEscalationError;
    559         return false;
    560       }
    561       AddRef();  // Matched in InstallUIProceed/InstallUIAbort
    562       install_prompt_.reset(
    563           new ExtensionInstallPrompt(GetAssociatedWebContents()));
    564       install_prompt_->ConfirmReEnable(this, extension);
    565       return true;
    566     }
    567     service()->EnableExtension(extension_id_);
    568   } else if (currently_enabled && !params->enabled) {
    569     service()->DisableExtension(extension_id_, Extension::DISABLE_USER_ACTION);
    570   }
    571 
    572   BrowserThread::PostTask(
    573       BrowserThread::UI,
    574       FROM_HERE,
    575       base::Bind(&ManagementSetEnabledFunction::SendResponse, this, true));
    576 
    577   return true;
    578 }
    579 
    580 void ManagementSetEnabledFunction::InstallUIProceed() {
    581   service()->EnableExtension(extension_id_);
    582   SendResponse(true);
    583   Release();
    584 }
    585 
    586 void ManagementSetEnabledFunction::InstallUIAbort(bool user_initiated) {
    587   error_ = keys::kUserDidNotReEnableError;
    588   SendResponse(false);
    589   Release();
    590 }
    591 
    592 ManagementUninstallFunctionBase::ManagementUninstallFunctionBase() {
    593 }
    594 
    595 ManagementUninstallFunctionBase::~ManagementUninstallFunctionBase() {
    596 }
    597 
    598 bool ManagementUninstallFunctionBase::Uninstall(
    599     const std::string& target_extension_id,
    600     bool show_confirm_dialog) {
    601   extension_id_ = target_extension_id;
    602   const Extension* target_extension =
    603       extensions::ExtensionRegistry::Get(browser_context())->
    604           GetExtensionById(extension_id_, ExtensionRegistry::EVERYTHING);
    605   if (!target_extension ||
    606       ui_util::ShouldNotBeVisible(target_extension, browser_context())) {
    607     error_ = ErrorUtils::FormatErrorMessage(
    608         keys::kNoExtensionError, extension_id_);
    609     return false;
    610   }
    611 
    612   if (!ExtensionSystem::Get(GetProfile())
    613            ->management_policy()
    614            ->UserMayModifySettings(target_extension, NULL)) {
    615     error_ = ErrorUtils::FormatErrorMessage(
    616         keys::kUserCantModifyError, extension_id_);
    617     return false;
    618   }
    619 
    620   if (auto_confirm_for_test == DO_NOT_SKIP) {
    621     if (show_confirm_dialog) {
    622       AddRef();  // Balanced in ExtensionUninstallAccepted/Canceled
    623       extensions::WindowController* controller = GetExtensionWindowController();
    624       extension_uninstall_dialog_.reset(ExtensionUninstallDialog::Create(
    625           GetProfile(),
    626           controller ? controller->window()->GetNativeWindow() : NULL,
    627           this));
    628       if (extension_id() != target_extension_id) {
    629         extension_uninstall_dialog_->ConfirmProgrammaticUninstall(
    630             target_extension, extension());
    631       } else {
    632         // If this is a self uninstall, show the generic uninstall dialog.
    633         extension_uninstall_dialog_->ConfirmUninstall(target_extension);
    634       }
    635     } else {
    636       Finish(true);
    637     }
    638   } else {
    639     Finish(auto_confirm_for_test == PROCEED);
    640   }
    641 
    642   return true;
    643 }
    644 
    645 // static
    646 void ManagementUninstallFunctionBase::SetAutoConfirmForTest(
    647     bool should_proceed) {
    648   auto_confirm_for_test = should_proceed ? PROCEED : ABORT;
    649 }
    650 
    651 void ManagementUninstallFunctionBase::Finish(bool should_uninstall) {
    652   if (should_uninstall) {
    653     // The extension can be uninstalled in another window while the UI was
    654     // showing. Do nothing in that case.
    655     ExtensionRegistry* registry = ExtensionRegistry::Get(GetProfile());
    656     const Extension* extension = registry->GetExtensionById(
    657         extension_id_, ExtensionRegistry::EVERYTHING);
    658     if (!extension) {
    659       error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError,
    660                                               extension_id_);
    661       SendResponse(false);
    662     } else {
    663       bool success = service()->UninstallExtension(
    664           extension_id_,
    665           extensions::UNINSTALL_REASON_MANAGEMENT_API,
    666           base::Bind(&base::DoNothing),
    667           NULL);
    668 
    669       // TODO set error_ if !success
    670       SendResponse(success);
    671     }
    672   } else {
    673     error_ = ErrorUtils::FormatErrorMessage(
    674         keys::kUninstallCanceledError, extension_id_);
    675     SendResponse(false);
    676   }
    677 }
    678 
    679 void ManagementUninstallFunctionBase::ExtensionUninstallAccepted() {
    680   Finish(true);
    681   Release();
    682 }
    683 
    684 void ManagementUninstallFunctionBase::ExtensionUninstallCanceled() {
    685   Finish(false);
    686   Release();
    687 }
    688 
    689 ManagementUninstallFunction::ManagementUninstallFunction() {
    690 }
    691 
    692 ManagementUninstallFunction::~ManagementUninstallFunction() {
    693 }
    694 
    695 bool ManagementUninstallFunction::RunAsync() {
    696   scoped_ptr<management::Uninstall::Params> params(
    697       management::Uninstall::Params::Create(*args_));
    698   EXTENSION_FUNCTION_VALIDATE(extension_.get());
    699   EXTENSION_FUNCTION_VALIDATE(params.get());
    700 
    701   bool show_confirm_dialog = true;
    702   // By default confirmation dialog isn't shown when uninstalling self, but this
    703   // can be overridden with showConfirmDialog.
    704   if (params->id == extension_->id()) {
    705     show_confirm_dialog = params->options.get() &&
    706                           params->options->show_confirm_dialog.get() &&
    707                           *params->options->show_confirm_dialog;
    708   }
    709   if (show_confirm_dialog && !user_gesture()) {
    710     error_ = keys::kGestureNeededForUninstallError;
    711     return false;
    712   }
    713   return Uninstall(params->id, show_confirm_dialog);
    714 }
    715 
    716 ManagementUninstallSelfFunction::ManagementUninstallSelfFunction() {
    717 }
    718 
    719 ManagementUninstallSelfFunction::~ManagementUninstallSelfFunction() {
    720 }
    721 
    722 bool ManagementUninstallSelfFunction::RunAsync() {
    723   scoped_ptr<management::UninstallSelf::Params> params(
    724       management::UninstallSelf::Params::Create(*args_));
    725   EXTENSION_FUNCTION_VALIDATE(params.get());
    726 
    727   bool show_confirm_dialog = false;
    728   if (params->options.get() && params->options->show_confirm_dialog.get())
    729     show_confirm_dialog = *params->options->show_confirm_dialog;
    730   return Uninstall(extension_->id(), show_confirm_dialog);
    731 }
    732 
    733 ManagementCreateAppShortcutFunction::ManagementCreateAppShortcutFunction() {
    734 }
    735 
    736 ManagementCreateAppShortcutFunction::~ManagementCreateAppShortcutFunction() {
    737 }
    738 
    739 // static
    740 void ManagementCreateAppShortcutFunction::SetAutoConfirmForTest(
    741     bool should_proceed) {
    742   auto_confirm_for_test = should_proceed ? PROCEED : ABORT;
    743 }
    744 
    745 void ManagementCreateAppShortcutFunction::OnCloseShortcutPrompt(bool created) {
    746   if (!created)
    747     error_ = keys::kCreateShortcutCanceledError;
    748   SendResponse(created);
    749   Release();
    750 }
    751 
    752 bool ManagementCreateAppShortcutFunction::RunAsync() {
    753   if (!user_gesture()) {
    754     error_ = keys::kGestureNeededForCreateAppShortcutError;
    755     return false;
    756   }
    757 
    758   scoped_ptr<management::CreateAppShortcut::Params> params(
    759       management::CreateAppShortcut::Params::Create(*args_));
    760   EXTENSION_FUNCTION_VALIDATE(params.get());
    761   const Extension* extension = service()->GetExtensionById(params->id, true);
    762   if (!extension) {
    763     error_ = ErrorUtils::FormatErrorMessage(keys::kNoExtensionError,
    764                                             params->id);
    765     return false;
    766   }
    767 
    768   if (!extension->is_app()) {
    769     error_ = ErrorUtils::FormatErrorMessage(keys::kNotAnAppError, params->id);
    770     return false;
    771   }
    772 
    773 #if defined(OS_MACOSX)
    774   if (!extension->is_platform_app()) {
    775     error_ = keys::kCreateOnlyPackagedAppShortcutMac;
    776     return false;
    777   }
    778 #endif
    779 
    780   Browser* browser = chrome::FindBrowserWithProfile(
    781       GetProfile(), chrome::HOST_DESKTOP_TYPE_NATIVE);
    782   if (!browser) {
    783     // Shouldn't happen if we have user gesture.
    784     error_ = keys::kNoBrowserToCreateShortcut;
    785     return false;
    786   }
    787 
    788   // Matched with a Release() in OnCloseShortcutPrompt().
    789   AddRef();
    790 
    791   if (auto_confirm_for_test == DO_NOT_SKIP) {
    792     chrome::ShowCreateChromeAppShortcutsDialog(
    793         browser->window()->GetNativeWindow(), browser->profile(), extension,
    794         base::Bind(&ManagementCreateAppShortcutFunction::OnCloseShortcutPrompt,
    795            this));
    796   } else {
    797     OnCloseShortcutPrompt(auto_confirm_for_test == PROCEED);
    798   }
    799 
    800   // Response is sent async in OnCloseShortcutPrompt().
    801   return true;
    802 }
    803 
    804 bool ManagementSetLaunchTypeFunction::RunSync() {
    805   if (!user_gesture()) {
    806     error_ = keys::kGestureNeededForSetLaunchTypeError;
    807     return false;
    808   }
    809 
    810   scoped_ptr<management::SetLaunchType::Params> params(
    811       management::SetLaunchType::Params::Create(*args_));
    812   EXTENSION_FUNCTION_VALIDATE(params.get());
    813   const Extension* extension = service()->GetExtensionById(params->id, true);
    814   if (!extension) {
    815     error_ =
    816         ErrorUtils::FormatErrorMessage(keys::kNoExtensionError, params->id);
    817     return false;
    818   }
    819 
    820   if (!extension->is_app()) {
    821     error_ = ErrorUtils::FormatErrorMessage(keys::kNotAnAppError, params->id);
    822     return false;
    823   }
    824 
    825   std::vector<management::LaunchType> available_launch_types =
    826       GetAvailableLaunchTypes(*extension);
    827 
    828   management::LaunchType app_launch_type = params->launch_type;
    829   if (std::find(available_launch_types.begin(),
    830                 available_launch_types.end(),
    831                 app_launch_type) == available_launch_types.end()) {
    832     error_ = keys::kLaunchTypeNotAvailableError;
    833     return false;
    834   }
    835 
    836   LaunchType launch_type = LAUNCH_TYPE_DEFAULT;
    837   switch (app_launch_type) {
    838     case management::LAUNCH_TYPE_OPEN_AS_PINNED_TAB:
    839       launch_type = LAUNCH_TYPE_PINNED;
    840       break;
    841     case management::LAUNCH_TYPE_OPEN_AS_REGULAR_TAB:
    842       launch_type = LAUNCH_TYPE_REGULAR;
    843       break;
    844     case management::LAUNCH_TYPE_OPEN_FULL_SCREEN:
    845       launch_type = LAUNCH_TYPE_FULLSCREEN;
    846       break;
    847     case management::LAUNCH_TYPE_OPEN_AS_WINDOW:
    848       launch_type = LAUNCH_TYPE_WINDOW;
    849       break;
    850     case management::LAUNCH_TYPE_NONE:
    851       NOTREACHED();
    852   }
    853 
    854   SetLaunchType(service(), params->id, launch_type);
    855 
    856   return true;
    857 }
    858 
    859 ManagementGenerateAppForLinkFunction::ManagementGenerateAppForLinkFunction() {
    860 }
    861 
    862 ManagementGenerateAppForLinkFunction::~ManagementGenerateAppForLinkFunction() {
    863 }
    864 
    865 void ManagementGenerateAppForLinkFunction::FinishCreateBookmarkApp(
    866     const Extension* extension,
    867     const WebApplicationInfo& web_app_info) {
    868   if (extension) {
    869     scoped_ptr<management::ExtensionInfo> info =
    870         CreateExtensionInfo(*extension, ExtensionSystem::Get(GetProfile()));
    871     results_ = management::GenerateAppForLink::Results::Create(*info);
    872 
    873     SendResponse(true);
    874     Release();
    875   } else {
    876     error_ = keys::kGenerateAppForLinkInstallError;
    877     SendResponse(false);
    878     Release();
    879   }
    880 }
    881 
    882 void ManagementGenerateAppForLinkFunction::OnFaviconForApp(
    883     const favicon_base::FaviconImageResult& image_result) {
    884   WebApplicationInfo web_app;
    885   web_app.title = base::UTF8ToUTF16(title_);
    886   web_app.app_url = launch_url_;
    887 
    888   if (!image_result.image.IsEmpty()) {
    889     WebApplicationInfo::IconInfo icon;
    890     icon.data = image_result.image.AsBitmap();
    891     icon.width = icon.data.width();
    892     icon.height = icon.data.height();
    893     web_app.icons.push_back(icon);
    894   }
    895 
    896   bookmark_app_helper_.reset(new BookmarkAppHelper(service(), web_app, NULL));
    897   bookmark_app_helper_->Create(base::Bind(
    898       &ManagementGenerateAppForLinkFunction::FinishCreateBookmarkApp, this));
    899 }
    900 
    901 bool ManagementGenerateAppForLinkFunction::RunAsync() {
    902   if (!user_gesture()) {
    903     error_ = keys::kGestureNeededForGenerateAppForLinkError;
    904     return false;
    905   }
    906 
    907   scoped_ptr<management::GenerateAppForLink::Params> params(
    908       management::GenerateAppForLink::Params::Create(*args_));
    909   EXTENSION_FUNCTION_VALIDATE(params.get());
    910 
    911   GURL launch_url(params->url);
    912   if (!launch_url.is_valid() || !launch_url.SchemeIsHTTPOrHTTPS()) {
    913     error_ = ErrorUtils::FormatErrorMessage(keys::kInvalidURLError,
    914                                             params->url);
    915     return false;
    916   }
    917 
    918   if (params->title.empty()) {
    919     error_ = keys::kEmptyTitleError;
    920     return false;
    921   }
    922 
    923   FaviconService* favicon_service =
    924       FaviconServiceFactory::GetForProfile(GetProfile(),
    925                                            Profile::EXPLICIT_ACCESS);
    926   DCHECK(favicon_service);
    927 
    928   title_ = params->title;
    929   launch_url_ = launch_url;
    930 
    931   favicon_service->GetFaviconImageForPageURL(
    932       launch_url,
    933       base::Bind(&ManagementGenerateAppForLinkFunction::OnFaviconForApp, this),
    934       &cancelable_task_tracker_);
    935 
    936   // Matched with a Release() in OnExtensionLoaded().
    937   AddRef();
    938 
    939   // Response is sent async in OnExtensionLoaded().
    940   return true;
    941 }
    942 
    943 ManagementEventRouter::ManagementEventRouter(content::BrowserContext* context)
    944     : browser_context_(context), extension_registry_observer_(this) {
    945   extension_registry_observer_.Add(ExtensionRegistry::Get(browser_context_));
    946 }
    947 
    948 ManagementEventRouter::~ManagementEventRouter() {}
    949 
    950 void ManagementEventRouter::OnExtensionLoaded(
    951     content::BrowserContext* browser_context,
    952     const Extension* extension) {
    953   BroadcastEvent(extension, management::OnEnabled::kEventName);
    954 }
    955 
    956 void ManagementEventRouter::OnExtensionUnloaded(
    957     content::BrowserContext* browser_context,
    958     const Extension* extension,
    959     UnloadedExtensionInfo::Reason reason) {
    960   BroadcastEvent(extension, management::OnDisabled::kEventName);
    961 }
    962 
    963 void ManagementEventRouter::OnExtensionInstalled(
    964     content::BrowserContext* browser_context,
    965     const Extension* extension,
    966     bool is_update) {
    967   BroadcastEvent(extension, management::OnInstalled::kEventName);
    968 }
    969 
    970 void ManagementEventRouter::OnExtensionUninstalled(
    971     content::BrowserContext* browser_context,
    972     const Extension* extension,
    973     extensions::UninstallReason reason) {
    974   BroadcastEvent(extension, management::OnUninstalled::kEventName);
    975 }
    976 
    977 void ManagementEventRouter::BroadcastEvent(const Extension* extension,
    978                                            const char* event_name) {
    979   if (ui_util::ShouldNotBeVisible(extension, browser_context_))
    980     return;  // Don't dispatch events for built-in extenions.
    981   scoped_ptr<base::ListValue> args(new base::ListValue());
    982   if (event_name == management::OnUninstalled::kEventName) {
    983     args->Append(new base::StringValue(extension->id()));
    984   } else {
    985     scoped_ptr<management::ExtensionInfo> info =
    986         CreateExtensionInfo(*extension, ExtensionSystem::Get(browser_context_));
    987     args->Append(info->ToValue().release());
    988   }
    989 
    990   EventRouter::Get(browser_context_)
    991       ->BroadcastEvent(scoped_ptr<Event>(new Event(event_name, args.Pass())));
    992 }
    993 
    994 ManagementAPI::ManagementAPI(content::BrowserContext* context)
    995     : browser_context_(context) {
    996   EventRouter* event_router = EventRouter::Get(browser_context_);
    997   event_router->RegisterObserver(this, management::OnInstalled::kEventName);
    998   event_router->RegisterObserver(this, management::OnUninstalled::kEventName);
    999   event_router->RegisterObserver(this, management::OnEnabled::kEventName);
   1000   event_router->RegisterObserver(this, management::OnDisabled::kEventName);
   1001 }
   1002 
   1003 ManagementAPI::~ManagementAPI() {
   1004 }
   1005 
   1006 void ManagementAPI::Shutdown() {
   1007   EventRouter::Get(browser_context_)->UnregisterObserver(this);
   1008 }
   1009 
   1010 static base::LazyInstance<BrowserContextKeyedAPIFactory<ManagementAPI> >
   1011     g_factory = LAZY_INSTANCE_INITIALIZER;
   1012 
   1013 // static
   1014 BrowserContextKeyedAPIFactory<ManagementAPI>*
   1015 ManagementAPI::GetFactoryInstance() {
   1016   return g_factory.Pointer();
   1017 }
   1018 
   1019 void ManagementAPI::OnListenerAdded(const EventListenerInfo& details) {
   1020   management_event_router_.reset(new ManagementEventRouter(browser_context_));
   1021   EventRouter::Get(browser_context_)->UnregisterObserver(this);
   1022 }
   1023 
   1024 }  // namespace extensions
   1025