blob: 10242433b71965c536401a2befd846babb2647af [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/webui/settings/safety_check_handler.h"
#include "base/bind.h"
#include "base/metrics/user_metrics.h"
#include "base/metrics/user_metrics_action.h"
#include "base/strings/string16.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.h"
#include "chrome/browser/password_manager/bulk_leak_check_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/url_constants.h"
#include "chrome/grit/chromium_strings.h"
#include "chrome/grit/generated_resources.h"
#include "components/prefs/pref_service.h"
#include "components/safe_browsing/core/common/safe_browsing_prefs.h"
#include "extensions/browser/extension_prefs_factory.h"
#include "extensions/browser/extension_system.h"
#include "extensions/common/extension_id.h"
#include "ui/base/l10n/l10n_util.h"
#if defined(OS_CHROMEOS)
#include "ui/chromeos/devicetype_utils.h"
#endif
namespace {
// Constants for communication with JS.
constexpr char kUpdatesEvent[] = "safety-check-updates-status-changed";
constexpr char kPasswordsEvent[] = "safety-check-passwords-status-changed";
constexpr char kSafeBrowsingEvent[] =
"safety-check-safe-browsing-status-changed";
constexpr char kExtensionsEvent[] = "safety-check-extensions-status-changed";
constexpr char kPerformSafetyCheck[] = "performSafetyCheck";
constexpr char kGetParentRanDisplayString[] = "getSafetyCheckRanDisplayString";
constexpr char kNewState[] = "newState";
constexpr char kDisplayString[] = "displayString";
constexpr char kButtonString[] = "buttonString";
constexpr char kPasswordsCompromised[] = "passwordsCompromised";
constexpr char kExtensionsReenabledByUser[] = "extensionsReenabledByUser";
constexpr char kExtensionsReenabledByAdmin[] = "extensionsReenabledByAdmin";
// Converts the VersionUpdater::Status to the UpdateStatus enum to be passed
// to the safety check frontend. Note: if the VersionUpdater::Status gets
// changed, this will fail to compile. That is done intentionally to ensure
// that the states of the safety check are always in sync with the
// VersionUpdater ones.
SafetyCheckHandler::UpdateStatus ConvertToUpdateStatus(
VersionUpdater::Status status) {
switch (status) {
case VersionUpdater::CHECKING:
return SafetyCheckHandler::UpdateStatus::kChecking;
case VersionUpdater::UPDATED:
return SafetyCheckHandler::UpdateStatus::kUpdated;
case VersionUpdater::UPDATING:
return SafetyCheckHandler::UpdateStatus::kUpdating;
case VersionUpdater::NEED_PERMISSION_TO_UPDATE:
case VersionUpdater::NEARLY_UPDATED:
return SafetyCheckHandler::UpdateStatus::kRelaunch;
case VersionUpdater::DISABLED:
case VersionUpdater::DISABLED_BY_ADMIN:
return SafetyCheckHandler::UpdateStatus::kDisabledByAdmin;
case VersionUpdater::FAILED:
case VersionUpdater::FAILED_CONNECTION_TYPE_DISALLOWED:
return SafetyCheckHandler::UpdateStatus::kFailed;
case VersionUpdater::FAILED_OFFLINE:
return SafetyCheckHandler::UpdateStatus::kFailedOffline;
}
}
} // namespace
SafetyCheckHandler::SafetyCheckHandler() = default;
SafetyCheckHandler::~SafetyCheckHandler() = default;
void SafetyCheckHandler::PerformSafetyCheck() {
AllowJavascript();
base::RecordAction(base::UserMetricsAction("SafetyCheck.Started"));
if (!version_updater_) {
version_updater_.reset(VersionUpdater::Create(web_ui()->GetWebContents()));
}
DCHECK(version_updater_);
CheckUpdates();
CheckSafeBrowsing();
if (!leak_service_) {
leak_service_ = BulkLeakCheckServiceFactory::GetForProfile(
Profile::FromWebUI(web_ui()));
}
DCHECK(leak_service_);
if (!passwords_delegate_) {
passwords_delegate_ =
extensions::PasswordsPrivateDelegateFactory::GetForBrowserContext(
Profile::FromWebUI(web_ui()), true);
}
DCHECK(passwords_delegate_);
CheckPasswords();
if (!extension_prefs_) {
extension_prefs_ = extensions::ExtensionPrefsFactory::GetForBrowserContext(
Profile::FromWebUI(web_ui()));
}
DCHECK(extension_prefs_);
if (!extension_service_) {
extension_service_ =
extensions::ExtensionSystem::Get(Profile::FromWebUI(web_ui()))
->extension_service();
}
DCHECK(extension_service_);
CheckExtensions();
}
SafetyCheckHandler::SafetyCheckHandler(
std::unique_ptr<VersionUpdater> version_updater,
password_manager::BulkLeakCheckService* leak_service,
extensions::PasswordsPrivateDelegate* passwords_delegate,
extensions::ExtensionPrefs* extension_prefs,
extensions::ExtensionServiceInterface* extension_service)
: version_updater_(std::move(version_updater)),
leak_service_(leak_service),
passwords_delegate_(passwords_delegate),
extension_prefs_(extension_prefs),
extension_service_(extension_service) {}
void SafetyCheckHandler::HandlePerformSafetyCheck(const base::ListValue* args) {
PerformSafetyCheck();
}
void SafetyCheckHandler::HandleGetParentRanDisplayString(
const base::ListValue* args) {
const base::Value* callback_id;
double timestampRanDouble;
CHECK(args->Get(0, &callback_id));
CHECK(args->GetDouble(1, &timestampRanDouble));
ResolveJavascriptCallback(
*callback_id, base::Value(GetStringForParentRan(timestampRanDouble)));
}
void SafetyCheckHandler::CheckUpdates() {
// Usage of base::Unretained(this) is safe, because we own `version_updater_`.
version_updater_->CheckForUpdate(
base::Bind(&SafetyCheckHandler::OnUpdateCheckResult,
base::Unretained(this)),
VersionUpdater::PromoteCallback());
}
void SafetyCheckHandler::CheckSafeBrowsing() {
PrefService* pref_service = Profile::FromWebUI(web_ui())->GetPrefs();
const PrefService::Preference* pref =
pref_service->FindPreference(prefs::kSafeBrowsingEnabled);
SafeBrowsingStatus status;
if (pref_service->GetBoolean(prefs::kSafeBrowsingEnabled)) {
status = SafeBrowsingStatus::kEnabled;
} else if (pref->IsManaged()) {
status = SafeBrowsingStatus::kDisabledByAdmin;
} else if (pref->IsExtensionControlled()) {
status = SafeBrowsingStatus::kDisabledByExtension;
} else {
status = SafeBrowsingStatus::kDisabled;
}
OnSafeBrowsingCheckResult(status);
}
void SafetyCheckHandler::CheckPasswords() {
// Remove |this| as an existing observer for BulkLeakCheck if it is
// registered. This takes care of an edge case when safety check starts twice
// on the same page. Normally this should not happen, but if it does, the
// browser should not crash.
observed_leak_check_.RemoveAll();
observed_leak_check_.Add(leak_service_);
passwords_delegate_->StartPasswordCheck(base::BindOnce(
&SafetyCheckHandler::OnStateChanged, weak_ptr_factory_.GetWeakPtr()));
}
void SafetyCheckHandler::CheckExtensions() {
extensions::ExtensionIdList extensions;
extension_prefs_->GetExtensions(&extensions);
int blocklisted = 0;
int reenabled_by_user = 0;
int reenabled_by_admin = 0;
for (auto extension_id : extensions) {
extensions::BlacklistState state =
extension_prefs_->GetExtensionBlacklistState(extension_id);
if (state == extensions::BLACKLISTED_UNKNOWN) {
// If any of the extensions are in the unknown blacklist state, that means
// there was an error the last time the blacklist was fetched. That means
// the results cannot be relied upon.
OnExtensionsCheckResult(ExtensionsStatus::kError, Blocklisted(0),
ReenabledUser(0), ReenabledAdmin(0));
return;
}
if (state == extensions::NOT_BLACKLISTED) {
continue;
}
++blocklisted;
if (!extension_service_->IsExtensionEnabled(extension_id)) {
continue;
}
if (extension_service_->UserCanDisableInstalledExtension(extension_id)) {
++reenabled_by_user;
} else {
++reenabled_by_admin;
}
}
if (blocklisted == 0) {
OnExtensionsCheckResult(ExtensionsStatus::kNoneBlocklisted, Blocklisted(0),
ReenabledUser(0), ReenabledAdmin(0));
} else if (reenabled_by_user == 0 && reenabled_by_admin == 0) {
OnExtensionsCheckResult(ExtensionsStatus::kBlocklistedAllDisabled,
Blocklisted(blocklisted), ReenabledUser(0),
ReenabledAdmin(0));
} else if (reenabled_by_user > 0 && reenabled_by_admin == 0) {
OnExtensionsCheckResult(ExtensionsStatus::kBlocklistedReenabledAllByUser,
Blocklisted(blocklisted),
ReenabledUser(reenabled_by_user),
ReenabledAdmin(0));
} else if (reenabled_by_admin > 0 && reenabled_by_user == 0) {
OnExtensionsCheckResult(ExtensionsStatus::kBlocklistedReenabledAllByAdmin,
Blocklisted(blocklisted), ReenabledUser(0),
ReenabledAdmin(reenabled_by_admin));
} else {
OnExtensionsCheckResult(ExtensionsStatus::kBlocklistedReenabledSomeByUser,
Blocklisted(blocklisted),
ReenabledUser(reenabled_by_user),
ReenabledAdmin(reenabled_by_admin));
}
}
void SafetyCheckHandler::OnUpdateCheckResult(VersionUpdater::Status status,
int progress,
bool rollback,
const std::string& version,
int64_t update_size,
const base::string16& message) {
UpdateStatus update_status = ConvertToUpdateStatus(status);
base::DictionaryValue event;
event.SetIntKey(kNewState, static_cast<int>(update_status));
event.SetStringKey(kDisplayString, GetStringForUpdates(update_status));
FireWebUIListener(kUpdatesEvent, event);
}
void SafetyCheckHandler::OnSafeBrowsingCheckResult(
SafetyCheckHandler::SafeBrowsingStatus status) {
base::DictionaryValue event;
event.SetIntKey(kNewState, static_cast<int>(status));
event.SetStringKey(kDisplayString, GetStringForSafeBrowsing(status));
FireWebUIListener(kSafeBrowsingEvent, event);
}
void SafetyCheckHandler::OnPasswordsCheckResult(PasswordsStatus status,
int num_compromised) {
base::DictionaryValue event;
event.SetIntKey(kNewState, static_cast<int>(status));
if (status == PasswordsStatus::kCompromisedExist) {
event.SetIntKey(kPasswordsCompromised, num_compromised);
event.SetStringKey(
kButtonString,
l10n_util::GetPluralStringFUTF16(
IDS_SETTINGS_SAFETY_CHECK_PASSWORDS_BUTTON, num_compromised));
}
event.SetStringKey(kDisplayString,
GetStringForPasswords(status, num_compromised));
FireWebUIListener(kPasswordsEvent, event);
}
void SafetyCheckHandler::OnExtensionsCheckResult(
ExtensionsStatus status,
Blocklisted blocklisted,
ReenabledUser reenabled_user,
ReenabledAdmin reenabled_admin) {
base::DictionaryValue event;
event.SetIntKey(kNewState, static_cast<int>(status));
if (status == ExtensionsStatus::kBlocklistedReenabledAllByUser ||
status == ExtensionsStatus::kBlocklistedReenabledSomeByUser) {
event.SetIntKey(kExtensionsReenabledByUser, reenabled_user.value());
}
if (status == ExtensionsStatus::kBlocklistedReenabledAllByAdmin ||
status == ExtensionsStatus::kBlocklistedReenabledSomeByUser) {
event.SetIntKey(kExtensionsReenabledByAdmin, reenabled_admin.value());
}
event.SetStringKey(kDisplayString,
GetStringForExtensions(status, Blocklisted(blocklisted),
reenabled_user, reenabled_admin));
FireWebUIListener(kExtensionsEvent, event);
}
base::string16 SafetyCheckHandler::GetStringForUpdates(UpdateStatus status) {
switch (status) {
case UpdateStatus::kChecking:
return l10n_util::GetStringUTF16(IDS_SETTINGS_SAFETY_CHECK_RUNNING);
case UpdateStatus::kUpdated:
#if defined(OS_CHROMEOS)
return ui::SubstituteChromeOSDeviceType(IDS_SETTINGS_UPGRADE_UP_TO_DATE);
#else
return l10n_util::GetStringUTF16(IDS_SETTINGS_UPGRADE_UP_TO_DATE);
#endif
case UpdateStatus::kUpdating:
return l10n_util::GetStringUTF16(IDS_SETTINGS_UPGRADE_UPDATING);
case UpdateStatus::kRelaunch:
return l10n_util::GetStringUTF16(
IDS_SETTINGS_UPGRADE_SUCCESSFUL_RELAUNCH);
case UpdateStatus::kDisabledByAdmin:
return l10n_util::GetStringFUTF16(
IDS_SETTINGS_SAFETY_CHECK_UPDATES_DISABLED_BY_ADMIN,
base::ASCIIToUTF16(chrome::kWhoIsMyAdministratorHelpURL));
case UpdateStatus::kFailedOffline:
return l10n_util::GetStringUTF16(
IDS_SETTINGS_SAFETY_CHECK_UPDATES_FAILED_OFFLINE);
case UpdateStatus::kFailed:
return l10n_util::GetStringFUTF16(
IDS_SETTINGS_SAFETY_CHECK_UPDATES_FAILED,
base::ASCIIToUTF16(chrome::kChromeFixUpdateProblems));
}
}
base::string16 SafetyCheckHandler::GetStringForSafeBrowsing(
SafeBrowsingStatus status) {
switch (status) {
case SafeBrowsingStatus::kChecking:
return l10n_util::GetStringUTF16(IDS_SETTINGS_SAFETY_CHECK_RUNNING);
case SafeBrowsingStatus::kEnabled:
return l10n_util::GetStringUTF16(
IDS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_ENABLED);
case SafeBrowsingStatus::kDisabled:
return l10n_util::GetStringUTF16(
IDS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_DISABLED);
case SafeBrowsingStatus::kDisabledByAdmin:
return l10n_util::GetStringFUTF16(
IDS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_DISABLED_BY_ADMIN,
base::ASCIIToUTF16(chrome::kWhoIsMyAdministratorHelpURL));
case SafeBrowsingStatus::kDisabledByExtension:
return l10n_util::GetStringUTF16(
IDS_SETTINGS_SAFETY_CHECK_SAFE_BROWSING_DISABLED_BY_EXTENSION);
}
}
base::string16 SafetyCheckHandler::GetStringForPasswords(PasswordsStatus status,
int num_compromised) {
switch (status) {
case PasswordsStatus::kChecking:
return l10n_util::GetStringUTF16(IDS_SETTINGS_SAFETY_CHECK_RUNNING);
case PasswordsStatus::kSafe:
return l10n_util::GetStringUTF16(
IDS_SETTINGS_SAFETY_CHECK_PASSWORDS_SAFE);
case PasswordsStatus::kCompromisedExist:
return l10n_util::GetPluralStringFUTF16(
IDS_SETTINGS_SAFETY_CHECK_PASSWORDS_COMPROMISED, num_compromised);
case PasswordsStatus::kOffline:
return l10n_util::GetStringUTF16(
IDS_SETTINGS_SAFETY_CHECK_PASSWORDS_OFFLINE);
case PasswordsStatus::kNoPasswords:
return l10n_util::GetStringUTF16(
IDS_SETTINGS_SAFETY_CHECK_PASSWORDS_NO_PASSWORDS);
case PasswordsStatus::kSignedOut:
return l10n_util::GetStringUTF16(
IDS_SETTINGS_SAFETY_CHECK_PASSWORDS_SIGNED_OUT);
case PasswordsStatus::kQuotaLimit:
return l10n_util::GetStringUTF16(
IDS_SETTINGS_SAFETY_CHECK_PASSWORDS_QUOTA_LIMIT);
case PasswordsStatus::kError:
return l10n_util::GetStringUTF16(
IDS_SETTINGS_SAFETY_CHECK_PASSWORDS_ERROR);
}
}
base::string16 SafetyCheckHandler::GetStringForExtensions(
ExtensionsStatus status,
Blocklisted blocklisted,
ReenabledUser reenabled_user,
ReenabledAdmin reenabled_admin) {
switch (status) {
case ExtensionsStatus::kChecking:
return l10n_util::GetStringUTF16(IDS_SETTINGS_SAFETY_CHECK_RUNNING);
case ExtensionsStatus::kError:
return l10n_util::GetStringUTF16(
IDS_SETTINGS_SAFETY_CHECK_EXTENSIONS_ERROR);
case ExtensionsStatus::kNoneBlocklisted:
return l10n_util::GetStringUTF16(
IDS_SETTINGS_SAFETY_CHECK_EXTENSIONS_SAFE);
case ExtensionsStatus::kBlocklistedAllDisabled:
return l10n_util::GetPluralStringFUTF16(
IDS_SETTINGS_SAFETY_CHECK_EXTENSIONS_BLOCKLISTED_OFF,
blocklisted.value());
case ExtensionsStatus::kBlocklistedReenabledAllByUser:
return l10n_util::GetPluralStringFUTF16(
IDS_SETTINGS_SAFETY_CHECK_EXTENSIONS_BLOCKLISTED_ON_USER,
reenabled_user.value());
case ExtensionsStatus::kBlocklistedReenabledSomeByUser:
// TODO(crbug/1060625): Make string concatenation with a period
// internationalized (see go/i18n-concatenation).
return l10n_util::GetPluralStringFUTF16(
IDS_SETTINGS_SAFETY_CHECK_EXTENSIONS_BLOCKLISTED_ON_USER,
reenabled_user.value()) +
base::ASCIIToUTF16(". ") +
l10n_util::GetPluralStringFUTF16(
IDS_SETTINGS_SAFETY_CHECK_EXTENSIONS_BLOCKLISTED_ON_ADMIN,
reenabled_admin.value()) +
base::ASCIIToUTF16(".");
case ExtensionsStatus::kBlocklistedReenabledAllByAdmin:
return l10n_util::GetPluralStringFUTF16(
IDS_SETTINGS_SAFETY_CHECK_EXTENSIONS_BLOCKLISTED_ON_ADMIN,
reenabled_admin.value());
}
}
base::string16 SafetyCheckHandler::GetStringForParentRan(double timestamp_ran) {
return SafetyCheckHandler::GetStringForParentRan(timestamp_ran,
base::Time::Now());
}
base::string16 SafetyCheckHandler::GetStringForParentRan(
double timestamp_ran,
base::Time system_time) {
const base::Time timeRan = base::Time::FromJsTime(timestamp_ran);
base::Time::Exploded timeRanExploded;
timeRan.LocalExplode(&timeRanExploded);
base::Time::Exploded systemTimeExploded;
system_time.LocalExplode(&systemTimeExploded);
const base::Time timeYesterday = system_time - base::TimeDelta::FromDays(1);
base::Time::Exploded timeYesterdayExploded;
timeYesterday.LocalExplode(&timeYesterdayExploded);
const auto timeDiff = system_time - timeRan;
if (timeRanExploded.year == systemTimeExploded.year &&
timeRanExploded.month == systemTimeExploded.month &&
timeRanExploded.day_of_month == systemTimeExploded.day_of_month) {
// Safety check ran today.
const int timeDiffInMinutes = timeDiff.InMinutes();
if (timeDiffInMinutes == 0) {
return l10n_util::GetStringUTF16(
IDS_SETTINGS_SAFETY_CHECK_PARENT_PRIMARY_LABEL_AFTER);
} else if (timeDiffInMinutes < 60) {
return l10n_util::GetPluralStringFUTF16(
IDS_SETTINGS_SAFETY_CHECK_PARENT_PRIMARY_LABEL_AFTER_MINS,
timeDiffInMinutes);
} else {
return l10n_util::GetPluralStringFUTF16(
IDS_SETTINGS_SAFETY_CHECK_PARENT_PRIMARY_LABEL_AFTER_HOURS,
timeDiffInMinutes / 60);
}
} else if (timeRanExploded.year == timeYesterdayExploded.year &&
timeRanExploded.month == timeYesterdayExploded.month &&
timeRanExploded.day_of_month ==
timeYesterdayExploded.day_of_month) {
// Safety check ran yesterday.
return l10n_util::GetStringUTF16(
IDS_SETTINGS_SAFETY_CHECK_PARENT_PRIMARY_LABEL_AFTER_YESTERDAY);
} else {
// Safety check ran longer ago than yesterday.
// TODO(crbug.com/1015841): While a minor issue, this is not be the ideal
// way to calculate the days passed since safety check ran. For example,
// <48 h might still be 2 days ago.
const int timeDiffInDays = timeDiff.InDays();
return l10n_util::GetPluralStringFUTF16(
IDS_SETTINGS_SAFETY_CHECK_PARENT_PRIMARY_LABEL_AFTER_DAYS,
timeDiffInDays);
}
}
void SafetyCheckHandler::DetermineIfNoPasswordsOrSafe(
const std::vector<extensions::api::passwords_private::PasswordUiEntry>&
passwords) {
OnPasswordsCheckResult(passwords.empty() ? PasswordsStatus::kNoPasswords
: PasswordsStatus::kSafe,
0);
}
void SafetyCheckHandler::OnStateChanged(
password_manager::BulkLeakCheckService::State state) {
using password_manager::BulkLeakCheckService;
switch (state) {
case BulkLeakCheckService::State::kIdle:
case BulkLeakCheckService::State::kCanceled: {
size_t num_compromised =
passwords_delegate_->GetCompromisedCredentials().size();
if (num_compromised == 0) {
passwords_delegate_->GetSavedPasswordsList(
base::BindOnce(&SafetyCheckHandler::DetermineIfNoPasswordsOrSafe,
base::Unretained(this)));
} else {
OnPasswordsCheckResult(PasswordsStatus::kCompromisedExist,
num_compromised);
}
break;
}
case BulkLeakCheckService::State::kRunning:
OnPasswordsCheckResult(PasswordsStatus::kChecking, 0);
// Non-terminal state, so nothing else needs to be done.
return;
case BulkLeakCheckService::State::kSignedOut:
OnPasswordsCheckResult(PasswordsStatus::kSignedOut, 0);
break;
case BulkLeakCheckService::State::kNetworkError:
OnPasswordsCheckResult(PasswordsStatus::kOffline, 0);
break;
case BulkLeakCheckService::State::kQuotaLimit:
OnPasswordsCheckResult(PasswordsStatus::kQuotaLimit, 0);
break;
case BulkLeakCheckService::State::kTokenRequestFailure:
case BulkLeakCheckService::State::kHashingFailure:
case BulkLeakCheckService::State::kServiceError:
OnPasswordsCheckResult(PasswordsStatus::kError, 0);
break;
}
// Stop observing the leak service in all terminal states, if it's still being
// observed.
observed_leak_check_.RemoveAll();
}
void SafetyCheckHandler::OnCredentialDone(
const password_manager::LeakCheckCredential& credential,
password_manager::IsLeaked is_leaked) {
// Do nothing because we only want to know the total number of compromised
// credentials at the end of the bulk leak check.
}
void SafetyCheckHandler::OnJavascriptAllowed() {}
void SafetyCheckHandler::OnJavascriptDisallowed() {
// Remove |this| as an observer for BulkLeakCheck. This takes care of an edge
// case when the page is reloaded while the password check is in progress and
// another safety check is started. Otherwise |observed_leak_check_|
// automatically calls RemoveAll() on destruction.
observed_leak_check_.RemoveAll();
// Destroy the version updater to prevent getting a callback and firing a
// WebUI event, which would cause a crash.
version_updater_.reset();
}
void SafetyCheckHandler::RegisterMessages() {
// Usage of base::Unretained(this) is safe, because web_ui() owns `this` and
// won't release ownership until destruction.
web_ui()->RegisterMessageCallback(
kPerformSafetyCheck,
base::BindRepeating(&SafetyCheckHandler::HandlePerformSafetyCheck,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
kGetParentRanDisplayString,
base::BindRepeating(&SafetyCheckHandler::HandleGetParentRanDisplayString,
base::Unretained(this)));
}