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