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