From f9cb187cbf1dcbe872b07546663355e5ae50ef9a Mon Sep 17 00:00:00 2001 From: Alexander Frick Date: Thu, 28 Dec 2023 21:33:15 -0600 Subject: [PATCH] update bookmarks and enable SSE2 setup.exe --- infra/THORIUM_DEV_BOOKMARKS.html | 363 +++++----- infra/portable/THORIUM_SHELL.BAT | 2 +- src/chrome/installer/setup/setup_util.cc | 840 +++++++++++++++++++++++ 3 files changed, 1023 insertions(+), 182 deletions(-) create mode 100644 src/chrome/installer/setup/setup_util.cc diff --git a/infra/THORIUM_DEV_BOOKMARKS.html b/infra/THORIUM_DEV_BOOKMARKS.html index 682f8755..eda67edc 100644 --- a/infra/THORIUM_DEV_BOOKMARKS.html +++ b/infra/THORIUM_DEV_BOOKMARKS.html @@ -13,208 +13,209 @@
Thorium Flags

THOR1

-

BUILD.gn - Chromium Code Search -
BUILD.gn - Chromium Code Search -
BUILD.gn - Chromium Code Search -
arm.gni - Chromium Code Search -
chromium_strings.grd - Chromium Code Search -
settings_chromium_strings.grdp - Chromium Code Search -
settings_strings.grdp - Chromium Code Search -
shared_settings_strings.grdp - Chromium Code Search -
generated_resources.grd - Chromium Code Search -
ffmpeg_options.gni - Chromium Code Search -
background_mode_manager.cc - Chromium Code Search -
floc_id_provider_factory.cc - Chromium Code Search -
stub_resolver_config_reader.cc - Chromium Code Search -
browser_ui_prefs.cc - Chromium Code Search -
google_api_keys_infobar_delegate.cc - Chromium Code Search -
infobar_utils.cc - Chromium Code Search -
default_browser_infobar_delegate.cc - Chromium Code Search -
chrome_constants.cc - Chromium Code Search -
common - Chromium Code Search -
debian - Chromium Code Search -
chrome.release - Chromium Code Search -
mini_installer_exe_main.cc - Chromium Code Search -
download_features.cc - Chromium Code Search -
privacy_sandbox_settings.cc - Chromium Code Search -
privacy_sandbox_prefs.cc - Chromium Code Search -
prepopulated_engines.json - Chromium Code Search -
template_url_prepopulate_data.cc - Chromium Code Search -
search_engine_type.h - Chromium Code Search +
BUILD.gn - Chromium Code Search +
BUILD.gn - Chromium Code Search +
BUILD.gn - Chromium Code Search +
arm.gni - Chromium Code Search +
chromium_strings.grd - Chromium Code Search +
settings_chromium_strings.grdp - Chromium Code Search +
settings_strings.grdp - Chromium Code Search +
shared_settings_strings.grdp - Chromium Code Search +
generated_resources.grd - Chromium Code Search +
ffmpeg_options.gni - Chromium Code Search +
background_mode_manager.cc - Chromium Code Search +
floc_id_provider_factory.cc - Chromium Code Search +
stub_resolver_config_reader.cc - Chromium Code Search +
browser_ui_prefs.cc - Chromium Code Search +
google_api_keys_infobar_delegate.cc - Chromium Code Search +
infobar_utils.cc - Chromium Code Search +
default_browser_infobar_delegate.cc - Chromium Code Search +
chrome_constants.cc - Chromium Code Search +
common - Chromium Code Search +
debian - Chromium Code Search +
chrome.release - Chromium Code Search +
mini_installer_exe_main.cc - Chromium Code Search +
download_features.cc - Chromium Code Search +
privacy_sandbox_settings.cc - Chromium Code Search +
privacy_sandbox_prefs.cc - Chromium Code Search +
prepopulated_engines.json - Chromium Code Search +
template_url_prepopulate_data.cc - Chromium Code Search +
search_engine_type.h - Chromium Code Search

THOR2

-

BUILD.gn - Chromium Code Search -
theme - Chromium Code Search -
theme - Chromium Code Search -
BUILD.gn - Chromium Code Search -
media_switches.cc - Chromium Code Search -
ffmpeg_video_decoder.cc - Chromium Code Search -
gpu_video_decode_accelerator_factory.cc - Chromium Code Search -
gpu_video_decode_accelerator.cc - Chromium Code Search -
vaapi_video_decode_accelerator.cc - Chromium Code Search -
vaapi_video_decode_accelerator.h - Chromium Code Search -
vaapi_wrapper.cc - Chromium Code Search -
vaapi_wrapper.h - Chromium Code Search -
load_flags_list.h - Chromium Code Search -
dns_transaction.cc - Chromium Code Search -
dns_client.cc - Chromium Code Search -
url_request_http_job.cc - Chromium Code Search -
bpf_audio_policy_linux.cc - Chromium Code Search -
BUILD.gn - Chromium Code Search -
BUILD.gn - Chromium Code Search -
x11_util.cc - Chromium Code Search -
js-display-names.cc - Chromium Code Search -
widevine_cdm_version.h - Chromium Code Search -
cdm_registration.cc - Chromium Code Search -
components.css - Chromium Code Search -
incognito_marker.svg - Chromium Code Search -
incognito.svg - Chromium Code Search -
icon_tabs.svg - Chromium Code Search -
vector_icons - Chromium Code Search -
vector_icons - Chromium Code Search -
vector_icons - Chromium Code Search -
new_incognito_window.icon - Chromium Code Search +
BUILD.gn - Chromium Code Search +
theme - Chromium Code Search +
theme - Chromium Code Search +
BUILD.gn - Chromium Code Search +
media_switches.cc - Chromium Code Search +
ffmpeg_video_decoder.cc - Chromium Code Search +
gpu_video_decode_accelerator_factory.cc - Chromium Code Search +
gpu_video_decode_accelerator.cc - Chromium Code Search +
vaapi_video_decode_accelerator.cc - Chromium Code Search +
vaapi_video_decode_accelerator.h - Chromium Code Search +
vaapi_wrapper.cc - Chromium Code Search +
vaapi_wrapper.h - Chromium Code Search +
load_flags_list.h - Chromium Code Search +
dns_transaction.cc - Chromium Code Search +
dns_client.cc - Chromium Code Search +
url_request_http_job.cc - Chromium Code Search +
bpf_audio_policy_linux.cc - Chromium Code Search +
BUILD.gn - Chromium Code Search +
BUILD.gn - Chromium Code Search +
x11_util.cc - Chromium Code Search +
js-display-names.cc - Chromium Code Search +
widevine_cdm_version.h - Chromium Code Search +
cdm_registration.cc - Chromium Code Search +
components.css - Chromium Code Search +
incognito_marker.svg - Chromium Code Search +
incognito.svg - Chromium Code Search +
icon_tabs.svg - Chromium Code Search +
vector_icons - Chromium Code Search +
vector_icons - Chromium Code Search +
vector_icons - Chromium Code Search +
new_incognito_window.icon - Chromium Code Search

