Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/installer/setup/setup_main.h" | 5 #include "chrome/installer/setup/setup_main.h" |
| 6 | 6 |
| 7 #include <windows.h> | 7 #include <windows.h> |
| 8 #include <msi.h> | 8 #include <msi.h> |
| 9 #include <shellapi.h> | 9 #include <shellapi.h> |
| 10 #include <shlobj.h> | 10 #include <shlobj.h> |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 73 #endif | 73 #endif |
| 74 | 74 |
| 75 using installer::InstallerState; | 75 using installer::InstallerState; |
| 76 using installer::InstallationState; | 76 using installer::InstallationState; |
| 77 using installer::InstallationValidator; | 77 using installer::InstallationValidator; |
| 78 using installer::MasterPreferences; | 78 using installer::MasterPreferences; |
| 79 using installer::Product; | 79 using installer::Product; |
| 80 using installer::ProductState; | 80 using installer::ProductState; |
| 81 using installer::Products; | 81 using installer::Products; |
| 82 | 82 |
| 83 const wchar_t kGoogleUpdatePipeName[] = L"\\\\.\\pipe\\GoogleCrashServices\\"; | 83 const wchar_t kGoogleUpdatePipeName[] = L"\\\\.\\pipe\\GoogleCrashServices\\"; |
|
grt (UTC plus 2)
2015/09/11 18:14:26
please move all of these constants that are only u
bcwhite
2015/09/11 19:24:44
Done.
| |
| 84 const wchar_t kSystemPrincipalSid[] = L"S-1-5-18"; | 84 const wchar_t kSystemPrincipalSid[] = L"S-1-5-18"; |
| 85 const wchar_t kDisplayVersion[] = L"DisplayVersion"; | |
| 86 const wchar_t kMsiInstallRegistryPrefix[] = | |
| 87 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\" | |
| 88 L"S-1-5-18\\Products\\"; | |
| 89 const wchar_t kMsiInstallRegistryPostfix[] = L"\\InstallProperties"; | |
| 90 const wchar_t kMsiUninstallRegistryPrefix[] = | |
| 91 L"SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\"; | |
| 92 const wchar_t kMsiUninstallRegistryPostfix[] = L""; | |
| 93 const wchar_t kMsiDisplayVersionOverwriteDelay[] = L"10"; // seconds as string | |
| 85 | 94 |
| 86 const MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>( | 95 const MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>( |
| 87 MiniDumpWithProcessThreadData | // Get PEB and TEB. | 96 MiniDumpWithProcessThreadData | // Get PEB and TEB. |
| 88 MiniDumpWithUnloadedModules | // Get unloaded modules when available. | 97 MiniDumpWithUnloadedModules | // Get unloaded modules when available. |
| 89 MiniDumpWithIndirectlyReferencedMemory); // Get memory referenced by stack. | 98 MiniDumpWithIndirectlyReferencedMemory); // Get memory referenced by stack. |
| 90 | 99 |
| 91 namespace { | 100 namespace { |
| 92 | 101 |
| 102 // Overwrite an existing DisplayVersion as written by the MSI installer | |
| 103 // with the real version number of Chrome. | |
| 104 LONG OverwriteDisplayVersion(const base::string16& path, | |
| 105 const base::string16& value) { | |
| 106 base::win::RegKey key; | |
| 107 LONG result = 0; | |
| 108 base::string16 existing; | |
| 109 if ((result = key.Open(HKEY_LOCAL_MACHINE, path.c_str(), | |
| 110 KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_WOW64_64KEY)) | |
| 111 != ERROR_SUCCESS) { | |
| 112 LOG(ERROR) << "Failed to set DisplayVersion: " << path << " not found"; | |
| 113 return result; | |
| 114 } | |
| 115 if ((result = key.ReadValue(kDisplayVersion, &existing)) != ERROR_SUCCESS) { | |
| 116 LOG(ERROR) << "Failed to set DisplayVersion: " << kDisplayVersion | |
| 117 << " not found under " << path; | |
| 118 return result; | |
| 119 } | |
| 120 if ((result = key.WriteValue(kDisplayVersion, value.c_str())) | |
| 121 != ERROR_SUCCESS) { | |
| 122 LOG(ERROR) << "Failed to set DisplayVersion: " << kDisplayVersion | |
| 123 << " could not be written under " << path; | |
| 124 return result; | |
| 125 } | |
| 126 VLOG(1) << "Set DisplayVersion at " << path << " to " << value | |
| 127 << " from " << existing; | |
| 128 return ERROR_SUCCESS; | |
| 129 } | |
| 130 | |
| 131 LONG OverwriteDisplayVersions(const base::string16& product, | |
| 132 const base::string16& value) { | |
| 133 // The version is held in two places. Frist change it in the MSI Installer | |
| 134 // registry entry. It is held under a "squashed guid" key. | |
| 135 base::string16 reg_path(kMsiInstallRegistryPrefix); | |
| 136 reg_path += base::ASCIIToUTF16( | |
|
grt (UTC plus 2)
2015/09/11 18:14:26
can GuidToSquid operate on base::string16 so we do
bcwhite
2015/09/11 19:24:44
Done.
| |
| 137 installer::GuidToSquid(base::UTF16ToASCII(product))); | |
| 138 reg_path += kMsiInstallRegistryPostfix; | |
| 139 LONG result1 = OverwriteDisplayVersion(reg_path, value); | |
| 140 | |
| 141 // The display version also exists under the Unininstall registry key with | |
| 142 // the original guid. | |
| 143 reg_path = kMsiUninstallRegistryPrefix; | |
|
grt (UTC plus 2)
2015/09/11 18:14:26
i think it's more clear to use base::StringPrintf
bcwhite
2015/09/11 19:24:45
Done.
| |
| 144 reg_path += L"{"; | |
| 145 reg_path += product; | |
| 146 reg_path += L"}"; | |
| 147 reg_path += kMsiUninstallRegistryPostfix; | |
| 148 LONG result2 = OverwriteDisplayVersion(reg_path, value); | |
| 149 | |
| 150 return result1 != ERROR_SUCCESS ? result1 : result2; | |
| 151 } | |
| 152 | |
| 153 void DelayedOverwriteDisplayVersions(const base::FilePath& setup_exe, | |
| 154 const base::string16& id, | |
| 155 const Version& version) { | |
| 156 // This process has to be able to exit so we launch ourselves with | |
| 157 // instructions on what to do and then return. | |
| 158 base::CommandLine command_line(setup_exe); | |
| 159 command_line.AppendSwitchNative( | |
| 160 installer::switches::kSetDisplayVersionProduct, id); | |
| 161 command_line.AppendSwitchNative(installer::switches::kSetDisplayVersionValue, | |
|
grt (UTC plus 2)
2015/09/11 18:14:26
nit: use AppendSwitchASCII and remove the ASCIIToU
bcwhite
2015/09/11 19:24:44
Done.
| |
| 162 base::ASCIIToUTF16(version.GetString())); | |
| 163 command_line.AppendSwitchNative(installer::switches::kDelay, | |
| 164 kMsiDisplayVersionOverwriteDelay); | |
| 165 | |
| 166 base::LaunchOptions launch_options; | |
| 167 launch_options.force_breakaway_from_job_ = true; | |
| 168 base::Process writer = base::LaunchProcess(command_line, launch_options); | |
| 169 if (!writer.IsValid()) { | |
| 170 LOG(ERROR) << "Failed to set DisplayVersion: " | |
|
grt (UTC plus 2)
2015/09/11 18:14:26
tip: PLOG(ERROR) and remove the GetLastError() tid
bcwhite
2015/09/11 19:24:45
Done.
| |
| 171 << "could not launch subprocess to make desired changes." | |
| 172 << " (error=" << ::GetLastError() << ")\n" | |
|
grt (UTC plus 2)
2015/09/11 18:14:26
i think it's best not to put newlines in log messa
bcwhite
2015/09/11 19:24:44
Done.
| |
| 173 << command_line.GetCommandLineString(); | |
| 174 } | |
| 175 } | |
| 176 | |
| 93 // Returns NULL if no compressed archive is available for processing, otherwise | 177 // Returns NULL if no compressed archive is available for processing, otherwise |
| 94 // returns a patch helper configured to uncompress and patch. | 178 // returns a patch helper configured to uncompress and patch. |
| 95 scoped_ptr<installer::ArchivePatchHelper> CreateChromeArchiveHelper( | 179 scoped_ptr<installer::ArchivePatchHelper> CreateChromeArchiveHelper( |
| 96 const base::FilePath& setup_exe, | 180 const base::FilePath& setup_exe, |
| 97 const base::CommandLine& command_line, | 181 const base::CommandLine& command_line, |
| 98 const installer::InstallerState& installer_state, | 182 const installer::InstallerState& installer_state, |
| 99 const base::FilePath& working_directory) { | 183 const base::FilePath& working_directory) { |
| 100 // A compressed archive is ordinarily given on the command line by the mini | 184 // A compressed archive is ordinarily given on the command line by the mini |
| 101 // installer. If one was not given, look for chrome.packed.7z next to the | 185 // installer. If one was not given, look for chrome.packed.7z next to the |
| 102 // running program. | 186 // running program. |
| (...skipping 810 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 913 | 997 |
| 914 // This method processes any command line options that make setup.exe do | 998 // This method processes any command line options that make setup.exe do |
| 915 // various tasks other than installation (renaming chrome.exe, showing eula | 999 // various tasks other than installation (renaming chrome.exe, showing eula |
| 916 // among others). This function returns true if any such command line option | 1000 // among others). This function returns true if any such command line option |
| 917 // has been found and processed (so setup.exe should exit at that point). | 1001 // has been found and processed (so setup.exe should exit at that point). |
| 918 bool HandleNonInstallCmdLineOptions(const InstallationState& original_state, | 1002 bool HandleNonInstallCmdLineOptions(const InstallationState& original_state, |
| 919 const base::FilePath& setup_exe, | 1003 const base::FilePath& setup_exe, |
| 920 const base::CommandLine& cmd_line, | 1004 const base::CommandLine& cmd_line, |
| 921 InstallerState* installer_state, | 1005 InstallerState* installer_state, |
| 922 int* exit_code) { | 1006 int* exit_code) { |
| 1007 // This option is independent of all others so doesn't belong in the if/else | |
| 1008 // block below. | |
| 1009 if (cmd_line.HasSwitch(installer::switches::kDelay)) { | |
| 1010 const std::string delay_seconds_string( | |
| 1011 cmd_line.GetSwitchValueASCII(installer::switches::kDelay)); | |
| 1012 int delay_seconds; | |
| 1013 if (base::StringToInt(delay_seconds_string, &delay_seconds) && | |
| 1014 delay_seconds > 0) { | |
| 1015 base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(delay_seconds)); | |
| 1016 } | |
| 1017 } | |
| 1018 | |
| 923 // TODO(gab): Add a local |status| variable which each block below sets; | 1019 // TODO(gab): Add a local |status| variable which each block below sets; |
| 924 // only determine the |exit_code| from |status| at the end (this will allow | 1020 // only determine the |exit_code| from |status| at the end (this will allow |
| 925 // this method to validate that | 1021 // this method to validate that |
| 926 // (!handled || status != installer::UNKNOWN_STATUS)). | 1022 // (!handled || status != installer::UNKNOWN_STATUS)). |
| 927 bool handled = true; | 1023 bool handled = true; |
| 928 // TODO(tommi): Split these checks up into functions and use a data driven | 1024 // TODO(tommi): Split these checks up into functions and use a data driven |
| 929 // map of switch->function. | 1025 // map of switch->function. |
| 930 if (cmd_line.HasSwitch(installer::switches::kUpdateSetupExe)) { | 1026 if (cmd_line.HasSwitch(installer::switches::kUpdateSetupExe)) { |
| 931 installer::InstallStatus status = installer::SETUP_PATCH_FAILED; | 1027 installer::InstallStatus status = installer::SETUP_PATCH_FAILED; |
| 932 // If --update-setup-exe command line option is given, we apply the given | 1028 // If --update-setup-exe command line option is given, we apply the given |
| (...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1156 patch_file, | 1252 patch_file, |
| 1157 output_file); | 1253 output_file); |
| 1158 } else { | 1254 } else { |
| 1159 *exit_code = installer::PATCH_INVALID_ARGUMENTS; | 1255 *exit_code = installer::PATCH_INVALID_ARGUMENTS; |
| 1160 } | 1256 } |
| 1161 } else if (cmd_line.HasSwitch(installer::switches::kReenableAutoupdates)) { | 1257 } else if (cmd_line.HasSwitch(installer::switches::kReenableAutoupdates)) { |
| 1162 // setup.exe has been asked to attempt to reenable updates for Chrome. | 1258 // setup.exe has been asked to attempt to reenable updates for Chrome. |
| 1163 bool updates_enabled = GoogleUpdateSettings::ReenableAutoupdates(); | 1259 bool updates_enabled = GoogleUpdateSettings::ReenableAutoupdates(); |
| 1164 *exit_code = updates_enabled ? installer::REENABLE_UPDATES_SUCCEEDED : | 1260 *exit_code = updates_enabled ? installer::REENABLE_UPDATES_SUCCEEDED : |
| 1165 installer::REENABLE_UPDATES_FAILED; | 1261 installer::REENABLE_UPDATES_FAILED; |
| 1262 } else if (cmd_line.HasSwitch( | |
| 1263 installer::switches::kSetDisplayVersionProduct)) { | |
| 1264 const base::string16 registry_product( | |
| 1265 cmd_line.GetSwitchValueNative( | |
| 1266 installer::switches::kSetDisplayVersionProduct)); | |
| 1267 const base::string16 registry_value( | |
| 1268 cmd_line.GetSwitchValueNative( | |
| 1269 installer::switches::kSetDisplayVersionValue)); | |
| 1270 *exit_code = OverwriteDisplayVersions(registry_product, registry_value); | |
| 1166 } else { | 1271 } else { |
| 1167 handled = false; | 1272 handled = false; |
| 1168 } | 1273 } |
| 1169 | 1274 |
| 1170 return handled; | 1275 return handled; |
| 1171 } | 1276 } |
| 1172 | 1277 |
| 1173 // Returns the Custom information for the client identified by the exe path | 1278 // Returns the Custom information for the client identified by the exe path |
| 1174 // passed in. This information is used for crash reporting. | 1279 // passed in. This information is used for crash reporting. |
| 1175 google_breakpad::CustomClientInfo* GetCustomInfo(const wchar_t* exe_path) { | 1280 google_breakpad::CustomClientInfo* GetCustomInfo(const wchar_t* exe_path) { |
| (...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1546 .Append(setup_path.BaseName()); | 1651 .Append(setup_path.BaseName()); |
| 1547 } | 1652 } |
| 1548 const Products& products = installer_state.products(); | 1653 const Products& products = installer_state.products(); |
| 1549 for (Products::const_iterator it = products.begin(); it < products.end(); | 1654 for (Products::const_iterator it = products.begin(); it < products.end(); |
| 1550 ++it) { | 1655 ++it) { |
| 1551 const Product& product = **it; | 1656 const Product& product = **it; |
| 1552 product.LaunchUserExperiment(setup_path, install_status, system_install); | 1657 product.LaunchUserExperiment(setup_path, install_status, system_install); |
| 1553 } | 1658 } |
| 1554 } | 1659 } |
| 1555 | 1660 |
| 1556 // If installation completed successfully, return the path to the directory | 1661 // If the installation completed successfully... |
| 1557 // containing the newly installed setup.exe and uncompressed archive if the | 1662 if (InstallUtil::GetInstallReturnCode(install_status) == 0) { |
| 1558 // caller requested it. | 1663 // Update the DisplayVersion created by an MSI-based install. |
| 1559 if (installer_directory && | 1664 std::string install_id; |
| 1560 InstallUtil::GetInstallReturnCode(install_status) == 0) { | 1665 if (prefs.GetString(installer::master_preferences::kMsiProductId, |
| 1561 *installer_directory = | 1666 &install_id)) { |
| 1562 installer_state.GetInstallerDirectory(*installer_version); | 1667 base::FilePath new_setup = |
| 1668 installer_state.GetInstallerDirectory(*installer_version) | |
| 1669 .Append(kSetupExe); | |
| 1670 DelayedOverwriteDisplayVersions( | |
| 1671 new_setup, base::ASCIIToUTF16(install_id), *installer_version); | |
|
grt (UTC plus 2)
2015/09/11 18:14:26
nit: pass install_id directly and use AppendSwitch
bcwhite
2015/09/11 19:24:44
Done.
grt (UTC plus 2)
2015/09/11 20:07:01
Not done?
bcwhite
2015/09/12 03:49:23
Weird. I absolutely did change that; no idea how
| |
| 1672 } | |
| 1673 // Return the path to the directory containing the newly installed | |
| 1674 // setup.exe and uncompressed archive if the caller requested it. | |
| 1675 if (installer_directory) { | |
| 1676 *installer_directory = | |
| 1677 installer_state.GetInstallerDirectory(*installer_version); | |
| 1678 } | |
| 1563 } | 1679 } |
| 1564 | 1680 |
| 1565 // temp_path's dtor will take care of deleting or scheduling itself for | 1681 // temp_path's dtor will take care of deleting or scheduling itself for |
| 1566 // deletion at reboot when this scope closes. | 1682 // deletion at reboot when this scope closes. |
| 1567 VLOG(1) << "Deleting temporary directory " << temp_path.path().value(); | 1683 VLOG(1) << "Deleting temporary directory " << temp_path.path().value(); |
| 1568 | 1684 |
| 1569 return install_status; | 1685 return install_status; |
| 1570 } | 1686 } |
| 1571 | 1687 |
| 1572 } // namespace installer | 1688 } // namespace installer |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1717 // Note that we allow the status installer::UNINSTALL_REQUIRES_REBOOT | 1833 // Note that we allow the status installer::UNINSTALL_REQUIRES_REBOOT |
| 1718 // to pass through, since this is only returned on uninstall which is | 1834 // to pass through, since this is only returned on uninstall which is |
| 1719 // never invoked directly by Google Update. | 1835 // never invoked directly by Google Update. |
| 1720 return_code = InstallUtil::GetInstallReturnCode(install_status); | 1836 return_code = InstallUtil::GetInstallReturnCode(install_status); |
| 1721 } | 1837 } |
| 1722 | 1838 |
| 1723 VLOG(1) << "Installation complete, returning: " << return_code; | 1839 VLOG(1) << "Installation complete, returning: " << return_code; |
| 1724 | 1840 |
| 1725 return return_code; | 1841 return return_code; |
| 1726 } | 1842 } |
| OLD | NEW |