| // Copyright 2016 The Chromium Authors |
| // 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/about_handler.h" |
| |
| #include <stddef.h> |
| |
| #include <limits> |
| #include <string> |
| |
| #include "base/command_line.h" |
| #include "base/files/file_path.h" |
| #include "base/files/file_util.h" |
| #include "base/functional/bind.h" |
| #include "base/functional/callback_helpers.h" |
| #include "base/location.h" |
| #include "base/metrics/user_metrics.h" |
| #include "base/metrics/user_metrics_action.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/task/thread_pool.h" |
| #include "base/time/default_clock.h" |
| #include "build/branding_buildflags.h" |
| #include "build/build_config.h" |
| #include "build/chromeos_buildflags.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/chrome_content_browser_client.h" |
| #include "chrome/browser/policy/management_utils.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_commands.h" |
| #include "chrome/browser/ui/browser_finder.h" |
| #include "chrome/browser/ui/chrome_pages.h" |
| #include "chrome/browser/ui/webui/theme_source.h" |
| #include "chrome/browser/upgrade_detector/upgrade_detector.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/common/url_constants.h" |
| #include "chrome/grit/chromium_strings.h" |
| #include "chrome/grit/generated_resources.h" |
| #include "components/google/core/common/google_util.h" |
| #include "components/policy/core/common/policy_namespace.h" |
| #include "components/policy/policy_constants.h" |
| #include "components/services/app_service/public/cpp/app_launch_util.h" |
| #include "components/strings/grit/components_strings.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/browser/web_ui.h" |
| #include "content/public/browser/web_ui_data_source.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "v8/include/v8-version-string.h" |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| #include "ash/constants/ash_features.h" |
| #include "ash/constants/ash_switches.h" |
| #include "ash/public/cpp/new_window_delegate.h" |
| #include "base/i18n/time_formatting.h" |
| #include "base/strings/strcat.h" |
| #include "chrome/browser/ash/arc/arc_util.h" |
| #include "chrome/browser/ash/eol_incentive_util.h" |
| #include "chrome/browser/ash/ownership/owner_settings_service_ash.h" |
| #include "chrome/browser/ash/ownership/owner_settings_service_ash_factory.h" |
| #include "chrome/browser/ash/profiles/profile_helper.h" |
| #include "chrome/browser/ash/settings/cros_settings.h" |
| #include "chrome/browser/ash/tpm_firmware_update.h" |
| #include "chrome/browser/ui/webui/ash/image_source.h" |
| #include "chrome/browser/ui/webui/help/help_utils_chromeos.h" |
| #include "chrome/browser/ui/webui/help/version_updater_chromeos.h" |
| #include "chrome/browser/ui/webui/webui_util.h" |
| #include "chromeos/ash/components/dbus/update_engine/update_engine_client.h" |
| #include "chromeos/ash/components/fwupd/firmware_update_manager.h" |
| #include "chromeos/ash/components/network/network_state.h" |
| #include "chromeos/ash/components/network/network_state_handler.h" |
| #include "chromeos/ash/components/system/statistics_provider.h" |
| #include "chromeos/dbus/power/power_manager_client.h" |
| #include "chromeos/version/version_loader.h" |
| #include "components/user_manager/user_manager.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| #include "ui/chromeos/devicetype_utils.h" |
| #endif |
| |
| namespace { |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| // The directory containing the regulatory labels for supported |
| // models/regions, relative to chromeos-assets directory |
| const char kRegulatoryLabelsDirectory[] = "regulatory_labels"; |
| |
| // File names of the image file and the file containing alt text for the label. |
| const char kRegulatoryLabelImageFilename[] = "label.png"; |
| const char kRegulatoryLabelTextFilename[] = "label.txt"; |
| |
| // Default region code to use if there's no label for the VPD region code. |
| const char kDefaultRegionCode[] = "us"; |
| |
| struct RegulatoryLabel { |
| const std::string label_text; |
| const std::string image_url; |
| }; |
| |
| // Returns message that informs user that for update it's better to |
| // connect to a network of one of the allowed types. |
| std::u16string GetAllowedConnectionTypesMessage() { |
| if (!help_utils_chromeos::IsUpdateOverCellularAllowed( |
| /*interactive=*/true)) { |
| return l10n_util::GetStringUTF16( |
| IDS_UPGRADE_NETWORK_LIST_CELLULAR_DISALLOWED); |
| } |
| |
| const bool metered = ash::NetworkHandler::Get() |
| ->network_state_handler() |
| ->default_network_is_metered(); |
| return l10n_util::GetStringUTF16( |
| metered ? IDS_UPGRADE_NETWORK_LIST_CELLULAR_ALLOWED_NOT_AUTOMATIC |
| : IDS_UPGRADE_NETWORK_LIST_CELLULAR_ALLOWED); |
| } |
| |
| // Returns true if current user can change channel, false otherwise. |
| bool CanChangeChannel(Profile* profile) { |
| if (policy::IsDeviceEnterpriseManaged()) { |
| bool value = false; |
| // On a managed machine we delegate this setting to the affiliated users |
| // only if the policy value is true. |
| ash::CrosSettings::Get()->GetBoolean(ash::kReleaseChannelDelegated, &value); |
| if (!value) |
| return false; |
| |
| // Get the currently logged-in user and check if it is affiliated. |
| const user_manager::User* user = |
| profile ? ash::ProfileHelper::Get()->GetUserByProfile(profile) |
| : nullptr; |
| return user && user->IsAffiliated(); |
| } |
| |
| // On non-managed machines, only the local owner can change the channel. |
| ash::OwnerSettingsServiceAsh* service = |
| ash::OwnerSettingsServiceAshFactory::GetInstance()->GetForBrowserContext( |
| profile); |
| return service && service->IsOwner(); |
| } |
| |
| // Returns the relative path under the chromeos-assets dir |
| // to the directory of regulatory labels for a given region, if found |
| // (e.g. "regulatory_labels/us"). Must be called from the blocking pool. |
| base::FilePath GetRegulatoryLabelDirForRegion(base::StringPiece region) { |
| base::FilePath region_path(kRegulatoryLabelsDirectory); |
| const std::string model_subdir = |
| base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
| ash::switches::kRegulatoryLabelDir); |
| if (!model_subdir.empty()) { |
| region_path = region_path.AppendASCII(model_subdir); |
| } |
| region_path = region_path.AppendASCII(region); |
| |
| // Check if the label image file exists in the full path, e.g., |
| // "/usr/share/chromeos-assets/regulatory_labels/us/label.png". |
| const base::FilePath image_path = |
| base::FilePath(chrome::kChromeOSAssetPath) |
| .Append(region_path) |
| .AppendASCII(kRegulatoryLabelImageFilename); |
| return base::PathExists(image_path) ? region_path : base::FilePath(); |
| } |
| |
| // Finds the relative path under the chromeos-assets dir to the region |
| // subdirectory of regulatory labels, using the VPD region code. Also |
| // tries "us" as a fallback region. Must be called from the blocking pool. |
| base::FilePath FindRegulatoryLabelDir() { |
| base::FilePath region_path; |
| // Use the VPD region code to find the label dir. |
| const absl::optional<base::StringPiece> region = |
| ash::system::StatisticsProvider::GetInstance()->GetMachineStatistic( |
| ash::system::kRegionKey); |
| if (region && !region->empty()) { |
| region_path = GetRegulatoryLabelDirForRegion(region.value()); |
| } |
| |
| // Try the fallback region code if no directory was found. |
| if (region_path.empty() && region != kDefaultRegionCode) |
| region_path = GetRegulatoryLabelDirForRegion(kDefaultRegionCode); |
| |
| return region_path; |
| } |
| |
| // Reads the file containing the regulatory label text, if found |
| // in the given relative path under the chromeos-assets dir. |
| // Must be called from the blocking pool. |
| std::string ReadRegulatoryLabelText(const base::FilePath& label_dir_path) { |
| const base::FilePath text_path = |
| base::FilePath(chrome::kChromeOSAssetPath) |
| .Append(label_dir_path) |
| .AppendASCII(kRegulatoryLabelTextFilename); |
| |
| std::string contents; |
| if (base::ReadFileToString(text_path, &contents)) |
| return contents; |
| return std::string(); |
| } |
| |
| base::Value::Dict GetVersionInfo() { |
| base::Value::Dict version_info; |
| absl::optional<std::string> version = chromeos::version_loader::GetVersion( |
| chromeos::version_loader::VERSION_FULL); |
| version_info.Set("osVersion", version.value_or("0.0.0.0")); |
| version_info.Set("arcVersion", chromeos::version_loader::GetArcVersion()); |
| version_info.Set("osFirmware", chromeos::version_loader::GetFirmware()); |
| return version_info; |
| } |
| |
| #endif // BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| std::string UpdateStatusToString(VersionUpdater::Status status) { |
| std::string status_str; |
| switch (status) { |
| case VersionUpdater::CHECKING: |
| status_str = "checking"; |
| break; |
| case VersionUpdater::UPDATING: |
| status_str = "updating"; |
| break; |
| case VersionUpdater::NEARLY_UPDATED: |
| status_str = "nearly_updated"; |
| break; |
| case VersionUpdater::UPDATED: |
| status_str = "updated"; |
| break; |
| case VersionUpdater::FAILED: |
| case VersionUpdater::FAILED_OFFLINE: |
| case VersionUpdater::FAILED_CONNECTION_TYPE_DISALLOWED: |
| status_str = "failed"; |
| break; |
| case VersionUpdater::FAILED_HTTP: |
| status_str = "failed_http"; |
| break; |
| case VersionUpdater::FAILED_DOWNLOAD: |
| status_str = "failed_download"; |
| break; |
| case VersionUpdater::DISABLED: |
| status_str = "disabled"; |
| break; |
| case VersionUpdater::DISABLED_BY_ADMIN: |
| status_str = "disabled_by_admin"; |
| break; |
| case VersionUpdater::NEED_PERMISSION_TO_UPDATE: |
| status_str = "need_permission_to_update"; |
| break; |
| case VersionUpdater::DEFERRED: |
| status_str = "deferred"; |
| break; |
| } |
| |
| return status_str; |
| } |
| |
| } // namespace |
| |
| namespace settings { |
| |
| AboutHandler::AboutHandler(Profile* profile) |
| : profile_(profile), clock_(base::DefaultClock::GetInstance()) { |
| UpgradeDetector::GetInstance()->AddObserver(this); |
| } |
| |
| AboutHandler::~AboutHandler() { |
| UpgradeDetector::GetInstance()->RemoveObserver(this); |
| } |
| |
| void AboutHandler::RegisterMessages() { |
| web_ui()->RegisterMessageCallback( |
| "aboutPageReady", base::BindRepeating(&AboutHandler::HandlePageReady, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback( |
| "refreshUpdateStatus", |
| base::BindRepeating(&AboutHandler::HandleRefreshUpdateStatus, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback( |
| "openFeedbackDialog", |
| base::BindRepeating(&AboutHandler::HandleOpenFeedbackDialog, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback( |
| "openHelpPage", base::BindRepeating(&AboutHandler::HandleOpenHelpPage, |
| base::Unretained(this))); |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| web_ui()->RegisterMessageCallback( |
| "openDiagnostics", |
| base::BindRepeating(&AboutHandler::HandleOpenDiagnostics, |
| base::Unretained(this))); |
| |
| web_ui()->RegisterMessageCallback( |
| "openFirmwareUpdatesPage", |
| base::BindRepeating(&AboutHandler::HandleOpenFirmwareUpdates, |
| base::Unretained(this))); |
| |
| web_ui()->RegisterMessageCallback( |
| "getFirmwareUpdateCount", |
| base::BindRepeating(&AboutHandler::HandleGetFirmwareUpdateCount, |
| base::Unretained(this))); |
| |
| web_ui()->RegisterMessageCallback( |
| "openOsHelpPage", base::BindRepeating(&AboutHandler::HandleOpenOsHelpPage, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback( |
| "setChannel", base::BindRepeating(&AboutHandler::HandleSetChannel, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback( |
| "applyDeferredUpdate", |
| base::BindRepeating(&AboutHandler::HandleApplyDeferredUpdate, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback( |
| "requestUpdate", base::BindRepeating(&AboutHandler::HandleRequestUpdate, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback( |
| "requestUpdateOverCellular", |
| base::BindRepeating(&AboutHandler::HandleRequestUpdateOverCellular, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback( |
| "getVersionInfo", base::BindRepeating(&AboutHandler::HandleGetVersionInfo, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback( |
| "getRegulatoryInfo", |
| base::BindRepeating(&AboutHandler::HandleGetRegulatoryInfo, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback( |
| "getChannelInfo", base::BindRepeating(&AboutHandler::HandleGetChannelInfo, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback( |
| "canChangeChannel", |
| base::BindRepeating(&AboutHandler::HandleCanChangeChannel, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback( |
| "refreshTPMFirmwareUpdateStatus", |
| base::BindRepeating(&AboutHandler::HandleRefreshTPMFirmwareUpdateStatus, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback( |
| "getEndOfLifeInfo", |
| base::BindRepeating(&AboutHandler::HandleGetEndOfLifeInfo, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback( |
| "openEndOfLifeIncentive", |
| base::BindRepeating(&AboutHandler::HandleOpenEndOfLifeIncentive, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback( |
| "launchReleaseNotes", |
| base::BindRepeating(&AboutHandler::HandleLaunchReleaseNotes, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback( |
| "checkInternetConnection", |
| base::BindRepeating(&AboutHandler::HandleCheckInternetConnection, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback( |
| "isManagedAutoUpdateEnabled", |
| base::BindRepeating(&AboutHandler::HandleIsManagedAutoUpdateEnabled, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback( |
| "isConsumerAutoUpdateEnabled", |
| base::BindRepeating(&AboutHandler::HandleIsConsumerAutoUpdateEnabled, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback( |
| "setConsumerAutoUpdate", |
| base::BindRepeating(&AboutHandler::HandleSetConsumerAutoUpdate, |
| base::Unretained(this))); |
| web_ui()->RegisterMessageCallback( |
| "openProductLicenseOther", |
| base::BindRepeating(&AboutHandler::HandleOpenProductLicenseOther, |
| base::Unretained(this))); |
| #endif |
| #if BUILDFLAG(IS_MAC) |
| web_ui()->RegisterMessageCallback( |
| "promoteUpdater", base::BindRepeating(&AboutHandler::PromoteUpdater, |
| base::Unretained(this))); |
| #endif |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| // Handler for the product label image, which will be shown if available. |
| content::URLDataSource::Add(profile_, std::make_unique<ash::ImageSource>()); |
| #endif |
| content::URLDataSource::Add(profile_, |
| std::make_unique<ThemeSource>(profile_)); |
| } |
| |
| void AboutHandler::OnJavascriptAllowed() { |
| apply_changes_from_upgrade_observer_ = true; |
| version_updater_.reset(VersionUpdater::Create(web_ui()->GetWebContents())); |
| policy_registrar_ = std::make_unique<policy::PolicyChangeRegistrar>( |
| g_browser_process->policy_service(), |
| policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, std::string())); |
| #if BUILDFLAG(IS_CHROMEOS) |
| policy_registrar_->Observe( |
| policy::key::kDeviceAutoUpdateDisabled, |
| base::BindRepeating(&AboutHandler::OnDeviceAutoUpdatePolicyChanged, |
| base::Unretained(this))); |
| #endif // BUILDFLAG(IS_CHROMEOS_ASH) |
| } |
| |
| void AboutHandler::OnJavascriptDisallowed() { |
| apply_changes_from_upgrade_observer_ = false; |
| version_updater_.reset(); |
| policy_registrar_.reset(); |
| } |
| |
| void AboutHandler::OnUpgradeRecommended() { |
| if (apply_changes_from_upgrade_observer_) { |
| // A version update is installed and ready to go. Refresh the UI so the |
| // correct state will be shown. |
| RequestUpdate(); |
| } |
| } |
| |
| void AboutHandler::OnDeviceAutoUpdatePolicyChanged( |
| const base::Value* previous_policy, |
| const base::Value* current_policy) { |
| bool previous_auto_update_disabled = false; |
| if (previous_policy) { |
| CHECK(previous_policy->is_bool()); |
| previous_auto_update_disabled = previous_policy->GetBool(); |
| } |
| |
| bool current_auto_update_disabled = false; |
| if (current_policy) { |
| CHECK(current_policy->is_bool()); |
| current_auto_update_disabled = current_policy->GetBool(); |
| } |
| |
| if (current_auto_update_disabled != previous_auto_update_disabled) { |
| // Refresh the update status to refresh the status of the UI. |
| RefreshUpdateStatus(); |
| } |
| } |
| |
| void AboutHandler::HandlePageReady(const base::Value::List& args) { |
| AllowJavascript(); |
| } |
| |
| void AboutHandler::HandleRefreshUpdateStatus(const base::Value::List& args) { |
| RefreshUpdateStatus(); |
| } |
| |
| void AboutHandler::RefreshUpdateStatus() { |
| // On Chrome OS, do not check for an update automatically. |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| static_cast<VersionUpdaterCros*>(version_updater_.get()) |
| ->GetUpdateStatus(base::BindRepeating(&AboutHandler::SetUpdateStatus, |
| base::Unretained(this))); |
| #else |
| RequestUpdate(); |
| #endif |
| } |
| |
| #if BUILDFLAG(IS_MAC) |
| void AboutHandler::PromoteUpdater(const base::Value::List& args) { |
| version_updater_->PromoteUpdater(); |
| } |
| #endif |
| |
| void AboutHandler::HandleOpenFeedbackDialog(const base::Value::List& args) { |
| DCHECK(args.empty()); |
| Browser* browser = |
| chrome::FindBrowserWithWebContents(web_ui()->GetWebContents()); |
| chrome::OpenFeedbackDialog(browser, |
| chrome::kFeedbackSourceMdSettingsAboutPage); |
| } |
| |
| void AboutHandler::HandleOpenHelpPage(const base::Value::List& args) { |
| DCHECK(args.empty()); |
| Browser* browser = |
| chrome::FindBrowserWithWebContents(web_ui()->GetWebContents()); |
| chrome::ShowHelp(browser, chrome::HELP_SOURCE_WEBUI); |
| } |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| void AboutHandler::HandleOpenDiagnostics(const base::Value::List& args) { |
| DCHECK(args.empty()); |
| chrome::ShowDiagnosticsApp(profile_); |
| } |
| |
| void AboutHandler::HandleOpenFirmwareUpdates(const base::Value::List& args) { |
| DCHECK(args.empty()); |
| chrome::ShowFirmwareUpdatesApp(profile_); |
| } |
| |
| void AboutHandler::HandleCheckInternetConnection( |
| const base::Value::List& args) { |
| CHECK_EQ(1U, args.size()); |
| const std::string& callback_id = args[0].GetString(); |
| |
| ash::NetworkStateHandler* network_state_handler = |
| ash::NetworkHandler::Get()->network_state_handler(); |
| const ash::NetworkState* network = network_state_handler->DefaultNetwork(); |
| ResolveJavascriptCallback(base::Value(callback_id), |
| base::Value(network && network->IsOnline())); |
| } |
| |
| void AboutHandler::HandleLaunchReleaseNotes(const base::Value::List& args) { |
| DCHECK(args.empty()); |
| // We can always show the release notes since the Help app caches it, or can |
| // show an appropriate error state (e.g. No internet connection). |
| base::RecordAction(base::UserMetricsAction("ReleaseNotes.LaunchedAboutPage")); |
| chrome::LaunchReleaseNotes(profile_, apps::LaunchSource::kFromOtherApp); |
| } |
| |
| void AboutHandler::HandleOpenOsHelpPage(const base::Value::List& args) { |
| DCHECK(args.empty()); |
| Browser* browser = |
| chrome::FindBrowserWithWebContents(web_ui()->GetWebContents()); |
| chrome::ShowHelp(browser, chrome::HELP_SOURCE_WEBUI_CHROME_OS); |
| } |
| |
| void AboutHandler::HandleSetChannel(const base::Value::List& args) { |
| DCHECK_EQ(2U, args.size()); |
| |
| if (!CanChangeChannel(profile_)) { |
| LOG(WARNING) << "Non-owner tried to change release track."; |
| return; |
| } |
| |
| if (!args[0].is_string() || !args[1].is_bool()) { |
| LOG(ERROR) << "Can't parse SetChannel() args"; |
| return; |
| } |
| const std::string& channel = args[0].GetString(); |
| const bool& is_powerwash_allowed = args[1].GetBool(); |
| |
| version_updater_->SetChannel(channel, is_powerwash_allowed); |
| if (user_manager::UserManager::Get()->IsCurrentUserOwner()) { |
| // Check for update after switching release channel. |
| version_updater_->CheckForUpdate( |
| base::BindRepeating(&AboutHandler::SetUpdateStatus, |
| base::Unretained(this)), |
| VersionUpdater::PromoteCallback()); |
| } |
| } |
| |
| void AboutHandler::HandleGetVersionInfo(const base::Value::List& args) { |
| CHECK_EQ(1U, args.size()); |
| const std::string& callback_id = args[0].GetString(); |
| base::ThreadPool::PostTaskAndReplyWithResult( |
| FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE}, |
| base::BindOnce(&GetVersionInfo), |
| base::BindOnce(&AboutHandler::OnGetVersionInfoReady, |
| weak_factory_.GetWeakPtr(), callback_id)); |
| } |
| |
| void AboutHandler::OnGetVersionInfoReady(std::string callback_id, |
| base::Value::Dict version_info) { |
| ResolveJavascriptCallback(base::Value(callback_id), version_info); |
| } |
| |
| void AboutHandler::HandleGetFirmwareUpdateCount(const base::Value::List& args) { |
| CHECK_EQ(1U, args.size()); |
| const std::string& callback_id = args[0].GetString(); |
| auto* firmware_update_manager = ash::FirmwareUpdateManager::Get(); |
| size_t update_count = firmware_update_manager->GetUpdateCount(); |
| DCHECK_LT(update_count, std::numeric_limits<size_t>::max()); |
| ResolveJavascriptCallback(base::Value(callback_id), |
| base::Value(static_cast<int>(update_count))); |
| } |
| |
| void AboutHandler::HandleGetRegulatoryInfo(const base::Value::List& args) { |
| CHECK_EQ(1U, args.size()); |
| const std::string& callback_id = args[0].GetString(); |
| |
| base::ThreadPool::PostTaskAndReplyWithResult( |
| FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE}, |
| base::BindOnce(&FindRegulatoryLabelDir), |
| base::BindOnce(&AboutHandler::OnRegulatoryLabelDirFound, |
| weak_factory_.GetWeakPtr(), callback_id)); |
| } |
| |
| void AboutHandler::HandleGetChannelInfo(const base::Value::List& args) { |
| CHECK_EQ(1U, args.size()); |
| const std::string& callback_id = args[0].GetString(); |
| version_updater_->GetChannel( |
| true /* get current channel */, |
| base::BindOnce(&AboutHandler::OnGetCurrentChannel, |
| weak_factory_.GetWeakPtr(), callback_id)); |
| } |
| |
| void AboutHandler::HandleCanChangeChannel(const base::Value::List& args) { |
| CHECK_EQ(1U, args.size()); |
| const std::string& callback_id = args[0].GetString(); |
| ResolveJavascriptCallback(base::Value(callback_id), |
| base::Value(CanChangeChannel(profile_))); |
| } |
| |
| void AboutHandler::OnGetCurrentChannel(std::string callback_id, |
| const std::string& current_channel) { |
| version_updater_->GetChannel( |
| false /* get target channel */, |
| base::BindOnce(&AboutHandler::OnGetTargetChannel, |
| weak_factory_.GetWeakPtr(), callback_id, current_channel)); |
| } |
| |
| void AboutHandler::OnGetTargetChannel(std::string callback_id, |
| const std::string& current_channel, |
| const std::string& target_channel) { |
| base::Value::Dict channel_info; |
| channel_info.Set("currentChannel", current_channel); |
| channel_info.Set("targetChannel", target_channel); |
| |
| // For the LTS pilot simply check whether the device policy is set and ignore |
| // its value. |
| std::string value; |
| bool is_lts = |
| ash::CrosSettings::Get()->GetString(ash::kReleaseLtsTag, &value); |
| channel_info.Set("isLts", is_lts); |
| |
| ResolveJavascriptCallback(base::Value(callback_id), channel_info); |
| } |
| |
| void AboutHandler::HandleApplyDeferredUpdate(const base::Value::List& args) { |
| version_updater_->ApplyDeferredUpdate(); |
| } |
| |
| void AboutHandler::HandleRequestUpdate(const base::Value::List& args) { |
| RequestUpdate(); |
| } |
| |
| void AboutHandler::HandleRequestUpdateOverCellular( |
| const base::Value::List& args) { |
| CHECK_EQ(2U, args.size()); |
| |
| const std::string& update_version = args[0].GetString(); |
| const std::string& update_size_string = args[1].GetString(); |
| int64_t update_size; |
| CHECK(base::StringToInt64(update_size_string, &update_size)); |
| |
| RequestUpdateOverCellular(update_version, update_size); |
| } |
| |
| void AboutHandler::RequestUpdateOverCellular(const std::string& update_version, |
| int64_t update_size) { |
| version_updater_->SetUpdateOverCellularOneTimePermission( |
| base::BindRepeating(&AboutHandler::SetUpdateStatus, |
| base::Unretained(this)), |
| update_version, update_size); |
| } |
| |
| void AboutHandler::HandleRefreshTPMFirmwareUpdateStatus( |
| const base::Value::List& args) { |
| ash::tpm_firmware_update::GetAvailableUpdateModes( |
| base::BindOnce(&AboutHandler::RefreshTPMFirmwareUpdateStatus, |
| weak_factory_.GetWeakPtr()), |
| base::TimeDelta()); |
| } |
| |
| void AboutHandler::RefreshTPMFirmwareUpdateStatus( |
| const std::set<ash::tpm_firmware_update::Mode>& modes) { |
| base::Value::Dict event; |
| event.Set("updateAvailable", !modes.empty()); |
| FireWebUIListener("tpm-firmware-update-status-changed", event); |
| } |
| |
| void AboutHandler::HandleGetEndOfLifeInfo(const base::Value::List& args) { |
| CHECK_EQ(1U, args.size()); |
| const std::string& callback_id = args[0].GetString(); |
| version_updater_->GetEolInfo(base::BindOnce(&AboutHandler::OnGetEndOfLifeInfo, |
| weak_factory_.GetWeakPtr(), |
| callback_id)); |
| } |
| |
| void AboutHandler::OnGetEndOfLifeInfo( |
| std::string callback_id, |
| ash::UpdateEngineClient::EolInfo eol_info) { |
| base::Value::Dict response; |
| if (!eol_info.eol_date.is_null()) { |
| bool has_eol_passed = eol_info.eol_date <= clock_->Now(); |
| response.Set("hasEndOfLife", has_eol_passed); |
| int eol_string_id = |
| has_eol_passed ? IDS_SETTINGS_ABOUT_PAGE_END_OF_LIFE_MESSAGE_PAST |
| : IDS_SETTINGS_ABOUT_PAGE_END_OF_LIFE_MESSAGE_FUTURE; |
| response.Set( |
| "aboutPageEndOfLifeMessage", |
| l10n_util::GetStringFUTF16( |
| eol_string_id, |
| base::TimeFormatMonthAndYearForTimeZone(eol_info.eol_date, |
| icu::TimeZone::getGMT()), |
| base::ASCIIToUTF16(has_eol_passed ? chrome::kEolNotificationURL |
| : chrome::kAutoUpdatePolicyURL))); |
| const ash::eol_incentive_util::EolIncentiveType eolIncentiveType = |
| ash::eol_incentive_util::ShouldShowEolIncentive( |
| profile_, eol_info.eol_date, clock_->Now()); |
| response.Set( |
| "shouldShowEndOfLifeIncentive", |
| (eolIncentiveType == |
| ash::eol_incentive_util::EolIncentiveType::kEolPassedRecently || |
| eolIncentiveType == |
| ash::eol_incentive_util::EolIncentiveType::kEolPassed) && |
| has_eol_passed && |
| base::FeatureList::IsEnabled(ash::features::kEolIncentiveSettings)); |
| eol_incentive_shows_offer_ = |
| (ash::features::kEolIncentiveParam.Get() != |
| ash::features::EolIncentiveParam::kNoOffer && |
| eolIncentiveType == |
| ash::eol_incentive_util::EolIncentiveType::kEolPassedRecently); |
| response.Set("shouldShowOfferText", eol_incentive_shows_offer_); |
| } else { |
| response.Set("hasEndOfLife", false); |
| response.Set("aboutPageEndOfLifeMessage", ""); |
| response.Set("shouldShowEndOfLifeIncentive", false); |
| response.Set("shouldShowOfferText", false); |
| } |
| ResolveJavascriptCallback(base::Value(callback_id), response); |
| } |
| |
| void AboutHandler::HandleOpenEndOfLifeIncentive(const base::Value::List& args) { |
| DCHECK(args.empty()); |
| ash::NewWindowDelegate::GetPrimary()->OpenUrl( |
| GURL(eol_incentive_shows_offer_ |
| ? chrome::kEolIncentiveNotificationOfferURL |
| : chrome::kEolIncentiveNotificationNoOfferURL), |
| ash::NewWindowDelegate::OpenUrlFrom::kUserInteraction, |
| ash::NewWindowDelegate::Disposition::kNewForegroundTab); |
| } |
| |
| void AboutHandler::HandleIsManagedAutoUpdateEnabled( |
| const base::Value::List& args) { |
| CHECK_EQ(1U, args.size()); |
| const std::string& callback_id = args[0].GetString(); |
| ResolveJavascriptCallback( |
| base::Value(callback_id), |
| base::Value(version_updater_->IsManagedAutoUpdateEnabled())); |
| } |
| |
| void AboutHandler::HandleIsConsumerAutoUpdateEnabled( |
| const base::Value::List& args) { |
| CHECK_EQ(1U, args.size()); |
| const std::string& callback_id = args[0].GetString(); |
| const std::string& feature = update_engine::kFeatureConsumerAutoUpdate; |
| version_updater_->IsFeatureEnabled( |
| feature, |
| base::BindOnce(&AboutHandler::OnIsConsumerAutoUpdateEnabled, |
| weak_factory_.GetWeakPtr(), callback_id, feature)); |
| } |
| |
| void AboutHandler::OnIsConsumerAutoUpdateEnabled(std::string callback_id, |
| std::string feature, |
| absl::optional<bool> enabled) { |
| if (!enabled.has_value()) { |
| LOG(ERROR) << "Failed to get feature value for " << feature |
| << " defaulting to enabled"; |
| enabled = true; |
| } |
| ResolveJavascriptCallback(base::Value(callback_id), |
| base::Value(enabled.value())); |
| } |
| |
| void AboutHandler::HandleSetConsumerAutoUpdate(const base::Value::List& args) { |
| CHECK_EQ(1U, args.size()); |
| if (!args[0].is_bool()) { |
| LOG(ERROR) << "Can't parse SetConsumerAutoUpdate() args"; |
| return; |
| } |
| bool enable = args[0].GetBool(); |
| const std::string& feature = update_engine::kFeatureConsumerAutoUpdate; |
| version_updater_->ToggleFeature(feature, enable); |
| } |
| |
| void AboutHandler::HandleOpenProductLicenseOther( |
| const base::Value::List& args) { |
| ash::NewWindowDelegate::GetPrimary()->OpenUrl( |
| GURL(chrome::kChromeUICreditsURL), |
| ash::NewWindowDelegate::OpenUrlFrom::kUserInteraction, |
| ash::NewWindowDelegate::Disposition::kSwitchToTab); |
| } |
| |
| #endif // BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| void AboutHandler::RequestUpdate() { |
| version_updater_->CheckForUpdate( |
| base::BindRepeating(&AboutHandler::SetUpdateStatus, |
| base::Unretained(this)), |
| #if BUILDFLAG(IS_MAC) |
| base::BindRepeating(&AboutHandler::SetPromotionState, |
| base::Unretained(this))); |
| #else |
| VersionUpdater::PromoteCallback()); |
| #endif // BUILDFLAG(IS_MAC) |
| } |
| |
| void AboutHandler::SetUpdateStatus(VersionUpdater::Status status, |
| int progress, |
| bool rollback, |
| bool powerwash, |
| const std::string& version, |
| int64_t size, |
| const std::u16string& message) { |
| // Only UPDATING state should have progress set. |
| DCHECK(status == VersionUpdater::UPDATING || progress == 0); |
| |
| base::Value::Dict event; |
| event.Set("status", UpdateStatusToString(status)); |
| event.Set("message", message); |
| event.Set("progress", progress); |
| event.Set("rollback", rollback); |
| event.Set("powerwash", powerwash); |
| event.Set("version", version); |
| // `base::Value::Dict` does not support int64_t, so convert to string. |
| event.Set("size", base::NumberToString(size)); |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| std::u16string types_msg; |
| if (status == VersionUpdater::FAILED_OFFLINE || |
| status == VersionUpdater::FAILED_CONNECTION_TYPE_DISALLOWED) { |
| types_msg = GetAllowedConnectionTypesMessage(); |
| } |
| base::Value types_value; |
| if (!types_msg.empty()) { |
| types_value = base::Value(std::move(types_msg)); |
| } |
| event.Set("connectionTypes", std::move(types_value)); |
| #endif // BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| FireWebUIListener("update-status-changed", event); |
| } |
| |
| #if BUILDFLAG(IS_MAC) |
| void AboutHandler::SetPromotionState(VersionUpdater::PromotionState state) { |
| // Worth noting: PROMOTE_DISABLED indicates that promotion is possible, |
| // there's just something else going on right now (e.g. checking for update). |
| bool hidden = state == VersionUpdater::PROMOTE_HIDDEN; |
| bool disabled = state == VersionUpdater::PROMOTE_HIDDEN || |
| state == VersionUpdater::PROMOTE_DISABLED || |
| state == VersionUpdater::PROMOTED; |
| bool actionable = state == VersionUpdater::PROMOTE_DISABLED || |
| state == VersionUpdater::PROMOTE_ENABLED; |
| |
| std::u16string text; |
| if (actionable) |
| text = l10n_util::GetStringUTF16(IDS_ABOUT_CHROME_AUTOUPDATE_ALL); |
| else if (state == VersionUpdater::PROMOTED) |
| text = l10n_util::GetStringUTF16(IDS_ABOUT_CHROME_AUTOUPDATE_ALL_IS_ON); |
| |
| base::Value::Dict promo_state; |
| promo_state.Set("hidden", hidden); |
| promo_state.Set("disabled", disabled); |
| promo_state.Set("actionable", actionable); |
| if (!text.empty()) |
| promo_state.Set("text", text); |
| |
| FireWebUIListener("promotion-state-changed", promo_state); |
| } |
| #endif // BUILDFLAG(IS_MAC) |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| void AboutHandler::OnRegulatoryLabelDirFound( |
| std::string callback_id, |
| const base::FilePath& label_dir_path) { |
| if (label_dir_path.empty()) { |
| ResolveJavascriptCallback(base::Value(callback_id), base::Value()); |
| return; |
| } |
| |
| base::ThreadPool::PostTaskAndReplyWithResult( |
| FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE}, |
| base::BindOnce(&ReadRegulatoryLabelText, label_dir_path), |
| base::BindOnce(&AboutHandler::OnRegulatoryLabelTextRead, |
| weak_factory_.GetWeakPtr(), callback_id, label_dir_path)); |
| } |
| |
| void AboutHandler::OnRegulatoryLabelTextRead( |
| std::string callback_id, |
| const base::FilePath& label_dir_path, |
| const std::string& text) { |
| base::Value::Dict regulatory_info; |
| // Remove unnecessary whitespace. |
| regulatory_info.Set("text", base::CollapseWhitespaceASCII(text, true)); |
| |
| std::string image_path = |
| label_dir_path.AppendASCII(kRegulatoryLabelImageFilename).MaybeAsASCII(); |
| std::string url = |
| base::StrCat({"chrome://", chrome::kChromeOSAssetHost, "/", image_path}); |
| regulatory_info.Set("url", url); |
| |
| ResolveJavascriptCallback(base::Value(callback_id), regulatory_info); |
| } |
| #endif // BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| } // namespace settings |