THOR3

-

search.cc - Chromium Code Search -
BUILD.gn - Chromium Code Search -
distilledpage.css - Chromium Code Search -
reload_button.cc - Chromium Code Search -
reload_button.h - Chromium Code Search -
features.cc - Chromium Code Search -
profile_shortcut_manager_win.cc - Chromium Code Search -
parser-base.h - Chromium Code Search -
ui_chromeos_strings.grd - Chromium Code Search -
autofill_payments_strings.grdp - Chromium Code Search -
autofill_strings.grdp - Chromium Code Search -
components_chromium_strings.grd - Chromium Code Search -
components_settings_strings.grdp - Chromium Code Search -
error_page_strings.grdp - Chromium Code Search -
flags_strings.grdp - Chromium Code Search -
heavy_ad_intervention_strings.grdp - Chromium Code Search -
management_strings.grdp - Chromium Code Search -
new_or_sad_tab_strings.grdp - Chromium Code Search -
ntp_snippets_strings.grdp - Chromium Code Search -
page_info_strings.grdp - Chromium Code Search -
reset_password_strings.grdp - Chromium Code Search -
security_interstitials_strings.grdp - Chromium Code Search -
ssl_errors_strings.grdp - Chromium Code Search -
ssl_errors_strings.grdp - Chromium Code Search -
user_data_dir_win_unittest.cc - Chromium Code Search -
chromium_install_modes.cc - Chromium Code Search -
chrome_paths_linux.cc - Chromium Code Search -
chrome_paths_mac.mm - Chromium Code Search -
ui_util.cc - Chromium Code Search -
ui_features.cc - Chromium Code Search -
x509_util.cc - Chromium Code Search +
search.cc - Chromium Code Search +
BUILD.gn - Chromium Code Search +
distilledpage.css - Chromium Code Search +
reload_button.cc - Chromium Code Search +
reload_button.h - Chromium Code Search +
features.cc - Chromium Code Search +
profile_shortcut_manager_win.cc - Chromium Code Search +
parser-base.h - Chromium Code Search +
ui_chromeos_strings.grd - Chromium Code Search +
autofill_payments_strings.grdp - Chromium Code Search +
autofill_strings.grdp - Chromium Code Search +
components_chromium_strings.grd - Chromium Code Search +
components_settings_strings.grdp - Chromium Code Search +
error_page_strings.grdp - Chromium Code Search +
flags_strings.grdp - Chromium Code Search +
heavy_ad_intervention_strings.grdp - Chromium Code Search +
management_strings.grdp - Chromium Code Search +
new_or_sad_tab_strings.grdp - Chromium Code Search +
ntp_snippets_strings.grdp - Chromium Code Search +
page_info_strings.grdp - Chromium Code Search +
reset_password_strings.grdp - Chromium Code Search +
security_interstitials_strings.grdp - Chromium Code Search +
ssl_errors_strings.grdp - Chromium Code Search +
ssl_errors_strings.grdp - Chromium Code Search +
user_data_dir_win_unittest.cc - Chromium Code Search +
chromium_install_modes.cc - Chromium Code Search +
chrome_paths_linux.cc - Chromium Code Search +
chrome_paths_mac.mm - Chromium Code Search +
ui_util.cc - Chromium Code Search +
ui_features.cc - Chromium Code Search +
x509_util.cc - Chromium Code Search

THOR4

-

BUILD.gn - Chromium Code Search -
BUILD.gn - Chromium Code Search -
BUILD.gn - Chromium Code Search -
memory_details_linux.cc - Chromium Code Search -
gtk_util.cc - Chromium Code Search -
chrome_proxy_main_win.cc - Chromium Code Search -
chrome_exe.ver - Chromium Code Search -
chrome_exe.vsprops - Chromium Code Search -
util_constants.cc - Chromium Code Search -
BUILD.gn - Chromium Code Search -
shell_main_delegate.cc - Chromium Code Search -
channel_info_posix.cc - Chromium Code Search -
shell_integration_linux.cc - Chromium Code Search -
BUILD.gn - Chromium Code Search -
mini_installer_exe_version.rc.version - Chromium Code Search -
launch_as_mojo_client_browsertest.cc - Chromium Code Search -
reorder-imports.py - Chromium Code Search -
vs_toolchain.py - Chromium Code Search -
install-build-deps.py - Chromium Code Search -
scheme_constants.cc - Chromium Code Search -
url_constants.cc - Chromium Code Search -
about_ui.cc - Chromium Code Search -
app_management_strings.grdp - Chromium Code Search -
neterror - Chromium Code Search -
resources - Chromium Code Search -
shell_platform_delegate_views.cc - Chromium Code Search -
BUILD.gn - Chromium Code Search -
quiet_notification_permission_ui_state.cc - Chromium Code Search +
BUILD.gn - Chromium Code Search +
BUILD.gn - Chromium Code Search +
BUILD.gn - Chromium Code Search +
memory_details_linux.cc - Chromium Code Search +
gtk_util.cc - Chromium Code Search +
chrome_proxy_main_win.cc - Chromium Code Search +
chrome_exe.ver - Chromium Code Search +
chrome_exe.vsprops - Chromium Code Search +
util_constants.cc - Chromium Code Search +
BUILD.gn - Chromium Code Search +
shell_main_delegate.cc - Chromium Code Search +
channel_info_posix.cc - Chromium Code Search +
shell_integration_linux.cc - Chromium Code Search +
BUILD.gn - Chromium Code Search +
mini_installer_exe_version.rc.version - Chromium Code Search +
launch_as_mojo_client_browsertest.cc - Chromium Code Search +
reorder-imports.py - Chromium Code Search +
vs_toolchain.py - Chromium Code Search +
install-build-deps.py - Chromium Code Search +
scheme_constants.cc - Chromium Code Search +
url_constants.cc - Chromium Code Search +
about_ui.cc - Chromium Code Search +
app_management_strings.grdp - Chromium Code Search +
neterror - Chromium Code Search +
resources - Chromium Code Search +
shell_platform_delegate_views.cc - Chromium Code Search +
BUILD.gn - Chromium Code Search +
quiet_notification_permission_ui_state.cc - Chromium Code Search

