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