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 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
74 using installer::InstallerState; | 74 using installer::InstallerState; |
75 using installer::InstallationState; | 75 using installer::InstallationState; |
76 using installer::InstallationValidator; | 76 using installer::InstallationValidator; |
77 using installer::MasterPreferences; | 77 using installer::MasterPreferences; |
78 using installer::Product; | 78 using installer::Product; |
79 using installer::ProductState; | 79 using installer::ProductState; |
80 using installer::Products; | 80 using installer::Products; |
81 | 81 |
82 const wchar_t kGoogleUpdatePipeName[] = L"\\\\.\\pipe\\GoogleCrashServices\\"; | 82 const wchar_t kGoogleUpdatePipeName[] = L"\\\\.\\pipe\\GoogleCrashServices\\"; |
83 const wchar_t kSystemPrincipalSid[] = L"S-1-5-18"; | 83 const wchar_t kSystemPrincipalSid[] = L"S-1-5-18"; |
84 const wchar_t kDisplayVersion[] = L"DisplayVersion"; | |
85 const wchar_t kMsiInstallRegistryPrefix[] = | |
86 L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Installer\\UserData\\" | |
87 L"S-1-5-18\\Products\\"; | |
88 const wchar_t kMsiInstallRegistryPostfix[] = L"\\InstallProperties"; | |
89 const wchar_t kMsiDisplayVersionOverwriteDelay[] = L"30"; // seconds as string | |
84 | 90 |
85 const MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>( | 91 const MINIDUMP_TYPE kLargerDumpType = static_cast<MINIDUMP_TYPE>( |
86 MiniDumpWithProcessThreadData | // Get PEB and TEB. | 92 MiniDumpWithProcessThreadData | // Get PEB and TEB. |
87 MiniDumpWithUnloadedModules | // Get unloaded modules when available. | 93 MiniDumpWithUnloadedModules | // Get unloaded modules when available. |
88 MiniDumpWithIndirectlyReferencedMemory); // Get memory referenced by stack. | 94 MiniDumpWithIndirectlyReferencedMemory); // Get memory referenced by stack. |
89 | 95 |
90 namespace { | 96 namespace { |
91 | 97 |
98 // Overwrite an existing DisplayVersion as written by the MSI installer | |
99 // with the real version number of Chrome. | |
100 LONG OverwriteDisplayVersion(const base::string16& path, | |
101 const base::string16& value) { | |
102 base::win::RegKey key; | |
103 LONG result = 0; | |
104 base::string16 existing; | |
105 if ((result = key.Open(HKEY_LOCAL_MACHINE, path.c_str(), | |
106 KEY_QUERY_VALUE | KEY_SET_VALUE | KEY_WOW64_64KEY)) | |
107 != ERROR_SUCCESS) { | |
108 LOG(ERROR) << "Failed to set DisplayVersion: " << path << " not found"; | |
109 return result; | |
110 } | |
111 if ((result = key.ReadValue(kDisplayVersion, &existing)) != ERROR_SUCCESS) { | |
112 LOG(ERROR) << "Failed to set DisplayVersion: " << kDisplayVersion | |
113 << " not found under " << path; | |
114 return result; | |
115 } | |
116 if ((result = key.WriteValue(kDisplayVersion, value.c_str())) | |
117 != ERROR_SUCCESS) { | |
118 LOG(ERROR) << "Failed to set DisplayVersion: " << kDisplayVersion | |
119 << " could not be written under " << path; | |
120 return result; | |
121 } | |
122 VLOG(1) << "Set DisplayVersion at " << path << " to " << value | |
123 << " from " << existing; | |
124 return ERROR_SUCCESS; | |
125 } | |
126 | |
127 void DelayedOverwriteDisplayVersion(const base::FilePath& setup_exe, | |
128 const std::string& id, | |
129 const Version& version) { | |
130 base::string16 reg_path(kMsiInstallRegistryPrefix); | |
131 reg_path += base::UTF8ToUTF16(id); | |
132 reg_path += kMsiInstallRegistryPostfix; | |
133 | |
134 // This process has to be able to exit so we launch ourselves with | |
135 // instructions on what to do and then return. | |
136 base::CommandLine command_line(setup_exe); | |
137 command_line.AppendSwitchNative(installer::switches::kSetDisplayVersionPath, | |
138 reg_path); | |
139 command_line.AppendSwitchNative(installer::switches::kSetDisplayVersionValue, | |
140 base::UTF8ToUTF16(version.GetString())); | |
grt (UTC plus 2)
2015/09/02 20:43:55
nit: base::ASCIIToUTF16 here since we're certain t
bcwhite
2015/09/09 18:20:22
Done.
| |
141 command_line.AppendSwitchNative(installer::switches::kDelay, | |
142 kMsiDisplayVersionOverwriteDelay); | |
143 | |
144 STARTUPINFOW si = {sizeof(si)}; | |
145 PROCESS_INFORMATION pi = {0}; | |
146 if (!::CreateProcess(setup_exe.value().c_str(), | |
147 &command_line.GetCommandLineString()[0], | |
148 NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, | |
149 &si, &pi)) { | |
150 LOG(ERROR) << "Failed to set DisplayVersion: " | |
151 << "could not launch subprocess to make desired changes." | |
152 << " (error=" << ::GetLastError() << ")\n" | |
153 << command_line.GetCommandLineString(); | |
154 return; | |
155 } | |
156 ::CloseHandle(pi.hThread); | |
157 } | |
158 | |
92 // Returns NULL if no compressed archive is available for processing, otherwise | 159 // Returns NULL if no compressed archive is available for processing, otherwise |
93 // returns a patch helper configured to uncompress and patch. | 160 // returns a patch helper configured to uncompress and patch. |
94 scoped_ptr<installer::ArchivePatchHelper> CreateChromeArchiveHelper( | 161 scoped_ptr<installer::ArchivePatchHelper> CreateChromeArchiveHelper( |
95 const base::FilePath& setup_exe, | 162 const base::FilePath& setup_exe, |
96 const base::CommandLine& command_line, | 163 const base::CommandLine& command_line, |
97 const installer::InstallerState& installer_state, | 164 const installer::InstallerState& installer_state, |
98 const base::FilePath& working_directory) { | 165 const base::FilePath& working_directory) { |
99 // A compressed archive is ordinarily given on the command line by the mini | 166 // A compressed archive is ordinarily given on the command line by the mini |
100 // installer. If one was not given, look for chrome.packed.7z next to the | 167 // installer. If one was not given, look for chrome.packed.7z next to the |
101 // running program. | 168 // running program. |
(...skipping 810 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
912 | 979 |
913 // This method processes any command line options that make setup.exe do | 980 // This method processes any command line options that make setup.exe do |
914 // various tasks other than installation (renaming chrome.exe, showing eula | 981 // various tasks other than installation (renaming chrome.exe, showing eula |
915 // among others). This function returns true if any such command line option | 982 // among others). This function returns true if any such command line option |
916 // has been found and processed (so setup.exe should exit at that point). | 983 // has been found and processed (so setup.exe should exit at that point). |
917 bool HandleNonInstallCmdLineOptions(const InstallationState& original_state, | 984 bool HandleNonInstallCmdLineOptions(const InstallationState& original_state, |
918 const base::FilePath& setup_exe, | 985 const base::FilePath& setup_exe, |
919 const base::CommandLine& cmd_line, | 986 const base::CommandLine& cmd_line, |
920 InstallerState* installer_state, | 987 InstallerState* installer_state, |
921 int* exit_code) { | 988 int* exit_code) { |
989 // This option is independent of all others so doesn't belong in the if/else | |
990 // block below. | |
991 if (cmd_line.HasSwitch(installer::switches::kDelay)) { | |
992 const std::string delay_seconds_string( | |
993 cmd_line.GetSwitchValueASCII(installer::switches::kDelay)); | |
994 int delay_seconds; | |
995 if (base::StringToInt(delay_seconds_string, &delay_seconds) && | |
996 delay_seconds > 0) { | |
997 ::Sleep(delay_seconds * 1000); | |
grt (UTC plus 2)
2015/09/02 20:43:55
if sleeping is really the only way to do this (as
bcwhite
2015/09/09 18:20:23
Done.
I think the best way is to have the process
| |
998 } | |
999 } | |
1000 | |
922 // TODO(gab): Add a local |status| variable which each block below sets; | 1001 // TODO(gab): Add a local |status| variable which each block below sets; |
923 // only determine the |exit_code| from |status| at the end (this will allow | 1002 // only determine the |exit_code| from |status| at the end (this will allow |
924 // this method to validate that | 1003 // this method to validate that |
925 // (!handled || status != installer::UNKNOWN_STATUS)). | 1004 // (!handled || status != installer::UNKNOWN_STATUS)). |
926 bool handled = true; | 1005 bool handled = true; |
927 // TODO(tommi): Split these checks up into functions and use a data driven | 1006 // TODO(tommi): Split these checks up into functions and use a data driven |
928 // map of switch->function. | 1007 // map of switch->function. |
929 if (cmd_line.HasSwitch(installer::switches::kUpdateSetupExe)) { | 1008 if (cmd_line.HasSwitch(installer::switches::kUpdateSetupExe)) { |
930 installer::InstallStatus status = installer::SETUP_PATCH_FAILED; | 1009 installer::InstallStatus status = installer::SETUP_PATCH_FAILED; |
931 // If --update-setup-exe command line option is given, we apply the given | 1010 // 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... | |
1155 patch_file, | 1234 patch_file, |
1156 output_file); | 1235 output_file); |
1157 } else { | 1236 } else { |
1158 *exit_code = installer::PATCH_INVALID_ARGUMENTS; | 1237 *exit_code = installer::PATCH_INVALID_ARGUMENTS; |
1159 } | 1238 } |
1160 } else if (cmd_line.HasSwitch(installer::switches::kReenableAutoupdates)) { | 1239 } else if (cmd_line.HasSwitch(installer::switches::kReenableAutoupdates)) { |
1161 // 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. |
1162 bool updates_enabled = GoogleUpdateSettings::ReenableAutoupdates(); | 1241 bool updates_enabled = GoogleUpdateSettings::ReenableAutoupdates(); |
1163 *exit_code = updates_enabled ? installer::REENABLE_UPDATES_SUCCEEDED : | 1242 *exit_code = updates_enabled ? installer::REENABLE_UPDATES_SUCCEEDED : |
1164 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( | |
1249 cmd_line.GetSwitchValueNative( | |
1250 installer::switches::kSetDisplayVersionValue)); | |
1251 *exit_code = OverwriteDisplayVersion(registry_path, registry_value); | |
1165 } else { | 1252 } else { |
1166 handled = false; | 1253 handled = false; |
1167 } | 1254 } |
1168 | 1255 |
1169 return handled; | 1256 return handled; |
1170 } | 1257 } |
1171 | 1258 |
1172 // 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 |
1173 // passed in. This information is used for crash reporting. | 1260 // passed in. This information is used for crash reporting. |
1174 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... | |
1539 .Append(setup_path.BaseName()); | 1626 .Append(setup_path.BaseName()); |
1540 } | 1627 } |
1541 const Products& products = installer_state.products(); | 1628 const Products& products = installer_state.products(); |
1542 for (Products::const_iterator it = products.begin(); it < products.end(); | 1629 for (Products::const_iterator it = products.begin(); it < products.end(); |
1543 ++it) { | 1630 ++it) { |
1544 const Product& product = **it; | 1631 const Product& product = **it; |
1545 product.LaunchUserExperiment(setup_path, install_status, system_install); | 1632 product.LaunchUserExperiment(setup_path, install_status, system_install); |
1546 } | 1633 } |
1547 } | 1634 } |
1548 | 1635 |
1549 // If installation completed successfully, return the path to the directory | 1636 // If the installation completed successfully... |
1550 // containing the newly installed setup.exe and uncompressed archive if the | 1637 if (InstallUtil::GetInstallReturnCode(install_status) == 0) { |
1551 // caller requested it. | 1638 // Update the DisplayVersion created by an MSI-based install. |
1552 if (installer_directory && | 1639 std::string install_id; |
grt (UTC plus 2)
2015/09/02 20:43:55
nit: move install_id and new_setup into the body o
bcwhite
2015/09/09 18:20:22
install_id is used by the "if" statement but I've
| |
1553 InstallUtil::GetInstallReturnCode(install_status) == 0) { | 1640 base::FilePath new_setup = |
1554 *installer_directory = | 1641 installer_state.GetInstallerDirectory(*installer_version); |
grt (UTC plus 2)
2015/09/02 20:43:55
four-space indent
bcwhite
2015/09/09 18:20:22
Done.
| |
1555 installer_state.GetInstallerDirectory(*installer_version); | 1642 new_setup.Append(kSetupExe); |
grt (UTC plus 2)
2015/09/02 20:43:55
either "new_setup = new_setup.Append(kSetupExe);",
bcwhite
2015/09/09 18:20:22
Done.
| |
1643 if (prefs.GetString(installer::master_preferences::kMsiProductId, | |
1644 &install_id)) { | |
1645 DelayedOverwriteDisplayVersion(new_setup, install_id, *installer_version); | |
1646 } | |
1647 // Return the path to the directory containing the newly installed | |
1648 // setup.exe and uncompressed archive if the caller requested it. | |
1649 if (installer_directory) | |
grt (UTC plus 2)
2015/09/02 20:43:55
nit: braces for multi-line body
bcwhite
2015/09/09 18:20:23
Done.
| |
1650 *installer_directory = | |
1651 installer_state.GetInstallerDirectory(*installer_version); | |
1556 } | 1652 } |
1557 | 1653 |
1558 // temp_path's dtor will take care of deleting or scheduling itself for | 1654 // temp_path's dtor will take care of deleting or scheduling itself for |
1559 // deletion at reboot when this scope closes. | 1655 // deletion at reboot when this scope closes. |
1560 VLOG(1) << "Deleting temporary directory " << temp_path.path().value(); | 1656 VLOG(1) << "Deleting temporary directory " << temp_path.path().value(); |
1561 | 1657 |
1562 return install_status; | 1658 return install_status; |
1563 } | 1659 } |
1564 | 1660 |
1565 } // namespace installer | 1661 } // namespace installer |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1710 // Note that we allow the status installer::UNINSTALL_REQUIRES_REBOOT | 1806 // Note that we allow the status installer::UNINSTALL_REQUIRES_REBOOT |
1711 // to pass through, since this is only returned on uninstall which is | 1807 // to pass through, since this is only returned on uninstall which is |
1712 // never invoked directly by Google Update. | 1808 // never invoked directly by Google Update. |
1713 return_code = InstallUtil::GetInstallReturnCode(install_status); | 1809 return_code = InstallUtil::GetInstallReturnCode(install_status); |
1714 } | 1810 } |
1715 | 1811 |
1716 VLOG(1) << "Installation complete, returning: " << return_code; | 1812 VLOG(1) << "Installation complete, returning: " << return_code; |
1717 | 1813 |
1718 return return_code; | 1814 return return_code; |
1719 } | 1815 } |
OLD | NEW |