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