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 using installer::InstallerState; | 73 using installer::InstallerState; |
| 74 using installer::InstallationState; | 74 using installer::InstallationState; |
| 75 using installer::InstallationValidator; | 75 using installer::InstallationValidator; |
| 76 using installer::MasterPreferences; | 76 using installer::MasterPreferences; |
| 77 using installer::Product; | 77 using installer::Product; |
| 78 using installer::ProductState; | 78 using installer::ProductState; |
| 79 using installer::Products; | 79 using installer::Products; |
| 80 | 80 |
| 81 const wchar_t kGoogleUpdatePipeName[] = L"\\\\.\\pipe\\GoogleCrashServices\\"; | 81 const wchar_t kGoogleUpdatePipeName[] = L"\\\\.\\pipe\\GoogleCrashServices\\"; |
| 82 const wchar_t kSystemPrincipalSid[] = L"S-1-5-18"; | 82 const wchar_t kSystemPrincipalSid[] = L"S-1-5-18"; |
| 83 const wchar_t kDisplayVersion[] = L"DisplayVersion"; | |
| 84 const wchar_t kMsiInstallRegistryPrefix[] = | |
| 85 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\" | |
| 86 L"S-1-5-18\\Products\\"; | |
| 87 const wchar_t kMsiInstallRegistryPostfix[] = L"\\InstallProperties"; | |
| 88 const wchar_t kMsiDisplayVersionOverwriteDelay[] = L"30"; // seconds as string | |
| 83 | 89 |
| 84 const MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>( | 90 const MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>( |
| 85 MiniDumpWithProcessThreadData | // Get PEB and TEB. | 91 MiniDumpWithProcessThreadData | // Get PEB and TEB. |
| 86 MiniDumpWithUnloadedModules | // Get unloaded modules when available. | 92 MiniDumpWithUnloadedModules | // Get unloaded modules when available. |
| 87 MiniDumpWithIndirectlyReferencedMemory); // Get memory referenced by stack. | 93 MiniDumpWithIndirectlyReferencedMemory); // Get memory referenced by stack. |
| 88 | 94 |
| 89 namespace { | 95 namespace { |
| 90 | 96 |
| 97 // Overwrite an existing DisplayVersion as written by the MSI installer | |
| 98 // with the real version number of Chrome. | |
| 99 LONG OverwriteDisplayVersion(const base::string16& path, | |
| 100 const base::string16& value) { | |
| 101 base::win::RegKey key; | |
| 102 LONG result = 0; | |
| 103 base::string16 existing; | |
| 104 if ((result = key.Open(HKEY_LOCAL_MACHINE, path.c_str(), | |
| 105 KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_WOW64_64KEY)) | |
| 106 != ERROR_SUCCESS) { | |
| 107 LOG(ERROR) << "Failed to set DisplayVersion: " << path << " not found"; | |
| 108 return result; | |
| 109 } | |
| 110 if ((result = key.ReadValue(kDisplayVersion, &existing)) != ERROR_SUCCESS) { | |
| 111 LOG(ERROR) << "Failed to set DisplayVersion: " << kDisplayVersion | |
| 112 << " not found under " << path; | |
| 113 return result; | |
| 114 } | |
| 115 if ((result = key.WriteValue(kDisplayVersion, value.c_str())) | |
| 116 != ERROR_SUCCESS) { | |
| 117 LOG(ERROR) << "Failed to set DisplayVersion: " << kDisplayVersion | |
| 118 << " could not be written under " << path; | |
| 119 return result; | |
| 120 } | |
| 121 VLOG(1) << "Set DisplayVersion at " << path << " to " << value | |
| 122 << " from " << existing; | |
| 123 return ERROR_SUCCESS; | |
| 124 } | |
| 125 | |
| 126 void DelayedOverwriteDisplayVersion(const base::FilePath& setup_exe, | |
| 127 const std::string& id, | |
| 128 const Version& version) { | |
| 129 base::string16 reg_path(kMsiInstallRegistryPrefix); | |
| 130 reg_path += base::UTF8ToUTF16(id); | |
| 131 reg_path += kMsiInstallRegistryPostfix; | |
| 132 | |
| 133 // This process has to be able to exit so we launch ourselves with | |
| 134 // instructions on what to do and then return. | |
| 135 base::string16 command_line; | |
|
robertshield
2015/08/18 17:27:26
base::CommandLine provides convenience methods to
bcwhite
2015/09/02 15:21:45
Done.
| |
| 136 command_line += L"\""; | |
| 137 command_line += setup_exe.AsUTF16Unsafe(); | |
| 138 command_line += L"\" --"; | |
| 139 command_line += base::UTF8ToUTF16( | |
| 140 installer::switches::kSetDisplayVersionPath); | |
| 141 command_line += L"="; | |
| 142 command_line += reg_path; | |
| 143 command_line += L" --"; | |
| 144 command_line += base::UTF8ToUTF16( | |
| 145 installer::switches::kSetDisplayVersionValue); | |
| 146 command_line += L"="; | |
| 147 command_line += base::UTF8ToUTF16(version.GetString()); | |
| 148 command_line += L" --"; | |
| 149 command_line += base::UTF8ToUTF16(installer::switches::kDelay); | |
| 150 command_line += L"="; | |
| 151 command_line += kMsiDisplayVersionOverwriteDelay; | |
| 152 | |
| 153 STARTUPINFOW si = {sizeof(si)}; | |
| 154 PROCESS_INFORMATION pi = {0}; | |
| 155 if (!::CreateProcess(setup_exe.AsUTF16Unsafe().c_str(), | |
|
robertshield
2015/08/18 17:27:26
use base::LaunchProcess here (https://code.google.
grt (UTC plus 2)
2015/08/19 17:43:30
i wonder if this should also use force_breakaway_f
robertshield
2015/08/19 17:57:07
I don't think it would hurt. MSI could also concei
bcwhite
2015/09/02 15:21:45
Why here but not elsewhere in this file?
grt (UTC plus 2)
2015/09/02 20:43:55
base::LaunchProcess should always be used unless s
bcwhite
2015/09/09 18:20:22
Done.
| |
| 156 (LPWSTR)command_line.c_str(), // discards const | |
|
robertshield
2015/08/18 17:27:26
can you const_cast instead?
bcwhite
2015/09/02 15:21:45
Already gone with switch to base::CommandLine.
| |
| 157 NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, | |
| 158 &si, &pi)) { | |
| 159 LOG(ERROR) << "Failed to set DisplayVersion: " | |
| 160 << "could not launch subprocess to make desired changes." | |
| 161 << " (error=" << ::GetLastError() << ")\n" | |
| 162 << command_line; | |
| 163 return; | |
| 164 } | |
| 165 ::CloseHandle(pi.hThread); | |
| 166 } | |
| 167 | |
| 91 // Returns NULL if no compressed archive is available for processing, otherwise | 168 // Returns NULL if no compressed archive is available for processing, otherwise |
| 92 // returns a patch helper configured to uncompress and patch. | 169 // returns a patch helper configured to uncompress and patch. |
| 93 scoped_ptr<installer::ArchivePatchHelper> CreateChromeArchiveHelper( | 170 scoped_ptr<installer::ArchivePatchHelper> CreateChromeArchiveHelper( |
| 94 const base::FilePath& setup_exe, | 171 const base::FilePath& setup_exe, |
| 95 const base::CommandLine& command_line, | 172 const base::CommandLine& command_line, |
| 96 const installer::InstallerState& installer_state, | 173 const installer::InstallerState& installer_state, |
| 97 const base::FilePath& working_directory) { | 174 const base::FilePath& working_directory) { |
| 98 // A compressed archive is ordinarily given on the command line by the mini | 175 // A compressed archive is ordinarily given on the command line by the mini |
| 99 // installer. If one was not given, look for chrome.packed.7z next to the | 176 // installer. If one was not given, look for chrome.packed.7z next to the |
| 100 // running program. | 177 // running program. |
| (...skipping 810 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 911 | 988 |
| 912 // This method processes any command line options that make setup.exe do | 989 // This method processes any command line options that make setup.exe do |
| 913 // various tasks other than installation (renaming chrome.exe, showing eula | 990 // various tasks other than installation (renaming chrome.exe, showing eula |
| 914 // among others). This function returns true if any such command line option | 991 // among others). This function returns true if any such command line option |
| 915 // has been found and processed (so setup.exe should exit at that point). | 992 // has been found and processed (so setup.exe should exit at that point). |
| 916 bool HandleNonInstallCmdLineOptions(const InstallationState& original_state, | 993 bool HandleNonInstallCmdLineOptions(const InstallationState& original_state, |
| 917 const base::FilePath& setup_exe, | 994 const base::FilePath& setup_exe, |
| 918 const base::CommandLine& cmd_line, | 995 const base::CommandLine& cmd_line, |
| 919 InstallerState* installer_state, | 996 InstallerState* installer_state, |
| 920 int* exit_code) { | 997 int* exit_code) { |
| 998 // This option is independent of all others so doesn't belong in the if/else | |
| 999 // block below. | |
| 1000 if (cmd_line.HasSwitch(installer::switches::kDelay)) { | |
| 1001 const std::string delay_seconds_string( | |
| 1002 cmd_line.GetSwitchValueASCII(installer::switches::kDelay)); | |
| 1003 int delay_seconds; | |
| 1004 if (base::StringToInt(delay_seconds_string, &delay_seconds) && | |
| 1005 delay_seconds > 0) { | |
| 1006 ::Sleep(delay_seconds * 1000); | |
| 1007 } | |
| 1008 } | |
| 1009 | |
| 921 // TODO(gab): Add a local |status| variable which each block below sets; | 1010 // TODO(gab): Add a local |status| variable which each block below sets; |
| 922 // only determine the |exit_code| from |status| at the end (this will allow | 1011 // only determine the |exit_code| from |status| at the end (this will allow |
| 923 // this method to validate that | 1012 // this method to validate that |
| 924 // (!handled || status != installer::UNKNOWN_STATUS)). | 1013 // (!handled || status != installer::UNKNOWN_STATUS)). |
| 925 bool handled = true; | 1014 bool handled = true; |
| 926 // TODO(tommi): Split these checks up into functions and use a data driven | 1015 // TODO(tommi): Split these checks up into functions and use a data driven |
| 927 // map of switch->function. | 1016 // map of switch->function. |
| 928 if (cmd_line.HasSwitch(installer::switches::kUpdateSetupExe)) { | 1017 if (cmd_line.HasSwitch(installer::switches::kUpdateSetupExe)) { |
| 929 installer::InstallStatus status = installer::SETUP_PATCH_FAILED; | 1018 installer::InstallStatus status = installer::SETUP_PATCH_FAILED; |
| 930 // If --update-setup-exe command line option is given, we apply the given | 1019 // If --update-setup-exe command line option is given, we apply the given |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1145 patch_file, | 1234 patch_file, |
| 1146 output_file); | 1235 output_file); |
| 1147 } else { | 1236 } else { |
| 1148 *exit_code = installer::PATCH_INVALID_ARGUMENTS; | 1237 *exit_code = installer::PATCH_INVALID_ARGUMENTS; |
| 1149 } | 1238 } |
| 1150 } else if (cmd_line.HasSwitch(installer::switches::kReenableAutoupdates)) { | 1239 } else if (cmd_line.HasSwitch(installer::switches::kReenableAutoupdates)) { |
| 1151 // setup.exe has been asked to attempt to reenable updates for Chrome. | 1240 // setup.exe has been asked to attempt to reenable updates for Chrome. |
| 1152 bool updates_enabled = GoogleUpdateSettings::ReenableAutoupdates(); | 1241 bool updates_enabled = GoogleUpdateSettings::ReenableAutoupdates(); |
| 1153 *exit_code = updates_enabled ? installer::REENABLE_UPDATES_SUCCEEDED : | 1242 *exit_code = updates_enabled ? installer::REENABLE_UPDATES_SUCCEEDED : |
| 1154 installer::REENABLE_UPDATES_FAILED; | 1243 installer::REENABLE_UPDATES_FAILED; |
| 1244 } else if (cmd_line.HasSwitch(installer::switches::kSetDisplayVersionPath)) { | |
| 1245 const base::string16 registry_path( | |
| 1246 cmd_line.GetSwitchValueNative( | |
| 1247 installer::switches::kSetDisplayVersionPath)); | |
| 1248 const base::string16 registry_value( | |
|
grt (UTC plus 2)
2015/08/19 17:43:30
i think it's better to extract the version from th
bcwhite
2015/09/02 15:21:45
If the original process has already gone through t
| |
| 1249 cmd_line.GetSwitchValueNative( | |
| 1250 installer::switches::kSetDisplayVersionValue)); | |
| 1251 *exit_code = OverwriteDisplayVersion(registry_path, registry_value); | |
| 1155 } else { | 1252 } else { |
| 1156 handled = false; | 1253 handled = false; |
| 1157 } | 1254 } |
| 1158 | 1255 |
| 1159 return handled; | 1256 return handled; |
| 1160 } | 1257 } |
| 1161 | 1258 |
| 1162 // Returns the Custom information for the client identified by the exe path | 1259 // Returns the Custom information for the client identified by the exe path |
| 1163 // passed in. This information is used for crash reporting. | 1260 // passed in. This information is used for crash reporting. |
| 1164 google_breakpad::CustomClientInfo* GetCustomInfo(const wchar_t* exe_path) { | 1261 google_breakpad::CustomClientInfo* GetCustomInfo(const wchar_t* exe_path) { |
| (...skipping 364 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1529 .Append(setup_path.BaseName()); | 1626 .Append(setup_path.BaseName()); |
| 1530 } | 1627 } |
| 1531 const Products& products = installer_state.products(); | 1628 const Products& products = installer_state.products(); |
| 1532 for (Products::const_iterator it = products.begin(); it < products.end(); | 1629 for (Products::const_iterator it = products.begin(); it < products.end(); |
| 1533 ++it) { | 1630 ++it) { |
| 1534 const Product& product = **it; | 1631 const Product& product = **it; |
| 1535 product.LaunchUserExperiment(setup_path, install_status, system_install); | 1632 product.LaunchUserExperiment(setup_path, install_status, system_install); |
| 1536 } | 1633 } |
| 1537 } | 1634 } |
| 1538 | 1635 |
| 1539 // If installation completed successfully, return the path to the directory | 1636 // If the installation completed successfully... |
| 1540 // containing the newly installed setup.exe and uncompressed archive if the | 1637 if (InstallUtil::GetInstallReturnCode(install_status) == 0) { |
| 1541 // caller requested it. | 1638 // Update the DisplayVersion created by an MSI-based install. |
| 1542 if (installer_directory && | 1639 std::string install_id; |
| 1543 InstallUtil::GetInstallReturnCode(install_status) == 0) { | 1640 if (prefs.GetString(installer::master_preferences::kMsiInstallId, |
| 1544 *installer_directory = | 1641 &install_id)) { |
| 1545 installer_state.GetInstallerDirectory(*installer_version); | 1642 DelayedOverwriteDisplayVersion(setup_exe, install_id, *installer_version); |
|
grt (UTC plus 2)
2015/08/19 17:43:30
if i'm reading the code correctly, |setup_exe| is
bcwhite
2015/09/02 15:21:45
Done.
| |
| 1643 } | |
| 1644 // Return the path to the directory containing the newly installed | |
| 1645 // setup.exe and uncompressed archive if the caller requested it. | |
| 1646 if (installer_directory) | |
| 1647 *installer_directory = | |
| 1648 installer_state.GetInstallerDirectory(*installer_version); | |
| 1546 } | 1649 } |
| 1547 | 1650 |
| 1548 // temp_path's dtor will take care of deleting or scheduling itself for | 1651 // temp_path's dtor will take care of deleting or scheduling itself for |
| 1549 // deletion at reboot when this scope closes. | 1652 // deletion at reboot when this scope closes. |
| 1550 VLOG(1) << "Deleting temporary directory " << temp_path.path().value(); | 1653 VLOG(1) << "Deleting temporary directory " << temp_path.path().value(); |
| 1551 | 1654 |
| 1552 return install_status; | 1655 return install_status; |
| 1553 } | 1656 } |
| 1554 | 1657 |
| 1555 } // namespace installer | 1658 } // namespace installer |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1700 // Note that we allow the status installer::UNINSTALL_REQUIRES_REBOOT | 1803 // Note that we allow the status installer::UNINSTALL_REQUIRES_REBOOT |
| 1701 // to pass through, since this is only returned on uninstall which is | 1804 // to pass through, since this is only returned on uninstall which is |
| 1702 // never invoked directly by Google Update. | 1805 // never invoked directly by Google Update. |
| 1703 return_code = InstallUtil::GetInstallReturnCode(install_status); | 1806 return_code = InstallUtil::GetInstallReturnCode(install_status); |
| 1704 } | 1807 } |
| 1705 | 1808 |
| 1706 VLOG(1) << "Installation complete, returning: " << return_code; | 1809 VLOG(1) << "Installation complete, returning: " << return_code; |
| 1707 | 1810 |
| 1708 return return_code; | 1811 return return_code; |
| 1709 } | 1812 } |
| OLD | NEW |