Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(114)

Side by Side Diff: chrome/browser/extensions/api/webstore_private/webstore_private_api.cc

Issue 389613006: Prevent duplicate concurrent installs of the same extension (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixed rebase Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/api/webstore_private/webstore_private_api.h" 5 #include "chrome/browser/extensions/api/webstore_private/webstore_private_api.h"
6 6
7 #include "base/bind_helpers.h" 7 #include "base/bind_helpers.h"
8 #include "base/command_line.h" 8 #include "base/command_line.h"
9 #include "base/lazy_instance.h" 9 #include "base/lazy_instance.h"
10 #include "base/memory/scoped_vector.h" 10 #include "base/memory/scoped_vector.h"
11 #include "base/metrics/histogram.h" 11 #include "base/metrics/histogram.h"
12 #include "base/prefs/pref_service.h" 12 #include "base/prefs/pref_service.h"
13 #include "base/strings/string_util.h" 13 #include "base/strings/string_util.h"
14 #include "base/strings/stringprintf.h" 14 #include "base/strings/stringprintf.h"
15 #include "base/strings/utf_string_conversions.h" 15 #include "base/strings/utf_string_conversions.h"
16 #include "base/values.h" 16 #include "base/values.h"
17 #include "base/version.h" 17 #include "base/version.h"
18 #include "chrome/browser/about_flags.h" 18 #include "chrome/browser/about_flags.h"
19 #include "chrome/browser/apps/ephemeral_app_launcher.h" 19 #include "chrome/browser/apps/ephemeral_app_launcher.h"
20 #include "chrome/browser/browser_process.h" 20 #include "chrome/browser/browser_process.h"
21 #include "chrome/browser/chrome_notification_types.h" 21 #include "chrome/browser/chrome_notification_types.h"
22 #include "chrome/browser/extensions/crx_installer.h" 22 #include "chrome/browser/extensions/crx_installer.h"
23 #include "chrome/browser/extensions/extension_service.h" 23 #include "chrome/browser/extensions/extension_service.h"
24 #include "chrome/browser/extensions/install_tracker.h"
24 #include "chrome/browser/extensions/webstore_installer.h" 25 #include "chrome/browser/extensions/webstore_installer.h"
25 #include "chrome/browser/gpu/gpu_feature_checker.h" 26 #include "chrome/browser/gpu/gpu_feature_checker.h"
26 #include "chrome/browser/profiles/profile_manager.h" 27 #include "chrome/browser/profiles/profile_manager.h"
27 #include "chrome/browser/signin/signin_manager_factory.h" 28 #include "chrome/browser/signin/signin_manager_factory.h"
28 #include "chrome/browser/signin/signin_promo.h" 29 #include "chrome/browser/signin/signin_promo.h"
29 #include "chrome/browser/signin/signin_tracker_factory.h" 30 #include "chrome/browser/signin/signin_tracker_factory.h"
30 #include "chrome/browser/sync/profile_sync_service.h" 31 #include "chrome/browser/sync/profile_sync_service.h"
31 #include "chrome/browser/sync/profile_sync_service_factory.h" 32 #include "chrome/browser/sync/profile_sync_service_factory.h"
32 #include "chrome/browser/ui/app_list/app_list_service.h" 33 #include "chrome/browser/ui/app_list/app_list_service.h"
33 #include "chrome/browser/ui/app_list/app_list_util.h" 34 #include "chrome/browser/ui/app_list/app_list_util.h"
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
109 WebstoreInstaller::Approval* approval = approvals_[i]; 110 WebstoreInstaller::Approval* approval = approvals_[i];
110 if (approval->extension_id == id && 111 if (approval->extension_id == id &&
111 profile->IsSameProfile(approval->profile)) { 112 profile->IsSameProfile(approval->profile)) {
112 approvals_.weak_erase(approvals_.begin() + i); 113 approvals_.weak_erase(approvals_.begin() + i);
113 return scoped_ptr<WebstoreInstaller::Approval>(approval); 114 return scoped_ptr<WebstoreInstaller::Approval>(approval);
114 } 115 }
115 } 116 }
116 return scoped_ptr<WebstoreInstaller::Approval>(); 117 return scoped_ptr<WebstoreInstaller::Approval>();
117 } 118 }
118 119
119 // Uniquely holds the profile and extension id of an install between the time we
120 // prompt and complete the installs.
121 class PendingInstalls {
122 public:
123 PendingInstalls();
124 ~PendingInstalls();
125
126 bool InsertInstall(Profile* profile, const std::string& id);
127 void EraseInstall(Profile* profile, const std::string& id);
128 bool ContainsInstall(Profile* profile, const std::string& id);
129 private:
130 typedef std::pair<Profile*, std::string> ProfileAndExtensionId;
131 typedef std::vector<ProfileAndExtensionId> InstallList;
132
133 InstallList::iterator FindInstall(Profile* profile, const std::string& id);
134
135 InstallList installs_;
136
137 DISALLOW_COPY_AND_ASSIGN(PendingInstalls);
138 };
139
140 PendingInstalls::PendingInstalls() {}
141 PendingInstalls::~PendingInstalls() {}
142
143 // Returns true and inserts the profile/id pair if it is not present. Otherwise
144 // returns false.
145 bool PendingInstalls::InsertInstall(Profile* profile, const std::string& id) {
146 if (FindInstall(profile, id) != installs_.end())
147 return false;
148 installs_.push_back(make_pair(profile, id));
149 return true;
150 }
151
152 // Removes the given profile/id pair.
153 void PendingInstalls::EraseInstall(Profile* profile, const std::string& id) {
154 InstallList::iterator it = FindInstall(profile, id);
155 if (it != installs_.end())
156 installs_.erase(it);
157 }
158
159 bool PendingInstalls::ContainsInstall(Profile* profile, const std::string& id) {
160 return FindInstall(profile, id) != installs_.end();
161 }
162
163 PendingInstalls::InstallList::iterator PendingInstalls::FindInstall(
164 Profile* profile,
165 const std::string& id) {
166 for (size_t i = 0; i < installs_.size(); ++i) {
167 ProfileAndExtensionId install = installs_[i];
168 if (install.second == id && profile->IsSameProfile(install.first))
169 return (installs_.begin() + i);
170 }
171 return installs_.end();
172 }
173
174 static base::LazyInstance<PendingApprovals> g_pending_approvals = 120 static base::LazyInstance<PendingApprovals> g_pending_approvals =
175 LAZY_INSTANCE_INITIALIZER; 121 LAZY_INSTANCE_INITIALIZER;
176 static base::LazyInstance<PendingInstalls> g_pending_installs =
177 LAZY_INSTANCE_INITIALIZER;
178 122
179 // A preference set by the web store to indicate login information for 123 // A preference set by the web store to indicate login information for
180 // purchased apps. 124 // purchased apps.
181 const char kWebstoreLogin[] = "extensions.webstore_login"; 125 const char kWebstoreLogin[] = "extensions.webstore_login";
182 const char kAlreadyInstalledError[] = "This item is already installed"; 126 const char kAlreadyInstalledError[] = "This item is already installed";
183 const char kCannotSpecifyIconDataAndUrlError[] = 127 const char kCannotSpecifyIconDataAndUrlError[] =
184 "You cannot specify both icon data and an icon url"; 128 "You cannot specify both icon data and an icon url";
185 const char kInvalidIconUrlError[] = "Invalid icon url"; 129 const char kInvalidIconUrlError[] = "Invalid icon url";
186 const char kInvalidIdError[] = "Invalid id"; 130 const char kInvalidIdError[] = "Invalid id";
187 const char kInvalidManifestError[] = "Invalid manifest"; 131 const char kInvalidManifestError[] = "Invalid manifest";
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
319 } 263 }
320 264
321 if (params_->details.authuser) { 265 if (params_->details.authuser) {
322 authuser_ = *params_->details.authuser; 266 authuser_ = *params_->details.authuser;
323 } 267 }
324 268
325 std::string icon_data = params_->details.icon_data ? 269 std::string icon_data = params_->details.icon_data ?
326 *params_->details.icon_data : std::string(); 270 *params_->details.icon_data : std::string();
327 271
328 Profile* profile = GetProfile(); 272 Profile* profile = GetProfile();
273 InstallTracker* tracker = InstallTracker::Get(profile);
274 DCHECK(tracker);
329 if (util::IsExtensionInstalledPermanently(params_->details.id, profile) || 275 if (util::IsExtensionInstalledPermanently(params_->details.id, profile) ||
330 !g_pending_installs.Get().InsertInstall(profile, params_->details.id)) { 276 tracker->GetActiveInstall(params_->details.id)) {
331 SetResultCode(ALREADY_INSTALLED); 277 SetResultCode(ALREADY_INSTALLED);
332 error_ = kAlreadyInstalledError; 278 error_ = kAlreadyInstalledError;
333 return false; 279 return false;
334 } 280 }
281 ActiveInstallData install_data(params_->details.id);
282 scoped_active_install_.reset(new ScopedActiveInstall(profile, install_data));
335 283
336 net::URLRequestContextGetter* context_getter = NULL; 284 net::URLRequestContextGetter* context_getter = NULL;
337 if (!icon_url.is_empty()) 285 if (!icon_url.is_empty())
338 context_getter = GetProfile()->GetRequestContext(); 286 context_getter = GetProfile()->GetRequestContext();
339 287
340 scoped_refptr<WebstoreInstallHelper> helper = new WebstoreInstallHelper( 288 scoped_refptr<WebstoreInstallHelper> helper = new WebstoreInstallHelper(
341 this, params_->details.id, params_->details.manifest, icon_data, icon_url, 289 this, params_->details.id, params_->details.manifest, icon_data, icon_url,
342 context_getter); 290 context_getter);
343 291
344 // The helper will call us back via OnWebstoreParseSuccess or 292 // The helper will call us back via OnWebstoreParseSuccess or
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
443 case WebstoreInstallHelper::Delegate::ICON_ERROR: 391 case WebstoreInstallHelper::Delegate::ICON_ERROR:
444 SetResultCode(ICON_ERROR); 392 SetResultCode(ICON_ERROR);
445 break; 393 break;
446 case WebstoreInstallHelper::Delegate::MANIFEST_ERROR: 394 case WebstoreInstallHelper::Delegate::MANIFEST_ERROR:
447 SetResultCode(MANIFEST_ERROR); 395 SetResultCode(MANIFEST_ERROR);
448 break; 396 break;
449 default: 397 default:
450 CHECK(false); 398 CHECK(false);
451 } 399 }
452 error_ = error_message; 400 error_ = error_message;
453 g_pending_installs.Get().EraseInstall(GetProfile(), id);
454 SendResponse(false); 401 SendResponse(false);
455 402
456 // Matches the AddRef in RunAsync(). 403 // Matches the AddRef in RunAsync().
457 Release(); 404 Release();
458 } 405 }
459 406
460 void WebstorePrivateBeginInstallWithManifest3Function::SigninFailed( 407 void WebstorePrivateBeginInstallWithManifest3Function::SigninFailed(
461 const GoogleServiceAuthError& error) { 408 const GoogleServiceAuthError& error) {
462 signin_tracker_.reset(); 409 signin_tracker_.reset();
463 410
464 SetResultCode(SIGNIN_FAILED); 411 SetResultCode(SIGNIN_FAILED);
465 error_ = error.ToString(); 412 error_ = error.ToString();
466 g_pending_installs.Get().EraseInstall(GetProfile(), params_->details.id);
467 SendResponse(false); 413 SendResponse(false);
468 414
469 // Matches the AddRef in RunAsync(). 415 // Matches the AddRef in RunAsync().
470 Release(); 416 Release();
471 } 417 }
472 418
473 void WebstorePrivateBeginInstallWithManifest3Function::SigninSuccess() { 419 void WebstorePrivateBeginInstallWithManifest3Function::SigninSuccess() {
474 signin_tracker_.reset(); 420 signin_tracker_.reset();
475 421
476 SigninCompletedOrNotNeeded(); 422 SigninCompletedOrNotNeeded();
(...skipping 30 matching lines...) Expand all
507 approval->use_app_installed_bubble = params_->details.app_install_bubble; 453 approval->use_app_installed_bubble = params_->details.app_install_bubble;
508 approval->enable_launcher = params_->details.enable_launcher; 454 approval->enable_launcher = params_->details.enable_launcher;
509 // If we are enabling the launcher, we should not show the app list in order 455 // If we are enabling the launcher, we should not show the app list in order
510 // to train the user to open it themselves at least once. 456 // to train the user to open it themselves at least once.
511 approval->skip_post_install_ui = params_->details.enable_launcher; 457 approval->skip_post_install_ui = params_->details.enable_launcher;
512 approval->dummy_extension = dummy_extension_; 458 approval->dummy_extension = dummy_extension_;
513 approval->installing_icon = gfx::ImageSkia::CreateFrom1xBitmap(icon_); 459 approval->installing_icon = gfx::ImageSkia::CreateFrom1xBitmap(icon_);
514 approval->authuser = authuser_; 460 approval->authuser = authuser_;
515 g_pending_approvals.Get().PushApproval(approval.Pass()); 461 g_pending_approvals.Get().PushApproval(approval.Pass());
516 462
463 DCHECK(scoped_active_install_.get());
464 scoped_active_install_->CancelDeregister();
465
517 SetResultCode(ERROR_NONE); 466 SetResultCode(ERROR_NONE);
518 SendResponse(true); 467 SendResponse(true);
519 468
520 // The Permissions_Install histogram is recorded from the ExtensionService 469 // The Permissions_Install histogram is recorded from the ExtensionService
521 // for all extension installs, so we only need to record the web store 470 // for all extension installs, so we only need to record the web store
522 // specific histogram here. 471 // specific histogram here.
523 ExtensionService::RecordPermissionMessagesHistogram( 472 ExtensionService::RecordPermissionMessagesHistogram(
524 dummy_extension_.get(), "Extensions.Permissions_WebStoreInstall2"); 473 dummy_extension_.get(), "Extensions.Permissions_WebStoreInstall2");
525 474
526 // Matches the AddRef in RunAsync(). 475 // Matches the AddRef in RunAsync().
527 Release(); 476 Release();
528 } 477 }
529 478
530 void WebstorePrivateBeginInstallWithManifest3Function::InstallUIAbort( 479 void WebstorePrivateBeginInstallWithManifest3Function::InstallUIAbort(
531 bool user_initiated) { 480 bool user_initiated) {
532 error_ = kUserCancelledError; 481 error_ = kUserCancelledError;
533 SetResultCode(USER_CANCELLED); 482 SetResultCode(USER_CANCELLED);
534 g_pending_installs.Get().EraseInstall(GetProfile(), params_->details.id);
535 SendResponse(false); 483 SendResponse(false);
536 484
537 // The web store install histograms are a subset of the install histograms. 485 // The web store install histograms are a subset of the install histograms.
538 // We need to record both histograms here since CrxInstaller::InstallUIAbort 486 // We need to record both histograms here since CrxInstaller::InstallUIAbort
539 // is never called for web store install cancellations. 487 // is never called for web store install cancellations.
540 std::string histogram_name = 488 std::string histogram_name =
541 user_initiated ? "Extensions.Permissions_WebStoreInstallCancel2" 489 user_initiated ? "Extensions.Permissions_WebStoreInstallCancel2"
542 : "Extensions.Permissions_WebStoreInstallAbort2"; 490 : "Extensions.Permissions_WebStoreInstallAbort2";
543 ExtensionService::RecordPermissionMessagesHistogram(dummy_extension_.get(), 491 ExtensionService::RecordPermissionMessagesHistogram(dummy_extension_.get(),
544 histogram_name.c_str()); 492 histogram_name.c_str());
(...skipping 24 matching lines...) Expand all
569 517
570 approval_ = g_pending_approvals.Get() 518 approval_ = g_pending_approvals.Get()
571 .PopApproval(GetProfile(), params->expected_id) 519 .PopApproval(GetProfile(), params->expected_id)
572 .Pass(); 520 .Pass();
573 if (!approval_) { 521 if (!approval_) {
574 error_ = ErrorUtils::FormatErrorMessage( 522 error_ = ErrorUtils::FormatErrorMessage(
575 kNoPreviousBeginInstallWithManifestError, params->expected_id); 523 kNoPreviousBeginInstallWithManifestError, params->expected_id);
576 return false; 524 return false;
577 } 525 }
578 526
527 scoped_active_install_.reset(
528 new ScopedActiveInstall(GetProfile(), params->expected_id));
529
579 AppListService* app_list_service = 530 AppListService* app_list_service =
580 AppListService::Get(GetCurrentBrowser()->host_desktop_type()); 531 AppListService::Get(GetCurrentBrowser()->host_desktop_type());
581 532
582 if (approval_->enable_launcher) { 533 if (approval_->enable_launcher) {
583 app_list_service->EnableAppList(GetProfile(), 534 app_list_service->EnableAppList(GetProfile(),
584 AppListService::ENABLE_FOR_APP_INSTALL); 535 AppListService::ENABLE_FOR_APP_INSTALL);
585 } 536 }
586 537
587 if (IsAppLauncherEnabled() && approval_->manifest->is_app()) { 538 if (IsAppLauncherEnabled() && approval_->manifest->is_app()) {
588 // Show the app list to show download is progressing. Don't show the app 539 // Show the app list to show download is progressing. Don't show the app
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
639 const std::string& id, 590 const std::string& id,
640 const std::string& error, 591 const std::string& error,
641 WebstoreInstaller::FailureReason reason) { 592 WebstoreInstaller::FailureReason reason) {
642 if (test_webstore_installer_delegate) { 593 if (test_webstore_installer_delegate) {
643 test_webstore_installer_delegate->OnExtensionInstallFailure( 594 test_webstore_installer_delegate->OnExtensionInstallFailure(
644 id, error, reason); 595 id, error, reason);
645 } 596 }
646 597
647 error_ = error; 598 error_ = error;
648 VLOG(1) << "Install failed, sending response"; 599 VLOG(1) << "Install failed, sending response";
649 g_pending_installs.Get().EraseInstall(GetProfile(), id);
650 SendResponse(false); 600 SendResponse(false);
651 601
652 RecordWebstoreExtensionInstallResult(false); 602 RecordWebstoreExtensionInstallResult(false);
653 603
654 // Matches the AddRef in RunAsync(). 604 // Matches the AddRef in RunAsync().
655 Release(); 605 Release();
656 } 606 }
657 607
658 void WebstorePrivateCompleteInstallFunction::OnInstallSuccess( 608 void WebstorePrivateCompleteInstallFunction::OnInstallSuccess(
659 const std::string& id) { 609 const std::string& id) {
660 if (test_webstore_installer_delegate) 610 if (test_webstore_installer_delegate)
661 test_webstore_installer_delegate->OnExtensionInstallSuccess(id); 611 test_webstore_installer_delegate->OnExtensionInstallSuccess(id);
662 612
663 VLOG(1) << "Install success, sending response"; 613 VLOG(1) << "Install success, sending response";
664 g_pending_installs.Get().EraseInstall(GetProfile(), id);
665 SendResponse(true); 614 SendResponse(true);
666 } 615 }
667 616
668 WebstorePrivateEnableAppLauncherFunction:: 617 WebstorePrivateEnableAppLauncherFunction::
669 WebstorePrivateEnableAppLauncherFunction() {} 618 WebstorePrivateEnableAppLauncherFunction() {}
670 619
671 WebstorePrivateEnableAppLauncherFunction:: 620 WebstorePrivateEnableAppLauncherFunction::
672 ~WebstorePrivateEnableAppLauncherFunction() {} 621 ~WebstorePrivateEnableAppLauncherFunction() {}
673 622
674 bool WebstorePrivateEnableAppLauncherFunction::RunSync() { 623 bool WebstorePrivateEnableAppLauncherFunction::RunSync() {
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after
849 if (!user_gesture()) { 798 if (!user_gesture()) {
850 SetResult(LaunchEphemeralAppResult::RESULT_USER_GESTURE_REQUIRED, 799 SetResult(LaunchEphemeralAppResult::RESULT_USER_GESTURE_REQUIRED,
851 "User gesture is required"); 800 "User gesture is required");
852 return false; 801 return false;
853 } 802 }
854 803
855 scoped_ptr<LaunchEphemeralApp::Params> params( 804 scoped_ptr<LaunchEphemeralApp::Params> params(
856 LaunchEphemeralApp::Params::Create(*args_)); 805 LaunchEphemeralApp::Params::Create(*args_));
857 EXTENSION_FUNCTION_VALIDATE(params); 806 EXTENSION_FUNCTION_VALIDATE(params);
858 807
859 // If a full install is in progress, do not install ephemerally.
860 if (g_pending_installs.Get().ContainsInstall(GetProfile(), params->id)) {
861 SetResult(LaunchEphemeralAppResult::RESULT_INSTALL_IN_PROGRESS,
862 "An install is already in progress");
863 return false;
864 }
865
866 AddRef(); // Balanced in OnLaunchComplete() 808 AddRef(); // Balanced in OnLaunchComplete()
867 809
868 scoped_refptr<EphemeralAppLauncher> launcher = 810 scoped_refptr<EphemeralAppLauncher> launcher =
869 EphemeralAppLauncher::CreateForWebContents( 811 EphemeralAppLauncher::CreateForWebContents(
870 params->id, 812 params->id,
871 web_contents, 813 web_contents,
872 base::Bind( 814 base::Bind(
873 &WebstorePrivateLaunchEphemeralAppFunction::OnLaunchComplete, 815 &WebstorePrivateLaunchEphemeralAppFunction::OnLaunchComplete,
874 base::Unretained(this))); 816 base::Unretained(this)));
875 launcher->Start(); 817 launcher->Start();
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
912 break; 854 break;
913 case webstore_install::BLOCKED_BY_POLICY: 855 case webstore_install::BLOCKED_BY_POLICY:
914 api_result = LaunchEphemeralAppResult::RESULT_BLOCKED_BY_POLICY; 856 api_result = LaunchEphemeralAppResult::RESULT_BLOCKED_BY_POLICY;
915 break; 857 break;
916 case webstore_install::LAUNCH_FEATURE_DISABLED: 858 case webstore_install::LAUNCH_FEATURE_DISABLED:
917 api_result = LaunchEphemeralAppResult::RESULT_FEATURE_DISABLED; 859 api_result = LaunchEphemeralAppResult::RESULT_FEATURE_DISABLED;
918 break; 860 break;
919 case webstore_install::LAUNCH_UNSUPPORTED_EXTENSION_TYPE: 861 case webstore_install::LAUNCH_UNSUPPORTED_EXTENSION_TYPE:
920 api_result = LaunchEphemeralAppResult::RESULT_UNSUPPORTED_EXTENSION_TYPE; 862 api_result = LaunchEphemeralAppResult::RESULT_UNSUPPORTED_EXTENSION_TYPE;
921 break; 863 break;
864 case webstore_install::INSTALL_IN_PROGRESS:
865 api_result = LaunchEphemeralAppResult::RESULT_INSTALL_IN_PROGRESS;
866 break;
867 case webstore_install::LAUNCH_IN_PROGRESS:
868 api_result = LaunchEphemeralAppResult::RESULT_LAUNCH_IN_PROGRESS;
869 break;
922 default: 870 default:
923 NOTREACHED(); 871 NOTREACHED();
924 break; 872 break;
925 } 873 }
926 874
927 SetResult(api_result, error); 875 SetResult(api_result, error);
928 Release(); // Matches AddRef() in RunAsync() 876 Release(); // Matches AddRef() in RunAsync()
929 } 877 }
930 878
931 void WebstorePrivateLaunchEphemeralAppFunction::SetResult( 879 void WebstorePrivateLaunchEphemeralAppFunction::SetResult(
(...skipping 20 matching lines...) Expand all
952 WebstorePrivateGetEphemeralAppsEnabledFunction:: 900 WebstorePrivateGetEphemeralAppsEnabledFunction::
953 ~WebstorePrivateGetEphemeralAppsEnabledFunction() {} 901 ~WebstorePrivateGetEphemeralAppsEnabledFunction() {}
954 902
955 bool WebstorePrivateGetEphemeralAppsEnabledFunction::RunSync() { 903 bool WebstorePrivateGetEphemeralAppsEnabledFunction::RunSync() {
956 results_ = GetEphemeralAppsEnabled::Results::Create( 904 results_ = GetEphemeralAppsEnabled::Results::Create(
957 EphemeralAppLauncher::IsFeatureEnabled()); 905 EphemeralAppLauncher::IsFeatureEnabled());
958 return true; 906 return true;
959 } 907 }
960 908
961 } // namespace extensions 909 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698