THOR5

-

install_worker.cc - Chromium Code Search -
chrome_content_browser_client.cc - Chromium Code Search -
flags_state.cc - Chromium Code Search -
omnibox_view.cc - Chromium Code Search -
about_flags.cc - Chromium Code Search -
build.sh - Chromium Code Search -
browser_commands.cc - Chromium Code Search -
offline_page_model.cc - Chromium Code Search -
url_schemes.cc - Chromium Code Search -
url_utils.cc - Chromium Code Search -
dom_distiller_features.cc - Chromium Code Search -
features.cc - Chromium Code Search -
examples_window.cc - Chromium Code Search -
BUILD.gn - Chromium Code Search -
BUILD.gn - Chromium Code Search -
offline.js - Chromium Code Search -
build.py - Chromium Code Search -
configure.ac - Chromium Code Search -
build_ffmpeg.py - Chromium Code Search -
bookmark_utils.cc - Chromium Code Search -
BUILD.gn - Chromium Code Search -
runtime_enabled_features.json5 - Chromium Code Search -
images - Chromium Code Search -
chromeos_strings.grd - Chromium Code Search +
install_worker.cc - Chromium Code Search +
setup_util.cc - Chromium Code Search +
chrome_content_browser_client.cc - Chromium Code Search +
flags_state.cc - Chromium Code Search +
omnibox_view.cc - Chromium Code Search +
about_flags.cc - Chromium Code Search +
build.sh - Chromium Code Search +
browser_commands.cc - Chromium Code Search +
offline_page_model.cc - Chromium Code Search +
url_schemes.cc - Chromium Code Search +
url_utils.cc - Chromium Code Search +
dom_distiller_features.cc - Chromium Code Search +
features.cc - Chromium Code Search +
examples_window.cc - Chromium Code Search +
BUILD.gn - Chromium Code Search +
BUILD.gn - Chromium Code Search +
offline.js - Chromium Code Search +
build.py - Chromium Code Search +
configure.ac - Chromium Code Search +
build_ffmpeg.py - Chromium Code Search +
bookmark_utils.cc - Chromium Code Search +
BUILD.gn - Chromium Code Search +
runtime_enabled_features.json5 - Chromium Code Search +
images - Chromium Code Search +
chromeos_strings.grd - Chromium Code Search

QUARANTINE_PATCH

-

base_file.cc - Chromium Code Search -
BUILD.gn - Chromium Code Search -
toolbar_view.cc - Chromium Code Search -
pepper_file_io_host.cc - Chromium Code Search -
pepper_file_io_host.h - Chromium Code Search -
chrome_location_bar_model_delegate.cc - Chromium Code Search -
file_system_access_safe_move_helper.cc - Chromium Code Search -
file_system_access_safe_move_helper.h - Chromium Code Search -
os_crypt_win.cc - Chromium Code Search -
os_crypt_linux.cc - Chromium Code Search -
machine_id_provider_nonwin.cc - Chromium Code Search -
machine_id_provider_win.cc - Chromium Code Search -
device_id_win.cc - Chromium Code Search -
accelerator_table.cc - Chromium Code Search -
browser.cc - Chromium Code Search -
browser.h - Chromium Code Search +
base_file.cc - Chromium Code Search +
BUILD.gn - Chromium Code Search +
toolbar_view.cc - Chromium Code Search +
pepper_file_io_host.cc - Chromium Code Search +
pepper_file_io_host.h - Chromium Code Search +
chrome_location_bar_model_delegate.cc - Chromium Code Search +
file_system_access_safe_move_helper.cc - Chromium Code Search +
file_system_access_safe_move_helper.h - Chromium Code Search +
os_crypt_win.cc - Chromium Code Search +
os_crypt_linux.cc - Chromium Code Search +
machine_id_provider_nonwin.cc - Chromium Code Search +
machine_id_provider_win.cc - Chromium Code Search +
device_id_win.cc - Chromium Code Search +
accelerator_table.cc - Chromium Code Search +
browser.cc - Chromium Code Search +
browser.h - Chromium Code Search

Android

-

java - Chromium Code Search -
BUILD.gn - Chromium Code Search -
chrome_public_apk_tmpl.gni - Chromium Code Search -
android_chrome_strings.grd - Chromium Code Search -
native_theme_gtk.cc - Chromium Code Search -
about_version.html - Chromium Code Search -
supported_types.cc - Chromium Code Search -
bad_flags_prompt.cc - Chromium Code Search -
variations_service.cc - Chromium Code Search -
ffmpeg_common.cc - Chromium Code Search -
BUILD.gn - Chromium Code Search -
media_options.gni - Chromium Code Search -
ignores.txt - Chromium Code Search +
java - Chromium Code Search +
BUILD.gn - Chromium Code Search +
chrome_public_apk_tmpl.gni - Chromium Code Search +
android_chrome_strings.grd - Chromium Code Search +
native_theme_gtk.cc - Chromium Code Search +
about_version.html - Chromium Code Search +
supported_types.cc - Chromium Code Search +
bad_flags_prompt.cc - Chromium Code Search +
variations_service.cc - Chromium Code Search +
ffmpeg_common.cc - Chromium Code Search +
BUILD.gn - Chromium Code Search +
media_options.gni - Chromium Code Search +
ignores.txt - Chromium Code Search

Th23

-

tab.cc - Chromium Code Search -
tab_strip.cc - Chromium Code Search -
tab_style_views.cc - Chromium Code Search -
tab_style_views.h - Chromium Code Search -
history_backend.cc - Chromium Code Search -
browser_root_view.h - Chromium Code Search -
browser_root_view.cc - Chromium Code Search -
new_tab_page_feed_v2_expandable_header.xml - Chromium Code Search -
new_tab_page_multi_feed_header.xml - Chromium Code Search -
pref_names.cc - Chromium Code Search +
tab.cc - Chromium Code Search +
tab_strip.cc - Chromium Code Search +
tab_style_views.cc - Chromium Code Search +
tab_style_views.h - Chromium Code Search +
history_backend.cc - Chromium Code Search +
browser_root_view.h - Chromium Code Search +
browser_root_view.cc - Chromium Code Search +
new_tab_page_feed_v2_expandable_header.xml - Chromium Code Search +
new_tab_page_multi_feed_header.xml - Chromium Code Search +
pref_names.cc - Chromium Code Search

