Home | History | Annotate | Download | only in webstore_private
      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/webstore_private/webstore_private_api.h"
      6 
      7 #include "base/bind_helpers.h"
      8 #include "base/command_line.h"
      9 #include "base/lazy_instance.h"
     10 #include "base/memory/scoped_vector.h"
     11 #include "base/metrics/histogram.h"
     12 #include "base/prefs/pref_service.h"
     13 #include "base/strings/string_util.h"
     14 #include "base/strings/utf_string_conversions.h"
     15 #include "base/values.h"
     16 #include "chrome/browser/about_flags.h"
     17 #include "chrome/browser/browser_process.h"
     18 #include "chrome/browser/chrome_notification_types.h"
     19 #include "chrome/browser/extensions/crx_installer.h"
     20 #include "chrome/browser/extensions/extension_function_dispatcher.h"
     21 #include "chrome/browser/extensions/extension_prefs.h"
     22 #include "chrome/browser/extensions/extension_service.h"
     23 #include "chrome/browser/extensions/extension_system.h"
     24 #include "chrome/browser/extensions/webstore_installer.h"
     25 #include "chrome/browser/gpu/gpu_feature_checker.h"
     26 #include "chrome/browser/profiles/profile_manager.h"
     27 #include "chrome/browser/signin/signin_manager.h"
     28 #include "chrome/browser/signin/signin_manager_factory.h"
     29 #include "chrome/browser/sync/profile_sync_service.h"
     30 #include "chrome/browser/sync/profile_sync_service_factory.h"
     31 #include "chrome/browser/ui/app_list/app_list_service.h"
     32 #include "chrome/browser/ui/app_list/app_list_util.h"
     33 #include "chrome/browser/ui/browser.h"
     34 #include "chrome/common/extensions/extension_constants.h"
     35 #include "chrome/common/extensions/extension_l10n_util.h"
     36 #include "chrome/common/pref_names.h"
     37 #include "content/public/browser/gpu_data_manager.h"
     38 #include "content/public/browser/notification_details.h"
     39 #include "content/public/browser/notification_source.h"
     40 #include "content/public/browser/web_contents.h"
     41 #include "extensions/common/error_utils.h"
     42 #include "extensions/common/extension.h"
     43 #include "grit/chromium_strings.h"
     44 #include "grit/generated_resources.h"
     45 #include "ui/base/l10n/l10n_util.h"
     46 
     47 using content::GpuDataManager;
     48 
     49 namespace extensions {
     50 
     51 namespace BeginInstallWithManifest3 =
     52     api::webstore_private::BeginInstallWithManifest3;
     53 namespace CompleteInstall = api::webstore_private::CompleteInstall;
     54 namespace GetBrowserLogin = api::webstore_private::GetBrowserLogin;
     55 namespace GetIsLauncherEnabled = api::webstore_private::GetIsLauncherEnabled;
     56 namespace GetStoreLogin = api::webstore_private::GetStoreLogin;
     57 namespace GetWebGLStatus = api::webstore_private::GetWebGLStatus;
     58 namespace InstallBundle = api::webstore_private::InstallBundle;
     59 namespace IsInIncognitoMode = api::webstore_private::IsInIncognitoMode;
     60 namespace SetStoreLogin = api::webstore_private::SetStoreLogin;
     61 
     62 namespace {
     63 
     64 // Holds the Approvals between the time we prompt and start the installs.
     65 class PendingApprovals {
     66  public:
     67   PendingApprovals();
     68   ~PendingApprovals();
     69 
     70   void PushApproval(scoped_ptr<WebstoreInstaller::Approval> approval);
     71   scoped_ptr<WebstoreInstaller::Approval> PopApproval(
     72       Profile* profile, const std::string& id);
     73  private:
     74   typedef ScopedVector<WebstoreInstaller::Approval> ApprovalList;
     75 
     76   ApprovalList approvals_;
     77 
     78   DISALLOW_COPY_AND_ASSIGN(PendingApprovals);
     79 };
     80 
     81 PendingApprovals::PendingApprovals() {}
     82 PendingApprovals::~PendingApprovals() {}
     83 
     84 void PendingApprovals::PushApproval(
     85     scoped_ptr<WebstoreInstaller::Approval> approval) {
     86   approvals_.push_back(approval.release());
     87 }
     88 
     89 scoped_ptr<WebstoreInstaller::Approval> PendingApprovals::PopApproval(
     90     Profile* profile, const std::string& id) {
     91   for (size_t i = 0; i < approvals_.size(); ++i) {
     92     WebstoreInstaller::Approval* approval = approvals_[i];
     93     if (approval->extension_id == id &&
     94         profile->IsSameProfile(approval->profile)) {
     95       approvals_.weak_erase(approvals_.begin() + i);
     96       return scoped_ptr<WebstoreInstaller::Approval>(approval);
     97     }
     98   }
     99   return scoped_ptr<WebstoreInstaller::Approval>();
    100 }
    101 
    102 // Uniquely holds the profile and extension id of an install between the time we
    103 // prompt and complete the installs.
    104 class PendingInstalls {
    105  public:
    106   PendingInstalls();
    107   ~PendingInstalls();
    108 
    109   bool InsertInstall(Profile* profile, const std::string& id);
    110   void EraseInstall(Profile* profile, const std::string& id);
    111  private:
    112   typedef std::pair<Profile*, std::string> ProfileAndExtensionId;
    113   typedef std::vector<ProfileAndExtensionId> InstallList;
    114 
    115   InstallList::iterator FindInstall(Profile* profile, const std::string& id);
    116 
    117   InstallList installs_;
    118 
    119   DISALLOW_COPY_AND_ASSIGN(PendingInstalls);
    120 };
    121 
    122 PendingInstalls::PendingInstalls() {}
    123 PendingInstalls::~PendingInstalls() {}
    124 
    125 // Returns true and inserts the profile/id pair if it is not present. Otherwise
    126 // returns false.
    127 bool PendingInstalls::InsertInstall(Profile* profile, const std::string& id) {
    128   if (FindInstall(profile, id) != installs_.end())
    129     return false;
    130   installs_.push_back(make_pair(profile, id));
    131   return true;
    132 }
    133 
    134 // Removes the given profile/id pair.
    135 void PendingInstalls::EraseInstall(Profile* profile, const std::string& id) {
    136   InstallList::iterator it = FindInstall(profile, id);
    137   if (it != installs_.end())
    138     installs_.erase(it);
    139 }
    140 
    141 PendingInstalls::InstallList::iterator PendingInstalls::FindInstall(
    142     Profile* profile,
    143     const std::string& id) {
    144   for (size_t i = 0; i < installs_.size(); ++i) {
    145     ProfileAndExtensionId install = installs_[i];
    146     if (install.second == id && profile->IsSameProfile(install.first))
    147       return (installs_.begin() + i);
    148   }
    149   return installs_.end();
    150 }
    151 
    152 static base::LazyInstance<PendingApprovals> g_pending_approvals =
    153     LAZY_INSTANCE_INITIALIZER;
    154 static base::LazyInstance<PendingInstalls> g_pending_installs =
    155     LAZY_INSTANCE_INITIALIZER;
    156 
    157 // A preference set by the web store to indicate login information for
    158 // purchased apps.
    159 const char kWebstoreLogin[] = "extensions.webstore_login";
    160 const char kAlreadyInstalledError[] = "This item is already installed";
    161 const char kCannotSpecifyIconDataAndUrlError[] =
    162     "You cannot specify both icon data and an icon url";
    163 const char kInvalidIconUrlError[] = "Invalid icon url";
    164 const char kInvalidIdError[] = "Invalid id";
    165 const char kInvalidManifestError[] = "Invalid manifest";
    166 const char kNoPreviousBeginInstallWithManifestError[] =
    167     "* does not match a previous call to beginInstallWithManifest3";
    168 const char kUserCancelledError[] = "User cancelled install";
    169 
    170 WebstoreInstaller::Delegate* test_webstore_installer_delegate = NULL;
    171 
    172 // We allow the web store to set a string containing login information when a
    173 // purchase is made, so that when a user logs into sync with a different
    174 // account we can recognize the situation. The Get function returns the login if
    175 // there was previously stored data, or an empty string otherwise. The Set will
    176 // overwrite any previous login.
    177 std::string GetWebstoreLogin(Profile* profile) {
    178   if (profile->GetPrefs()->HasPrefPath(kWebstoreLogin))
    179     return profile->GetPrefs()->GetString(kWebstoreLogin);
    180   return std::string();
    181 }
    182 
    183 void SetWebstoreLogin(Profile* profile, const std::string& login) {
    184   profile->GetPrefs()->SetString(kWebstoreLogin, login);
    185 }
    186 
    187 void RecordWebstoreExtensionInstallResult(bool success) {
    188   UMA_HISTOGRAM_BOOLEAN("Webstore.ExtensionInstallResult", success);
    189 }
    190 
    191 }  // namespace
    192 
    193 // static
    194 void WebstorePrivateApi::SetWebstoreInstallerDelegateForTesting(
    195     WebstoreInstaller::Delegate* delegate) {
    196   test_webstore_installer_delegate = delegate;
    197 }
    198 
    199 // static
    200 scoped_ptr<WebstoreInstaller::Approval>
    201 WebstorePrivateApi::PopApprovalForTesting(
    202     Profile* profile, const std::string& extension_id) {
    203   return g_pending_approvals.Get().PopApproval(profile, extension_id);
    204 }
    205 
    206 WebstorePrivateInstallBundleFunction::WebstorePrivateInstallBundleFunction() {}
    207 WebstorePrivateInstallBundleFunction::~WebstorePrivateInstallBundleFunction() {}
    208 
    209 bool WebstorePrivateInstallBundleFunction::RunImpl() {
    210   scoped_ptr<InstallBundle::Params> params(
    211       InstallBundle::Params::Create(*args_));
    212   EXTENSION_FUNCTION_VALIDATE(params);
    213 
    214   BundleInstaller::ItemList items;
    215   if (!ReadBundleInfo(*params, &items))
    216     return false;
    217 
    218   bundle_ = new BundleInstaller(GetCurrentBrowser(), items);
    219 
    220   AddRef();  // Balanced in OnBundleInstallCompleted / OnBundleInstallCanceled.
    221 
    222   bundle_->PromptForApproval(this);
    223   return true;
    224 }
    225 
    226 bool WebstorePrivateInstallBundleFunction::
    227     ReadBundleInfo(const InstallBundle::Params& params,
    228     BundleInstaller::ItemList* items) {
    229   for (size_t i = 0; i < params.details.size(); ++i) {
    230     BundleInstaller::Item item;
    231     item.id = params.details[i]->id;
    232     item.manifest = params.details[i]->manifest;
    233     item.localized_name = params.details[i]->localized_name;
    234     items->push_back(item);
    235   }
    236 
    237   return true;
    238 }
    239 
    240 void WebstorePrivateInstallBundleFunction::OnBundleInstallApproved() {
    241   bundle_->CompleteInstall(
    242       &(dispatcher()->delegate()->GetAssociatedWebContents()->GetController()),
    243       this);
    244 }
    245 
    246 void WebstorePrivateInstallBundleFunction::OnBundleInstallCanceled(
    247     bool user_initiated) {
    248   if (user_initiated)
    249     error_ = "user_canceled";
    250   else
    251     error_ = "unknown_error";
    252 
    253   SendResponse(false);
    254 
    255   Release();  // Balanced in RunImpl().
    256 }
    257 
    258 void WebstorePrivateInstallBundleFunction::OnBundleInstallCompleted() {
    259   SendResponse(true);
    260 
    261   Release();  // Balanced in RunImpl().
    262 }
    263 
    264 WebstorePrivateBeginInstallWithManifest3Function::
    265     WebstorePrivateBeginInstallWithManifest3Function() {}
    266 
    267 WebstorePrivateBeginInstallWithManifest3Function::
    268     ~WebstorePrivateBeginInstallWithManifest3Function() {}
    269 
    270 bool WebstorePrivateBeginInstallWithManifest3Function::RunImpl() {
    271   params_ = BeginInstallWithManifest3::Params::Create(*args_);
    272   EXTENSION_FUNCTION_VALIDATE(params_);
    273 
    274   if (!extensions::Extension::IdIsValid(params_->details.id)) {
    275     SetResultCode(INVALID_ID);
    276     error_ = kInvalidIdError;
    277     return false;
    278   }
    279 
    280   if (params_->details.icon_data && params_->details.icon_url) {
    281     SetResultCode(ICON_ERROR);
    282     error_ = kCannotSpecifyIconDataAndUrlError;
    283     return false;
    284   }
    285 
    286   GURL icon_url;
    287   if (params_->details.icon_url) {
    288     std::string tmp_url;
    289     icon_url = source_url().Resolve(*params_->details.icon_url);
    290     if (!icon_url.is_valid()) {
    291       SetResultCode(INVALID_ICON_URL);
    292       error_ = kInvalidIconUrlError;
    293       return false;
    294     }
    295   }
    296 
    297   std::string icon_data = params_->details.icon_data ?
    298       *params_->details.icon_data : std::string();
    299 
    300   ExtensionService* service =
    301       extensions::ExtensionSystem::Get(GetProfile())->extension_service();
    302   if (service->GetInstalledExtension(params_->details.id) ||
    303       !g_pending_installs.Get().InsertInstall(GetProfile(),
    304                                               params_->details.id)) {
    305     SetResultCode(ALREADY_INSTALLED);
    306     error_ = kAlreadyInstalledError;
    307     return false;
    308   }
    309 
    310   net::URLRequestContextGetter* context_getter = NULL;
    311   if (!icon_url.is_empty())
    312     context_getter = GetProfile()->GetRequestContext();
    313 
    314   scoped_refptr<WebstoreInstallHelper> helper = new WebstoreInstallHelper(
    315       this, params_->details.id, params_->details.manifest, icon_data, icon_url,
    316           context_getter);
    317 
    318   // The helper will call us back via OnWebstoreParseSuccess or
    319   // OnWebstoreParseFailure.
    320   helper->Start();
    321 
    322   // Matched with a Release in OnWebstoreParseSuccess/OnWebstoreParseFailure.
    323   AddRef();
    324 
    325   // The response is sent asynchronously in OnWebstoreParseSuccess/
    326   // OnWebstoreParseFailure.
    327   return true;
    328 }
    329 
    330 const char* WebstorePrivateBeginInstallWithManifest3Function::
    331     ResultCodeToString(ResultCode code) {
    332   switch (code) {
    333     case ERROR_NONE:
    334       return "";
    335     case UNKNOWN_ERROR:
    336       return "unknown_error";
    337     case USER_CANCELLED:
    338       return "user_cancelled";
    339     case MANIFEST_ERROR:
    340       return "manifest_error";
    341     case ICON_ERROR:
    342       return "icon_error";
    343     case INVALID_ID:
    344       return "invalid_id";
    345     case PERMISSION_DENIED:
    346       return "permission_denied";
    347     case INVALID_ICON_URL:
    348       return "invalid_icon_url";
    349     case SIGNIN_FAILED:
    350       return "signin_failed";
    351     case ALREADY_INSTALLED:
    352       return "already_installed";
    353   }
    354   NOTREACHED();
    355   return "";
    356 }
    357 
    358 void WebstorePrivateBeginInstallWithManifest3Function::SetResultCode(
    359     ResultCode code) {
    360   results_ = BeginInstallWithManifest3::Results::Create(
    361       ResultCodeToString(code));
    362 }
    363 
    364 void WebstorePrivateBeginInstallWithManifest3Function::OnWebstoreParseSuccess(
    365     const std::string& id,
    366     const SkBitmap& icon,
    367     base::DictionaryValue* parsed_manifest) {
    368   CHECK_EQ(params_->details.id, id);
    369   CHECK(parsed_manifest);
    370   icon_ = icon;
    371   parsed_manifest_.reset(parsed_manifest);
    372 
    373   std::string localized_name = params_->details.localized_name ?
    374       *params_->details.localized_name : std::string();
    375 
    376   std::string error;
    377   dummy_extension_ = ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
    378       parsed_manifest_.get(),
    379       Extension::FROM_WEBSTORE,
    380       id,
    381       localized_name,
    382       std::string(),
    383       &error);
    384 
    385   if (!dummy_extension_.get()) {
    386     OnWebstoreParseFailure(params_->details.id,
    387                            WebstoreInstallHelper::Delegate::MANIFEST_ERROR,
    388                            kInvalidManifestError);
    389     return;
    390   }
    391 
    392   SigninManagerBase* signin_manager =
    393       SigninManagerFactory::GetForProfile(GetProfile());
    394   if (dummy_extension_->is_platform_app() &&
    395       signin_manager &&
    396       signin_manager->GetAuthenticatedUsername().empty() &&
    397       signin_manager->AuthInProgress()) {
    398     signin_tracker_.reset(new SigninTracker(GetProfile(), this));
    399     return;
    400   }
    401 
    402   SigninCompletedOrNotNeeded();
    403 }
    404 
    405 void WebstorePrivateBeginInstallWithManifest3Function::OnWebstoreParseFailure(
    406     const std::string& id,
    407     WebstoreInstallHelper::Delegate::InstallHelperResultCode result_code,
    408     const std::string& error_message) {
    409   CHECK_EQ(params_->details.id, id);
    410 
    411   // Map from WebstoreInstallHelper's result codes to ours.
    412   switch (result_code) {
    413     case WebstoreInstallHelper::Delegate::UNKNOWN_ERROR:
    414       SetResultCode(UNKNOWN_ERROR);
    415       break;
    416     case WebstoreInstallHelper::Delegate::ICON_ERROR:
    417       SetResultCode(ICON_ERROR);
    418       break;
    419     case WebstoreInstallHelper::Delegate::MANIFEST_ERROR:
    420       SetResultCode(MANIFEST_ERROR);
    421       break;
    422     default:
    423       CHECK(false);
    424   }
    425   error_ = error_message;
    426   g_pending_installs.Get().EraseInstall(GetProfile(), id);
    427   SendResponse(false);
    428 
    429   // Matches the AddRef in RunImpl().
    430   Release();
    431 }
    432 
    433 void WebstorePrivateBeginInstallWithManifest3Function::SigninFailed(
    434     const GoogleServiceAuthError& error) {
    435   signin_tracker_.reset();
    436 
    437   SetResultCode(SIGNIN_FAILED);
    438   error_ = error.ToString();
    439   g_pending_installs.Get().EraseInstall(GetProfile(), params_->details.id);
    440   SendResponse(false);
    441 
    442   // Matches the AddRef in RunImpl().
    443   Release();
    444 }
    445 
    446 void WebstorePrivateBeginInstallWithManifest3Function::SigninSuccess() {
    447   signin_tracker_.reset();
    448 
    449   SigninCompletedOrNotNeeded();
    450 }
    451 
    452 void WebstorePrivateBeginInstallWithManifest3Function::
    453     SigninCompletedOrNotNeeded() {
    454   content::WebContents* web_contents = GetAssociatedWebContents();
    455   if (!web_contents)  // The browser window has gone away.
    456     return;
    457   install_prompt_.reset(new ExtensionInstallPrompt(web_contents));
    458   install_prompt_->ConfirmWebstoreInstall(
    459       this,
    460       dummy_extension_.get(),
    461       &icon_,
    462       ExtensionInstallPrompt::GetDefaultShowDialogCallback());
    463   // Control flow finishes up in InstallUIProceed or InstallUIAbort.
    464 }
    465 
    466 void WebstorePrivateBeginInstallWithManifest3Function::InstallUIProceed() {
    467   // This gets cleared in CrxInstaller::ConfirmInstall(). TODO(asargent) - in
    468   // the future we may also want to add time-based expiration, where a whitelist
    469   // entry is only valid for some number of minutes.
    470   scoped_ptr<WebstoreInstaller::Approval> approval(
    471       WebstoreInstaller::Approval::CreateWithNoInstallPrompt(
    472           GetProfile(), params_->details.id, parsed_manifest_.Pass(), false));
    473   approval->use_app_installed_bubble = params_->details.app_install_bubble;
    474   approval->enable_launcher = params_->details.enable_launcher;
    475   // If we are enabling the launcher, we should not show the app list in order
    476   // to train the user to open it themselves at least once.
    477   approval->skip_post_install_ui = params_->details.enable_launcher;
    478   approval->dummy_extension = dummy_extension_;
    479   approval->installing_icon = gfx::ImageSkia::CreateFrom1xBitmap(icon_);
    480   g_pending_approvals.Get().PushApproval(approval.Pass());
    481 
    482   SetResultCode(ERROR_NONE);
    483   SendResponse(true);
    484 
    485   // The Permissions_Install histogram is recorded from the ExtensionService
    486   // for all extension installs, so we only need to record the web store
    487   // specific histogram here.
    488   ExtensionService::RecordPermissionMessagesHistogram(
    489       dummy_extension_.get(), "Extensions.Permissions_WebStoreInstall");
    490 
    491   // Matches the AddRef in RunImpl().
    492   Release();
    493 }
    494 
    495 void WebstorePrivateBeginInstallWithManifest3Function::InstallUIAbort(
    496     bool user_initiated) {
    497   error_ = kUserCancelledError;
    498   SetResultCode(USER_CANCELLED);
    499   g_pending_installs.Get().EraseInstall(GetProfile(), params_->details.id);
    500   SendResponse(false);
    501 
    502   // The web store install histograms are a subset of the install histograms.
    503   // We need to record both histograms here since CrxInstaller::InstallUIAbort
    504   // is never called for web store install cancellations.
    505   std::string histogram_name = user_initiated ?
    506       "Extensions.Permissions_WebStoreInstallCancel" :
    507       "Extensions.Permissions_WebStoreInstallAbort";
    508   ExtensionService::RecordPermissionMessagesHistogram(dummy_extension_.get(),
    509                                                       histogram_name.c_str());
    510 
    511   histogram_name = user_initiated ?
    512       "Extensions.Permissions_InstallCancel" :
    513       "Extensions.Permissions_InstallAbort";
    514   ExtensionService::RecordPermissionMessagesHistogram(dummy_extension_.get(),
    515                                                       histogram_name.c_str());
    516 
    517   // Matches the AddRef in RunImpl().
    518   Release();
    519 }
    520 
    521 WebstorePrivateCompleteInstallFunction::
    522     WebstorePrivateCompleteInstallFunction() {}
    523 
    524 WebstorePrivateCompleteInstallFunction::
    525     ~WebstorePrivateCompleteInstallFunction() {}
    526 
    527 bool WebstorePrivateCompleteInstallFunction::RunImpl() {
    528   scoped_ptr<CompleteInstall::Params> params(
    529       CompleteInstall::Params::Create(*args_));
    530   EXTENSION_FUNCTION_VALIDATE(params);
    531   if (!extensions::Extension::IdIsValid(params->expected_id)) {
    532     error_ = kInvalidIdError;
    533     return false;
    534   }
    535 
    536   approval_ = g_pending_approvals.Get()
    537                   .PopApproval(GetProfile(), params->expected_id)
    538                   .Pass();
    539   if (!approval_) {
    540     error_ = ErrorUtils::FormatErrorMessage(
    541         kNoPreviousBeginInstallWithManifestError, params->expected_id);
    542     return false;
    543   }
    544 
    545   // Balanced in OnExtensionInstallSuccess() or OnExtensionInstallFailure().
    546   AddRef();
    547   AppListService* app_list_service =
    548       AppListService::Get(GetCurrentBrowser()->host_desktop_type());
    549 
    550   if (approval_->enable_launcher)
    551     app_list_service->EnableAppList(GetProfile());
    552 
    553   if (IsAppLauncherEnabled() && approval_->manifest->is_app()) {
    554     // Show the app list to show download is progressing. Don't show the app
    555     // list on first app install so users can be trained to open it themselves.
    556     if (approval_->enable_launcher)
    557       app_list_service->CreateForProfile(GetProfile());
    558     else
    559       app_list_service->ShowForProfile(GetProfile());
    560   }
    561 
    562   // The extension will install through the normal extension install flow, but
    563   // the whitelist entry will bypass the normal permissions install dialog.
    564   scoped_refptr<WebstoreInstaller> installer = new WebstoreInstaller(
    565       GetProfile(),
    566       this,
    567       &(dispatcher()->delegate()->GetAssociatedWebContents()->GetController()),
    568       params->expected_id,
    569       approval_.Pass(),
    570       WebstoreInstaller::INSTALL_SOURCE_OTHER);
    571   installer->Start();
    572 
    573   return true;
    574 }
    575 
    576 void WebstorePrivateCompleteInstallFunction::OnExtensionInstallSuccess(
    577     const std::string& id) {
    578   if (test_webstore_installer_delegate)
    579     test_webstore_installer_delegate->OnExtensionInstallSuccess(id);
    580 
    581   LOG(INFO) << "Install success, sending response";
    582   g_pending_installs.Get().EraseInstall(GetProfile(), id);
    583   SendResponse(true);
    584 
    585   RecordWebstoreExtensionInstallResult(true);
    586 
    587   // Matches the AddRef in RunImpl().
    588   Release();
    589 }
    590 
    591 void WebstorePrivateCompleteInstallFunction::OnExtensionInstallFailure(
    592     const std::string& id,
    593     const std::string& error,
    594     WebstoreInstaller::FailureReason reason) {
    595   if (test_webstore_installer_delegate) {
    596     test_webstore_installer_delegate->OnExtensionInstallFailure(
    597         id, error, reason);
    598   }
    599 
    600   error_ = error;
    601   LOG(INFO) << "Install failed, sending response";
    602   g_pending_installs.Get().EraseInstall(GetProfile(), id);
    603   SendResponse(false);
    604 
    605   RecordWebstoreExtensionInstallResult(false);
    606 
    607   // Matches the AddRef in RunImpl().
    608   Release();
    609 }
    610 
    611 WebstorePrivateEnableAppLauncherFunction::
    612     WebstorePrivateEnableAppLauncherFunction() {}
    613 
    614 WebstorePrivateEnableAppLauncherFunction::
    615     ~WebstorePrivateEnableAppLauncherFunction() {}
    616 
    617 bool WebstorePrivateEnableAppLauncherFunction::RunImpl() {
    618   AppListService::Get(GetCurrentBrowser()->host_desktop_type())->
    619       EnableAppList(GetProfile());
    620   return true;
    621 }
    622 
    623 bool WebstorePrivateGetBrowserLoginFunction::RunImpl() {
    624   GetBrowserLogin::Results::Info info;
    625   info.login = GetProfile()->GetOriginalProfile()->GetPrefs()->GetString(
    626       prefs::kGoogleServicesUsername);
    627   results_ = GetBrowserLogin::Results::Create(info);
    628   return true;
    629 }
    630 
    631 bool WebstorePrivateGetStoreLoginFunction::RunImpl() {
    632   results_ = GetStoreLogin::Results::Create(GetWebstoreLogin(GetProfile()));
    633   return true;
    634 }
    635 
    636 bool WebstorePrivateSetStoreLoginFunction::RunImpl() {
    637   scoped_ptr<SetStoreLogin::Params> params(
    638       SetStoreLogin::Params::Create(*args_));
    639   EXTENSION_FUNCTION_VALIDATE(params);
    640   SetWebstoreLogin(GetProfile(), params->login);
    641   return true;
    642 }
    643 
    644 WebstorePrivateGetWebGLStatusFunction::WebstorePrivateGetWebGLStatusFunction() {
    645   feature_checker_ = new GPUFeatureChecker(
    646       gpu::GPU_FEATURE_TYPE_WEBGL,
    647       base::Bind(&WebstorePrivateGetWebGLStatusFunction::OnFeatureCheck,
    648           base::Unretained(this)));
    649 }
    650 
    651 WebstorePrivateGetWebGLStatusFunction::
    652     ~WebstorePrivateGetWebGLStatusFunction() {}
    653 
    654 void WebstorePrivateGetWebGLStatusFunction::CreateResult(bool webgl_allowed) {
    655   results_ = GetWebGLStatus::Results::Create(GetWebGLStatus::Results::
    656       ParseWebgl_status(webgl_allowed ? "webgl_allowed" : "webgl_blocked"));
    657 }
    658 
    659 bool WebstorePrivateGetWebGLStatusFunction::RunImpl() {
    660   feature_checker_->CheckGPUFeatureAvailability();
    661   return true;
    662 }
    663 
    664 void WebstorePrivateGetWebGLStatusFunction::
    665     OnFeatureCheck(bool feature_allowed) {
    666   CreateResult(feature_allowed);
    667   SendResponse(true);
    668 }
    669 
    670 bool WebstorePrivateGetIsLauncherEnabledFunction::RunImpl() {
    671   results_ = GetIsLauncherEnabled::Results::Create(IsAppLauncherEnabled());
    672   return true;
    673 }
    674 
    675 bool WebstorePrivateIsInIncognitoModeFunction::RunImpl() {
    676   results_ = IsInIncognitoMode::Results::Create(
    677       GetProfile() != GetProfile()->GetOriginalProfile());
    678   return true;
    679 }
    680 
    681 }  // namespace extensions
    682