Chromium Code Search
overlay-amd64-generic - Chromium Code Search diff --git a/infra/portable/THORIUM_SHELL.BAT b/infra/portable/THORIUM_SHELL.BAT index 56d8e1ec..7e806618 100644 --- a/infra/portable/THORIUM_SHELL.BAT +++ b/infra/portable/THORIUM_SHELL.BAT @@ -1 +1 @@ -START "" "%cd%\BIN\117.0.5938.157\thorium_shell.exe" --data-path="%~dp0%\USER_DATA\thorium_shell" --allow-outdated-plugins --disable-logging --disable-breakpad --enable-experimental-web-platform-features +START "" "%cd%\BIN\119.0.6045.214\thorium_shell.exe" --data-path="%~dp0%\USER_DATA\thorium_shell" --allow-outdated-plugins --disable-logging --disable-breakpad --enable-experimental-web-platform-features diff --git a/src/chrome/installer/setup/setup_util.cc b/src/chrome/installer/setup/setup_util.cc new file mode 100644 index 00000000..1d84d39b --- /dev/null +++ b/src/chrome/installer/setup/setup_util.cc @@ -0,0 +1,840 @@ +// Copyright 2023 The Chromium Authors and Alex313031 +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +// +// This file declares util functions for setup project. + +#include "chrome/installer/setup/setup_util.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "base/base64.h" +#include "base/check.h" +#include "base/command_line.h" +#include "base/cpu.h" +#include "base/files/file.h" +#include "base/files/file_enumerator.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/functional/bind.h" +#include "base/logging.h" +#include "base/metrics/histogram_functions.h" +#include "base/metrics/histogram_macros.h" +#include "base/numerics/safe_conversions.h" +#include "base/ranges/algorithm.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "base/version.h" +#include "base/win/registry.h" +#include "base/win/win_util.h" +#include "base/win/windows_version.h" +#include "build/branding_buildflags.h" +#include "build/build_config.h" +#include "chrome/install_static/install_details.h" +#include "chrome/install_static/install_modes.h" +#include "chrome/install_static/install_util.h" +#include "chrome/installer/setup/installer_state.h" +#include "chrome/installer/setup/setup_constants.h" +#include "chrome/installer/setup/user_hive_visitor.h" +#include "chrome/installer/util/app_command.h" +#include "chrome/installer/util/google_update_constants.h" +#include "chrome/installer/util/google_update_settings.h" +#include "chrome/installer/util/initial_preferences.h" +#include "chrome/installer/util/initial_preferences_constants.h" +#include "chrome/installer/util/install_util.h" +#include "chrome/installer/util/installation_state.h" +#include "chrome/installer/util/registry_util.h" +#include "chrome/installer/util/util_constants.h" +#include "chrome/installer/util/work_item.h" +#include "chrome/installer/util/work_item_list.h" +#include "components/zucchini/zucchini.h" +#include "components/zucchini/zucchini_integration.h" +#include "courgette/courgette.h" +#include "courgette/third_party/bsdiff/bsdiff.h" + +namespace installer { + +namespace { + +// Event log providers registry location. +constexpr wchar_t kEventLogProvidersRegPath[] = + L"SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\"; + +// Remove the registration of the browser's DelegateExecute verb handler class. +// This was once registered in support of "metro" mode on Windows 8. +void RemoveLegacyIExecuteCommandKey(const InstallerState& installer_state) { + const std::wstring handler_class_uuid = + install_static::GetLegacyCommandExecuteImplClsid(); + + // No work to do if this mode of install never registered a DelegateExecute + // verb handler. + if (handler_class_uuid.empty()) + return; + + const HKEY root = installer_state.root_key(); + std::wstring delegate_execute_path(L"Software\\Classes\\CLSID\\"); + delegate_execute_path.append(handler_class_uuid); + + // Delete both 64 and 32 keys to handle 32->64 or 64->32 migration. + for (REGSAM bitness : {KEY_WOW64_32KEY, KEY_WOW64_64KEY}) + installer::DeleteRegistryKey(root, delegate_execute_path, bitness); +} + +// "The binaries" once referred to the on-disk footprint of Chrome and/or Chrome +// Frame when the products were configured to share such on-disk bits. Support +// for this mode of install was dropped from ToT in December 2016. Remove any +// stray bits in the registry leftover from such installs. +void RemoveBinariesVersionKey(const InstallerState& installer_state) { +#if !BUILDFLAG(GOOGLE_CHROME_FOR_TESTING_BRANDING) +#if BUILDFLAG(GOOGLE_CHROME_BRANDING) + std::wstring path(install_static::GetClientsKeyPath( + L"{4DC8B4CA-1BDA-483e-B5FA-D3C12E15B62D}")); +#else + // Assume that non-Google is Chromium branding. + std::wstring path(L"Software\\Chromium Binaries"); +#endif + installer::DeleteRegistryKey(installer_state.root_key(), path, + KEY_WOW64_32KEY); +#endif // !BUILDFLAG(GOOGLE_CHROME_FOR_TESTING_BRANDING) +} + +void RemoveAppLauncherVersionKey(const InstallerState& installer_state) { +// The app launcher was only registered for Google Chrome. +#if BUILDFLAG(GOOGLE_CHROME_BRANDING) + static constexpr wchar_t kLauncherGuid[] = + L"{FDA71E6F-AC4C-4a00-8B70-9958A68906BF}"; + + installer::DeleteRegistryKey(installer_state.root_key(), + install_static::GetClientsKeyPath(kLauncherGuid), + KEY_WOW64_32KEY); +#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) +} + +void RemoveLegacyChromeAppCommands(const InstallerState& installer_state) { +// These app commands were only registered for Google Chrome. +#if BUILDFLAG(GOOGLE_CHROME_BRANDING) + std::unique_ptr list(WorkItem::CreateWorkItemList()); + AppCommand(L"install-extension", {}) + .AddDeleteAppCommandWorkItems(installer_state.root_key(), list.get()); + list->Do(); +#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING) +} + +} // namespace + +const char kUnPackStatusMetricsName[] = "Setup.Install.LzmaUnPackStatus"; + +int CourgettePatchFiles(const base::FilePath& src, + const base::FilePath& patch, + const base::FilePath& dest) { + VLOG(1) << "Applying Courgette patch " << patch.value() << " to file " + << src.value() << " and generating file " << dest.value(); + + if (src.empty() || patch.empty() || dest.empty()) + return installer::PATCH_INVALID_ARGUMENTS; + + const courgette::Status patch_status = courgette::ApplyEnsemblePatch( + src.value().c_str(), patch.value().c_str(), dest.value().c_str()); + const int exit_code = + (patch_status != courgette::C_OK) + ? static_cast(patch_status) + kCourgetteErrorOffset + : 0; + + LOG_IF(ERROR, exit_code) << "Failed to apply Courgette patch " + << patch.value() << " to file " << src.value() + << " and generating file " << dest.value() + << ". err=" << exit_code; + + return exit_code; +} + +int BsdiffPatchFiles(const base::FilePath& src, + const base::FilePath& patch, + const base::FilePath& dest) { + VLOG(1) << "Applying bsdiff patch " << patch.value() << " to file " + << src.value() << " and generating file " << dest.value(); + + if (src.empty() || patch.empty() || dest.empty()) + return installer::PATCH_INVALID_ARGUMENTS; + + const int patch_status = bsdiff::ApplyBinaryPatch(src, patch, dest); + const int exit_code = + patch_status != bsdiff::OK ? patch_status + kBsdiffErrorOffset : 0; + + LOG_IF(ERROR, exit_code) << "Failed to apply bsdiff patch " << patch.value() + << " to file " << src.value() + << " and generating file " << dest.value() + << ". err=" << exit_code; + + return exit_code; +} + +int ZucchiniPatchFiles(const base::FilePath& src, + const base::FilePath& patch, + const base::FilePath& dest) { + VLOG(1) << "Applying Zucchini patch " << patch.value() << " to file " + << src.value() << " and generating file " << dest.value(); + + if (src.empty() || patch.empty() || dest.empty()) + return installer::PATCH_INVALID_ARGUMENTS; + + const zucchini::status::Code patch_status = zucchini::Apply(src, patch, dest); + const int exit_code = + (patch_status != zucchini::status::kStatusSuccess) + ? static_cast(patch_status) + kZucchiniErrorOffset + : 0; + + LOG_IF(ERROR, exit_code) << "Failed to apply Zucchini patch " << patch.value() + << " to file " << src.value() + << " and generating file " << dest.value() + << ". err=" << exit_code; + + return exit_code; +} + +base::Version* GetMaxVersionFromArchiveDir(const base::FilePath& chrome_path) { + VLOG(1) << "Looking for Chrome version folder under " << chrome_path.value(); + base::FileEnumerator version_enum(chrome_path, false, + base::FileEnumerator::DIRECTORIES); + // TODO(tommi): The version directory really should match the version of + // setup.exe. To begin with, we should at least DCHECK that that's true. + + std::unique_ptr max_version(new base::Version("0.0.0.0")); + bool version_found = false; + + while (!version_enum.Next().empty()) { + base::FileEnumerator::FileInfo find_data = version_enum.GetInfo(); + VLOG(1) << "directory found: " << find_data.GetName().value(); + + std::unique_ptr found_version( + new base::Version(base::WideToASCII(find_data.GetName().value()))); + if (found_version->IsValid() && + found_version->CompareTo(*max_version.get()) > 0) { + max_version = std::move(found_version); + version_found = true; + } + } + + return (version_found ? max_version.release() : nullptr); +} + +base::FilePath FindArchiveToPatch(const InstallationState& original_state, + const InstallerState& installer_state, + const base::Version& desired_version) { + if (desired_version.IsValid()) { + base::FilePath archive( + installer_state.GetInstallerDirectory(desired_version) + .Append(kChromeArchive)); + return base::PathExists(archive) ? archive : base::FilePath(); + } + + // Check based on the version number advertised to Google Update, since that + // is the value used to select a specific differential update. If an archive + // can't be found using that, fallback to using the newest version present. + base::FilePath patch_source; + const ProductState* product = + original_state.GetProductState(installer_state.system_install()); + if (product) { + patch_source = installer_state.GetInstallerDirectory(product->version()) + .Append(installer::kChromeArchive); + if (base::PathExists(patch_source)) + return patch_source; + } + std::unique_ptr version( + installer::GetMaxVersionFromArchiveDir(installer_state.target_path())); + if (version) { + patch_source = installer_state.GetInstallerDirectory(*version).Append( + installer::kChromeArchive); + if (base::PathExists(patch_source)) + return patch_source; + } + return base::FilePath(); +} + +bool DeleteFileFromTempProcess(const base::FilePath& path, + uint32_t delay_before_delete_ms) { + static const wchar_t kRunDll32Path[] = + L"%SystemRoot%\\System32\\rundll32.exe"; + wchar_t rundll32[MAX_PATH]; + DWORD size = + ExpandEnvironmentStrings(kRunDll32Path, rundll32, std::size(rundll32)); + if (!size || size >= MAX_PATH) + return false; + + STARTUPINFO startup = {sizeof(STARTUPINFO)}; + PROCESS_INFORMATION pi = {0}; + BOOL ok = ::CreateProcess(nullptr, rundll32, nullptr, nullptr, FALSE, + CREATE_SUSPENDED, nullptr, nullptr, &startup, &pi); + if (ok) { + // We use the main thread of the new process to run: + // Sleep(delay_before_delete_ms); + // DeleteFile(path); + // ExitProcess(0); + // This runs before the main routine of the process runs, so it doesn't + // matter much which executable we choose except that we don't want to + // use e.g. a console app that causes a window to be created. + size = static_cast((path.value().length() + 1) * + sizeof(path.value()[0])); + void* mem = ::VirtualAllocEx(pi.hProcess, nullptr, size, MEM_COMMIT, + PAGE_READWRITE); + if (mem) { + SIZE_T written = 0; + ::WriteProcessMemory(pi.hProcess, mem, path.value().c_str(), + (path.value().size() + 1) * sizeof(path.value()[0]), + &written); + HMODULE kernel32 = ::GetModuleHandle(L"kernel32.dll"); + PAPCFUNC sleep = + reinterpret_cast(::GetProcAddress(kernel32, "Sleep")); + PAPCFUNC delete_file = + reinterpret_cast(::GetProcAddress(kernel32, "DeleteFileW")); + PAPCFUNC exit_process = + reinterpret_cast(::GetProcAddress(kernel32, "ExitProcess")); + if (!sleep || !delete_file || !exit_process) { + NOTREACHED(); + ok = FALSE; + } else { + ::QueueUserAPC(sleep, pi.hThread, delay_before_delete_ms); + ::QueueUserAPC(delete_file, pi.hThread, + reinterpret_cast(mem)); + ::QueueUserAPC(exit_process, pi.hThread, 0); + ::ResumeThread(pi.hThread); + } + } else { + PLOG(ERROR) << "VirtualAllocEx"; + ::TerminateProcess(pi.hProcess, ~static_cast(0)); + } + ::CloseHandle(pi.hThread); + ::CloseHandle(pi.hProcess); + } + + return ok != FALSE; +} + +bool AdjustThreadPriority() { + const DWORD priority_class = ::GetPriorityClass(::GetCurrentProcess()); + if (priority_class == BELOW_NORMAL_PRIORITY_CLASS || + priority_class == IDLE_PRIORITY_CLASS) { + // Don't use SetPriorityClass with PROCESS_MODE_BACKGROUND_BEGIN because it + // will cap the process working set to 32 MiB. See + // https://crbug.com/1475179. + const BOOL result = + ::SetThreadPriority(::GetCurrentThread(), THREAD_MODE_BACKGROUND_BEGIN); + PLOG_IF(WARNING, !result) << "Failed to enter background mode."; + return !!result; + } + + if (priority_class == 0) + PLOG(WARNING) << "Failed to get the process's priority class."; + + return false; +} + +bool IsUninstallSuccess(InstallStatus install_status) { + // The following status values represent failed uninstalls: + // 15: CHROME_NOT_INSTALLED + // 20: UNINSTALL_FAILED + // 21: UNINSTALL_CANCELLED + return (install_status == UNINSTALL_SUCCESSFUL || + install_status == UNINSTALL_REQUIRES_REBOOT); +} + +bool ContainsUnsupportedSwitch(const base::CommandLine& cmd_line) { + static const char* const kLegacySwitches[] = { + // Chrome Frame ready-mode. + "ready-mode", + "ready-mode-opt-in", + "ready-mode-temp-opt-out", + "ready-mode-end-temp-opt-out", + // Chrome Frame quick-enable. + "quick-enable-cf", + // Installation of Chrome Frame. + "chrome-frame", + "migrate-chrome-frame", + // Stand-alone App Launcher. + "app-host", + "app-launcher", + }; + for (size_t i = 0; i < std::size(kLegacySwitches); ++i) { + if (cmd_line.HasSwitch(kLegacySwitches[i])) + return true; + } + return false; +} + +bool IsProcessorSupported() { +#if defined(ARCH_CPU_X86_FAMILY) + return base::CPU().has_sse2(); +#elif defined(ARCH_CPU_ARM64) + return true; +#else +#error Port +#endif +} + +void DeleteRegistryKeyPartial( + HKEY root, + const std::wstring& path, + const std::vector& keys_to_preserve) { + // Downcase the list of keys to preserve (all must be ASCII strings). + std::set lowered_keys_to_preserve; + base::ranges::transform( + keys_to_preserve, + std::inserter(lowered_keys_to_preserve, lowered_keys_to_preserve.begin()), + [](const std::wstring& str) { + DCHECK(!str.empty()); + DCHECK(base::IsStringASCII(str)); + return base::ToLowerASCII(str); + }); + base::win::RegKey key; + LONG result = + key.Open(root, path.c_str(), + (KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_SET_VALUE)); + if (result != ERROR_SUCCESS) { + LOG_IF(ERROR, result != ERROR_FILE_NOT_FOUND) + << "Failed to open " << path << "; result = " << result; + return; + } + + // Repeatedly iterate over all subkeys deleting those that should not be + // preserved until only those remain. Multiple passes are needed since + // deleting one key may change the enumeration order of all remaining keys. + + // Subkeys or values to be skipped on subsequent passes. + std::set to_skip; + DWORD index = 0; + const size_t kMaxKeyNameLength = 256; // MSDN says 255; +1 for terminator. + std::wstring name(kMaxKeyNameLength, wchar_t()); + bool did_delete = false; // True if at least one item was deleted. + while (true) { + DWORD name_length = base::saturated_cast(name.capacity()); + name.resize(name_length); + result = ::RegEnumKeyEx(key.Handle(), index, &name[0], &name_length, + nullptr, nullptr, nullptr, nullptr); + if (result == ERROR_MORE_DATA) { + // Unexpected, but perhaps the max key name length was raised. MSDN + // doesn't clearly say that name_length will contain the necessary + // length in this case, so double the buffer and try again. + name.reserve(name.capacity() * 2); + continue; + } + if (result == ERROR_NO_MORE_ITEMS) { + if (!did_delete) + break; // All subkeys were deleted. The job is done. + // Otherwise, loop again. + did_delete = false; + index = 0; + continue; + } + if (result != ERROR_SUCCESS) + break; + // Shrink the string to the actual length of the name. + name.resize(name_length); + + // Skip over this key if it couldn't be deleted on a previous iteration. + if (to_skip.count(name)) { + ++index; + continue; + } + + // Skip over this key if it is one of the keys to preserve. + if (base::IsStringASCII(name) && + lowered_keys_to_preserve.count(base::ToLowerASCII(name))) { + // Add the true name of the key to the list of keys to skip for subsequent + // iterations. + to_skip.insert(name); + ++index; + continue; + } + + // Delete this key. + result = key.DeleteKey(name.c_str()); + if (result != ERROR_SUCCESS) { + LOG(ERROR) << "Failed to delete subkey " << name << " under path " + << path; + // Skip over this key on subsequent iterations. + to_skip.insert(name); + ++index; + continue; + } + did_delete = true; + } + + // Delete the key if it no longer has any subkeys. + if (to_skip.empty()) { + result = key.DeleteKey(L""); + if (result != ERROR_SUCCESS) { + ::SetLastError(result); + PLOG(ERROR) << "Failed to delete key " << path; + } + return; + } + + // Delete all values since subkeys are being preserved. + to_skip.clear(); + did_delete = false; + index = 0; + while (true) { + DWORD name_length = base::saturated_cast(name.capacity()); + name.resize(name_length); + result = ::RegEnumValue(key.Handle(), index, &name[0], &name_length, + nullptr, nullptr, nullptr, nullptr); + if (result == ERROR_MORE_DATA) { + if (name_length < + static_cast(std::numeric_limits::max())) { + // Double the space to hold the value name and try again. + name.reserve(name.capacity() * 2); + continue; + } + // Otherwise, the max has been exceeded. Nothing more to be done. + break; + } + if (result == ERROR_NO_MORE_ITEMS) { + if (!did_delete) + break; // All values were deleted. The job is done. + // Otherwise, loop again. + did_delete = false; + index = 0; + continue; + } + if (result != ERROR_SUCCESS) + break; + // Shrink the string to the actual length of the name. + name.resize(name_length); + + // Skip over this value if it couldn't be deleted on a previous iteration. + if (to_skip.count(name)) { + ++index; + continue; + } + + // Delete this value. + result = key.DeleteValue(name.c_str()); + if (result != ERROR_SUCCESS) { + LOG(ERROR) << "Failed to delete value " << name << " in key " << path; + // Skip over this value on subsequent iterations. + to_skip.insert(name); + ++index; + continue; + } + did_delete = true; + } +} + +bool IsDowngradeAllowed(const InitialPreferences& prefs) { + bool allow_downgrade = false; + return prefs.GetBool(initial_preferences::kAllowDowngrade, + &allow_downgrade) && + allow_downgrade; +} + +int GetInstallAge(const InstallerState& installer_state) { + base::File::Info info; + if (!base::GetFileInfo(installer_state.target_path(), &info)) + return -1; + base::TimeDelta age = base::Time::Now() - info.creation_time; + return age >= base::TimeDelta() ? age.InDays() : -1; +} + +void RecordUnPackMetrics(UnPackStatus unpack_status, UnPackConsumer consumer) { + std::string consumer_name; + + switch (consumer) { + case UnPackConsumer::CHROME_ARCHIVE_PATCH: + consumer_name = "ChromeArchivePatch"; + break; + case UnPackConsumer::COMPRESSED_CHROME_ARCHIVE: + consumer_name = "CompressedChromeArchive"; + break; + case UnPackConsumer::SETUP_EXE_PATCH: + consumer_name = "SetupExePatch"; + break; + case UnPackConsumer::UNCOMPRESSED_CHROME_ARCHIVE: + consumer_name = "UncompressedChromeArchive"; + break; + } + + base::UmaHistogramExactLinear( + std::string(std::string(kUnPackStatusMetricsName) + "_" + consumer_name), + unpack_status, UNPACK_STATUS_COUNT); +} + +void RegisterEventLogProvider(const base::FilePath& install_directory, + const base::Version& version) { + std::wstring reg_path(kEventLogProvidersRegPath); + reg_path.append(install_static::InstallDetails::Get().install_full_name()); + VLOG(1) << "Registering Chrome's event log provider at " << reg_path; + + std::unique_ptr work_item_list(WorkItem::CreateWorkItemList()); + work_item_list->set_log_message("Register event log provider"); + + work_item_list->AddCreateRegKeyWorkItem(HKEY_LOCAL_MACHINE, reg_path, + WorkItem::kWow64Default); + // Speicifes the number of event categories defined in the dll. + work_item_list->AddSetRegValueWorkItem( + HKEY_LOCAL_MACHINE, reg_path, WorkItem::kWow64Default, L"CategoryCount", + static_cast(1), true); + // Specifies the event type emitted by this event source. + work_item_list->AddSetRegValueWorkItem( + HKEY_LOCAL_MACHINE, reg_path, WorkItem::kWow64Default, L"TypesSupported", + static_cast(EVENTLOG_ERROR_TYPE | EVENTLOG_INFORMATION_TYPE | + EVENTLOG_WARNING_TYPE), + true); + + const base::FilePath provider( + install_directory.AppendASCII(version.GetString()) + .Append(FILE_PATH_LITERAL("eventlog_provider.dll"))); + + static constexpr const wchar_t* kFileKeys[] = { + L"CategoryMessageFile", + L"EventMessageFile", + L"ParameterMessageFile", + }; + for (const wchar_t* file_key : kFileKeys) { + work_item_list->AddSetRegValueWorkItem(HKEY_LOCAL_MACHINE, reg_path, + WorkItem::kWow64Default, file_key, + provider.value(), true); + } + + // if the operation fails we log the error but still continue because none of + // these are critical for the proper operation of the browser. + if (!work_item_list->Do()) + work_item_list->Rollback(); +} + +void DeRegisterEventLogProvider() { + std::wstring reg_path(kEventLogProvidersRegPath); + reg_path.append(install_static::InstallDetails::Get().install_full_name()); + + // TODO(http://crbug.com/668120): If the Event Viewer is open the provider dll + // will fail to get deleted. This doesn't fail the uninstallation altogether + // but leaves files behind. + installer::DeleteRegistryKey(HKEY_LOCAL_MACHINE, reg_path, + WorkItem::kWow64Default); +} + +void DoLegacyCleanups(const InstallerState& installer_state, + InstallStatus install_status) { + // Do no harm if the install didn't succeed. + if (InstallUtil::GetInstallReturnCode(install_status)) + return; + + // Cleanups that apply to any install mode. + RemoveLegacyIExecuteCommandKey(installer_state); + + // The cleanups below only apply to normal Chrome, not side-by-side (canary). + if (!install_static::InstallDetails::Get().is_primary_mode()) + return; + + RemoveBinariesVersionKey(installer_state); + RemoveAppLauncherVersionKey(installer_state); + RemoveLegacyChromeAppCommands(installer_state); +} + +base::Time GetConsoleSessionStartTime() { + constexpr DWORD kInvalidSessionId = 0xFFFFFFFF; + DWORD console_session_id = ::WTSGetActiveConsoleSessionId(); + if (console_session_id == kInvalidSessionId) + return base::Time(); + wchar_t* buffer = nullptr; + DWORD buffer_size = 0; + if (!::WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, + console_session_id, WTSSessionInfo, &buffer, + &buffer_size)) { + return base::Time(); + } + base::ScopedClosureRunner wts_deleter( + base::BindOnce(&::WTSFreeMemory, base::Unretained(buffer))); + + WTSINFO* wts_info = nullptr; + if (buffer_size < sizeof(*wts_info)) + return base::Time(); + + wts_info = reinterpret_cast(buffer); + FILETIME filetime = {wts_info->LogonTime.u.LowPart, + static_cast(wts_info->LogonTime.u.HighPart)}; + return base::Time::FromFileTime(filetime); +} + +absl::optional DecodeDMTokenSwitchValue( + const std::wstring& encoded_token) { + if (encoded_token.empty()) { + LOG(ERROR) << "Empty DMToken specified on the command line"; + return absl::nullopt; + } + + // The token passed on the command line is base64-encoded, but since this is + // on Windows, it is passed in as a wide string containing base64 values only. + std::string token; + if (!base::IsStringASCII(encoded_token) || + !base::Base64Decode(base::WideToASCII(encoded_token), &token)) { + LOG(ERROR) << "DMToken passed on the command line is not correctly encoded"; + return absl::nullopt; + } + + return token; +} + +absl::optional DecodeNonceSwitchValue( + const std::string& encoded_nonce) { + if (encoded_nonce.empty()) { + // The nonce command line argument is optional. If none is specified use + // an empty string. + return std::string(); + } + + // The nonce passed on the command line is base64-encoded. + std::string nonce; + if (!base::Base64Decode(encoded_nonce, &nonce)) { + LOG(ERROR) << "Nonce passed on the command line is not correctly encoded"; + return absl::nullopt; + } + + return nonce; +} + +bool StoreDMToken(const std::string& token) { + DCHECK(install_static::IsSystemInstall()); + + if (token.size() > kMaxDMTokenLength) { + LOG(ERROR) << "DMToken length out of bounds"; + return false; + } + + // Write the token both to the app-neutral and browser-specific locations. + // Only the former is mandatory -- the latter is best-effort. + base::win::RegKey key; + std::wstring value_name; + bool succeeded = false; + for (const auto& is_browser_location : {InstallUtil::BrowserLocation(false), + InstallUtil::BrowserLocation(true)}) { + std::tie(key, value_name) = InstallUtil::GetCloudManagementDmTokenLocation( + InstallUtil::ReadOnly(false), is_browser_location); + // If the key couldn't be opened on the first iteration (the mandatory + // location), return failure straight away. Otherwise, continue iterating. + if (!key.Valid()) { + if (succeeded) + continue; + // Logging already performed in GetCloudManagementDmTokenLocation. + return false; + } + + auto result = + key.WriteValue(value_name.c_str(), token.data(), + base::saturated_cast(token.size()), REG_BINARY); + if (result == ERROR_SUCCESS) { + succeeded = true; + } else if (!succeeded) { + ::SetLastError(result); + PLOG(ERROR) << "Unable to write specified DMToken to the registry"; + return false; + } // Else ignore the failure to write to the best-effort location. + } + + VLOG(1) << "Successfully stored specified DMToken in the registry."; + return true; +} + +bool DeleteDMToken() { + DCHECK(install_static::IsSystemInstall()); + + // Delete the token from both the app-neutral and browser-specific locations. + // Only the former is mandatory -- the latter is best-effort. + for (const auto& is_browser_location : {InstallUtil::BrowserLocation(false), + InstallUtil::BrowserLocation(true)}) { + auto [key_path, value_name] = + InstallUtil::GetCloudManagementDmTokenPath(is_browser_location); + REGSAM wow_access = is_browser_location ? KEY_WOW64_64KEY : KEY_WOW64_32KEY; + + base::win::RegKey key; + auto result = key.Open(HKEY_LOCAL_MACHINE, key_path.c_str(), + KEY_QUERY_VALUE | KEY_SET_VALUE | wow_access); + if (result == ERROR_FILE_NOT_FOUND) { + // The registry key which stores the DMToken value was not found, so + // deletion is not necessary. + continue; + } + if (result != ERROR_SUCCESS) { + ::SetLastError(result); + PLOG(ERROR) << "Failed to open registry key HKLM\\" << key_path + << " for deletion"; + // If the key couldn't be opened for the mandatory location, return + // failure immediately. Otherwise, continue iterating. + if (!is_browser_location) + return false; + continue; + } + + if (!DeleteRegistryValue(key.Handle(), std::wstring(), wow_access, + value_name)) { + if (!is_browser_location) + return false; // Logging already performed in `DeleteRegistryValue()`. + continue; + } // Else ignore the failure to write to the best-effort location. + + // Delete the key if no other values or keys are present. + if (key.GetValueCount().value_or(1) == 0) { + key.DeleteKey(L"", base::win::RegKey::RecursiveDelete(false)); + } + } + + VLOG(1) << "Successfully deleted DMToken from the registry."; + return true; +} + +base::FilePath GetNotificationHelperPath(const base::FilePath& target_path, + const base::Version& version) { + return target_path.AppendASCII(version.GetString()) + .Append(kNotificationHelperExe); +} + +base::FilePath GetWerHelperPath(const base::FilePath& target_path, + const base::Version& version) { + return target_path.AppendASCII(version.GetString()).Append(kWerDll); +} + +std::wstring GetWerHelperRegistryPath() { + return L"Software\\Microsoft\\Windows\\Windows Error Reporting" + L"\\RuntimeExceptionHelperModules"; +} + +base::FilePath GetElevationServicePath(const base::FilePath& target_path, + const base::Version& version) { + return target_path.AppendASCII(version.GetString()) + .Append(kElevationServiceExe); +} + +void AddUpdateDowngradeVersionItem(HKEY root, + const base::Version& current_version, + const base::Version& new_version, + WorkItemList* list) { + DCHECK(list); + DCHECK(new_version.IsValid()); + const auto downgrade_version = InstallUtil::GetDowngradeVersion(); + const std::wstring client_state_key = install_static::GetClientStateKeyPath(); + if (current_version.IsValid() && new_version < current_version) { + // This is a downgrade. Write the value if this is the first one (i.e., no + // previous value exists). Otherwise, leave any existing value in place. + if (!downgrade_version) { + list->AddSetRegValueWorkItem( + root, client_state_key, KEY_WOW64_32KEY, kRegDowngradeVersion, + base::ASCIIToWide(current_version.GetString()), true); + } + } else if (!current_version.IsValid() || new_version >= downgrade_version) { + // This is a new install or an upgrade to/past a previous DowngradeVersion. + list->AddDeleteRegValueWorkItem(root, client_state_key, KEY_WOW64_32KEY, + kRegDowngradeVersion); + } +} + +} // namespace installer