Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(37)

Side by Side Diff: chrome/installer/mini_installer/mini_installer.cc

Issue 2507293005: Force migrate all clients from multi-install back to single-install. (Closed)
Patch Set: mini_installer too Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 // mini_installer.exe is the first exe that is run when chrome is being 5 // mini_installer.exe is the first exe that is run when chrome is being
6 // installed or upgraded. It is designed to be extremely small (~5KB with no 6 // installed or upgraded. It is designed to be extremely small (~5KB with no
7 // extra resources linked) and it has two main jobs: 7 // extra resources linked) and it has two main jobs:
8 // 1) unpack the resources (possibly decompressing some) 8 // 1) unpack the resources (possibly decompressing some)
9 // 2) run the real installer (setup.exe) with appropriate flags. 9 // 2) run the real installer (setup.exe) with appropriate flags.
10 // 10 //
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
67 // of resource callbacks. 67 // of resource callbacks.
68 struct Context { 68 struct Context {
69 // Input to the call back method. Specifies the dir to save resources. 69 // Input to the call back method. Specifies the dir to save resources.
70 const wchar_t* base_path; 70 const wchar_t* base_path;
71 // First output from call back method. Full path of Chrome archive. 71 // First output from call back method. Full path of Chrome archive.
72 PathString* chrome_resource_path; 72 PathString* chrome_resource_path;
73 // Second output from call back method. Full path of Setup archive/exe. 73 // Second output from call back method. Full path of Setup archive/exe.
74 PathString* setup_resource_path; 74 PathString* setup_resource_path;
75 }; 75 };
76 76
77 77 #if defined(GOOGLE_CHROME_BUILD)
78 // Opens the Google Update ClientState key for the current install 78 // Opens the Google Update ClientState key. If |binaries| is false, opens the
79 // configuration. This includes locating the correct key in the face of 79 // key for Google Chrome or Chrome SxS (canary). If |binaries| is true and an
80 // multi-install. The flag will by default be written to HKCU, but if 80 // existing multi-install Chrome is being updated, opens the key for the
81 // --system-level is included in the command line, it will be written to 81 // binaries; otherwise, returns false.
82 // HKLM instead. 82 bool OpenInstallStateKey(const Configuration& configuration,
83 bool OpenInstallStateKey(const Configuration& configuration, RegKey* key) { 83 bool binaries,
84 RegKey* key) {
85 if (binaries && !configuration.is_updating_multi_chrome())
86 return false;
84 const HKEY root_key = 87 const HKEY root_key =
85 configuration.is_system_level() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; 88 configuration.is_system_level() ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
86 const wchar_t* app_guid = configuration.chrome_app_guid(); 89 const wchar_t* app_guid = binaries ? google_update::kMultiInstallAppGuid
90 : configuration.chrome_app_guid();
87 const REGSAM key_access = KEY_QUERY_VALUE | KEY_SET_VALUE; 91 const REGSAM key_access = KEY_QUERY_VALUE | KEY_SET_VALUE;
88 92
89 return OpenClientStateKey(root_key, app_guid, key_access, key); 93 return OpenClientStateKey(root_key, app_guid, key_access, key) ==
94 ERROR_SUCCESS;
90 } 95 }
91 96
92 // Writes install results into registry where it is read by Google Update. 97 // Writes install results into the registry where it is read by Google Update.
93 // Don't write anything if there is already a result present, likely 98 // Don't write anything if there is already a result present, likely
94 // written by setup.exe. 99 // written by setup.exe.
95 void WriteInstallResults(const Configuration& configuration, 100 void WriteInstallResults(const Configuration& configuration,
96 ProcessExitResult result) { 101 ProcessExitResult result) {
97 #if defined(GOOGLE_CHROME_BUILD)
98 // Calls to setup.exe will write a "success" result if everything was good 102 // Calls to setup.exe will write a "success" result if everything was good
99 // so we don't need to write anything from here. 103 // so we don't need to write anything from here.
100 if (result.IsSuccess()) 104 if (result.IsSuccess())
101 return; 105 return;
102 106
103 RegKey key; 107 // Write the value in Chrome ClientState key and in the binaries' if an
104 DWORD value; 108 // existing multi-install Chrome is being updated.
gab 2016/12/12 21:38:16 Is this because the cleanup is two phase? i.e. fir
grt (UTC plus 2) 2016/12/13 09:20:37 No, it's single phase. This is so that the results
gab 2016/12/14 16:33:38 Aaaah, I see, that's what I hadn't realized : on e
105 if (OpenInstallStateKey(configuration, &key)) { 109 for (int i = 0; i < 2; ++i) {
106 if (key.ReadDWValue(kInstallerResultRegistryValue, &value) 110 RegKey key;
107 != ERROR_SUCCESS || value == 0) { 111 DWORD value;
108 key.WriteDWValue(kInstallerResultRegistryValue, 112 if (OpenInstallStateKey(configuration, i != 0, &key)) {
109 result.exit_code ? 1 /* FAILED_CUSTOM_ERROR */ 113 if (key.ReadDWValue(kInstallerResultRegistryValue, &value) !=
110 : 0 /* SUCCESS */); 114 ERROR_SUCCESS ||
111 key.WriteDWValue(kInstallerErrorRegistryValue, result.exit_code); 115 value == 0) {
112 key.WriteDWValue(kInstallerExtraCode1RegistryValue, result.windows_error); 116 key.WriteDWValue(kInstallerResultRegistryValue,
117 result.exit_code ? 1 /* FAILED_CUSTOM_ERROR */
118 : 0 /* SUCCESS */);
119 key.WriteDWValue(kInstallerErrorRegistryValue, result.exit_code);
120 key.WriteDWValue(kInstallerExtraCode1RegistryValue,
121 result.windows_error);
122 }
113 } 123 }
114 key.Close();
115 } 124 }
116 #endif
117 } 125 }
118 126
119 // This function sets the flag in registry to indicate that Google Update 127 // This function sets the flag in registry to indicate that Google Update
120 // should try full installer next time. If the current installer works, this 128 // should try full installer next time. If the current installer works, this
121 // flag is cleared by setup.exe at the end of install. 129 // flag is cleared by setup.exe at the end of install.
122 void SetInstallerFlags(const Configuration& configuration) { 130 void SetInstallerFlags(const Configuration& configuration) {
123 RegKey key;
124 StackString<128> value; 131 StackString<128> value;
125 LONG ret = ERROR_SUCCESS;
126 132
127 if (!OpenInstallStateKey(configuration, &key)) 133 for (int i = 0; i < 2; ++i) {
128 return; 134 RegKey key;
135 if (!OpenInstallStateKey(configuration, i != 0, &key))
136 continue;
129 137
130 ret = key.ReadSZValue(kApRegistryValue, value.get(), value.capacity()); 138 LONG ret = key.ReadSZValue(kApRegistryValue, value.get(), value.capacity());
131 139
132 // The conditions below are handling two cases: 140 // The conditions below are handling two cases:
133 // 1. When ap value is present, we want to add the required tag only if it is 141 // 1. When ap value is present, we want to add the required tag only if it
134 // not present. 142 // is not present.
135 // 2. When ap value is missing, we are going to create it with the required 143 // 2. When ap value is missing, we are going to create it with the required
136 // tag. 144 // tag.
137 if ((ret == ERROR_SUCCESS) || (ret == ERROR_FILE_NOT_FOUND)) { 145 if ((ret == ERROR_SUCCESS) || (ret == ERROR_FILE_NOT_FOUND)) {
138 if (ret == ERROR_FILE_NOT_FOUND) 146 if (ret == ERROR_FILE_NOT_FOUND)
139 value.clear(); 147 value.clear();
140 148
141 if (!StrEndsWith(value.get(), kFullInstallerSuffix) && 149 if (!StrEndsWith(value.get(), kFullInstallerSuffix) &&
142 value.append(kFullInstallerSuffix)) { 150 value.append(kFullInstallerSuffix)) {
143 key.WriteSZValue(kApRegistryValue, value.get()); 151 key.WriteSZValue(kApRegistryValue, value.get());
152 }
144 } 153 }
145 } 154 }
146 } 155 }
156 #endif // GOOGLE_CHROME_BUILD
147 157
148 // Gets the setup.exe path from Registry by looking at the value of Uninstall 158 // Gets the setup.exe path from Registry by looking at the value of Uninstall
149 // string. |size| is measured in wchar_t units. 159 // string. |size| is measured in wchar_t units.
150 ProcessExitResult GetSetupExePathForAppGuid(bool system_level, 160 ProcessExitResult GetSetupExePathForAppGuid(bool system_level,
151 const wchar_t* app_guid, 161 const wchar_t* app_guid,
152 const wchar_t* previous_version, 162 const wchar_t* previous_version,
153 wchar_t* path, 163 wchar_t* path,
154 size_t size) { 164 size_t size) {
155 const HKEY root_key = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; 165 const HKEY root_key = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
156 RegKey key; 166 RegKey key;
157 if (!OpenClientStateKey(root_key, app_guid, KEY_QUERY_VALUE, &key)) 167 LONG result = OpenClientStateKey(root_key, app_guid, KEY_QUERY_VALUE, &key);
158 return ProcessExitResult(UNABLE_TO_FIND_REGISTRY_KEY); 168 if (result == ERROR_SUCCESS)
159 DWORD result = key.ReadSZValue(kUninstallRegistryValue, path, size); 169 result = key.ReadSZValue(kUninstallRegistryValue, path, size);
160 if (result != ERROR_SUCCESS) 170 if (result != ERROR_SUCCESS)
161 return ProcessExitResult(UNABLE_TO_FIND_REGISTRY_KEY, result); 171 return ProcessExitResult(UNABLE_TO_FIND_REGISTRY_KEY, result);
162 172
163 // Check that the path to the existing installer includes the expected 173 // Check that the path to the existing installer includes the expected
164 // version number. It's not necessary for accuracy to verify before/after 174 // version number. It's not necessary for accuracy to verify before/after
165 // delimiters. 175 // delimiters.
166 if (!SearchStringI(path, previous_version)) 176 if (!SearchStringI(path, previous_version))
167 return ProcessExitResult(PATCH_NOT_FOR_INSTALLED_VERSION); 177 return ProcessExitResult(PATCH_NOT_FOR_INSTALLED_VERSION);
168 178
169 return ProcessExitResult(SUCCESS_EXIT_CODE); 179 return ProcessExitResult(SUCCESS_EXIT_CODE);
170 } 180 }
171 181
172 // Gets the path to setup.exe of the previous version. The overall path is found 182 // Gets the path to setup.exe of the previous version. The overall path is found
173 // in the Uninstall string in the registry. A previous version number specified 183 // in the Uninstall string in the registry. A previous version number specified
174 // in |configuration| is used if available. |size| is measured in wchar_t units. 184 // in |configuration| is used if available. |size| is measured in wchar_t units.
175 ProcessExitResult GetPreviousSetupExePath(const Configuration& configuration, 185 ProcessExitResult GetPreviousSetupExePath(const Configuration& configuration,
176 wchar_t* path, 186 wchar_t* path,
177 size_t size) { 187 size_t size) {
178 bool system_level = configuration.is_system_level(); 188 bool system_level = configuration.is_system_level();
179 const wchar_t* previous_version = configuration.previous_version(); 189 const wchar_t* previous_version = configuration.previous_version();
180 ProcessExitResult exit_code = ProcessExitResult(GENERIC_ERROR); 190 ProcessExitResult exit_code = ProcessExitResult(GENERIC_ERROR);
181 191
182 // If this is a multi install, first try looking in the binaries for the path. 192 // Check Chrome's ClientState key for the path to setup.exe. This will have
183 if (configuration.is_multi_install()) { 193 // the correct path for all well-functioning installs.
184 exit_code = GetSetupExePathForAppGuid( 194 exit_code =
185 system_level, google_update::kMultiInstallAppGuid, previous_version, 195 GetSetupExePathForAppGuid(system_level, configuration.chrome_app_guid(),
186 path, size); 196 previous_version, path, size);
187 }
188 197
189 // Make a last-ditch effort to look in the Chrome client state key. 198 // Failing that, check the binaries if updating multi-install Chrome.
190 if (!exit_code.IsSuccess()) { 199 if (!exit_code.IsSuccess() && configuration.is_updating_multi_chrome()) {
191 exit_code = GetSetupExePathForAppGuid( 200 exit_code = GetSetupExePathForAppGuid(system_level,
192 system_level, configuration.chrome_app_guid(), previous_version, 201 google_update::kMultiInstallAppGuid,
193 path, size); 202 previous_version, path, size);
194 } 203 }
195 204
196 return exit_code; 205 return exit_code;
197 } 206 }
198 207
199 // Calls CreateProcess with good default parameters and waits for the process to 208 // Calls CreateProcess with good default parameters and waits for the process to
200 // terminate returning the process exit code. |exit_code|, if non-NULL, is 209 // terminate returning the process exit code. |exit_code|, if non-NULL, is
201 // populated with the process exit code. 210 // populated with the process exit code.
202 ProcessExitResult RunProcessAndWait(const wchar_t* exe_path, wchar_t* cmdline) { 211 ProcessExitResult RunProcessAndWait(const wchar_t* exe_path, wchar_t* cmdline) {
203 STARTUPINFOW si = {sizeof(si)}; 212 STARTUPINFOW si = {sizeof(si)};
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after
444 return ProcessExitResult(UNABLE_TO_EXTRACT_SETUP, ::GetLastError()); 453 return ProcessExitResult(UNABLE_TO_EXTRACT_SETUP, ::GetLastError());
445 } 454 }
446 } 455 }
447 #endif 456 #endif
448 457
449 return exit_code; 458 return exit_code;
450 } 459 }
451 460
452 // Executes setup.exe, waits for it to finish and returns the exit code. 461 // Executes setup.exe, waits for it to finish and returns the exit code.
453 ProcessExitResult RunSetup(const Configuration& configuration, 462 ProcessExitResult RunSetup(const Configuration& configuration,
454 const wchar_t* archive_path, 463 const wchar_t* archive_path,
455 const wchar_t* setup_path) { 464 const wchar_t* setup_path) {
456 // There could be three full paths in the command line for setup.exe (path 465 // There could be three full paths in the command line for setup.exe (path
457 // to exe itself, path to archive and path to log file), so we declare 466 // to exe itself, path to archive and path to log file), so we declare
458 // total size as three + one additional to hold command line options. 467 // total size as three + one additional to hold command line options.
459 CommandString cmd_line; 468 CommandString cmd_line;
460 469
461 // Get the path to setup.exe first. 470 // Get the path to setup.exe first.
462 if (::lstrlen(setup_path) > 0) { 471 if (::lstrlen(setup_path) > 0) {
463 if (!cmd_line.assign(L"\"") || 472 if (!cmd_line.assign(L"\"") ||
464 !cmd_line.append(setup_path) || 473 !cmd_line.append(setup_path) ||
465 !cmd_line.append(L"\"")) 474 !cmd_line.append(L"\""))
(...skipping 375 matching lines...) Expand 10 before | Expand all | Expand 10 after
841 return exit_code; 850 return exit_code;
842 851
843 // First get a path where we can extract payload 852 // First get a path where we can extract payload
844 PathString base_path; 853 PathString base_path;
845 if (!GetWorkDir(module, &base_path, &exit_code)) 854 if (!GetWorkDir(module, &base_path, &exit_code))
846 return exit_code; 855 return exit_code;
847 856
848 #if defined(GOOGLE_CHROME_BUILD) 857 #if defined(GOOGLE_CHROME_BUILD)
849 // Set the magic suffix in registry to try full installer next time. We ignore 858 // Set the magic suffix in registry to try full installer next time. We ignore
850 // any errors here and we try to set the suffix for user level unless 859 // any errors here and we try to set the suffix for user level unless
851 // --system-level is on the command line in which case we set it for system 860 // GoogleUpdateIsMachine=1 is present in the environment or --system-level is
852 // level instead. This only applies to the Google Chrome distribution. 861 // on the command line in which case we set it for system level instead. This
862 // only applies to the Google Chrome distribution.
853 SetInstallerFlags(configuration); 863 SetInstallerFlags(configuration);
854 #endif 864 #endif
855 865
856 PathString archive_path; 866 PathString archive_path;
857 PathString setup_path; 867 PathString setup_path;
858 exit_code = UnpackBinaryResources(configuration, module, base_path.get(), 868 exit_code = UnpackBinaryResources(configuration, module, base_path.get(),
859 &archive_path, &setup_path); 869 &archive_path, &setup_path);
860 870
861 // While unpacking the binaries, we paged in a whole bunch of memory that 871 // While unpacking the binaries, we paged in a whole bunch of memory that
862 // we don't need anymore. Let's give it back to the pool before running 872 // we don't need anymore. Let's give it back to the pool before running
863 // setup. 873 // setup.
864 ::SetProcessWorkingSetSize(::GetCurrentProcess(), (SIZE_T)-1, (SIZE_T)-1); 874 ::SetProcessWorkingSetSize(::GetCurrentProcess(), (SIZE_T)-1, (SIZE_T)-1);
865 875
866 if (exit_code.IsSuccess()) 876 if (exit_code.IsSuccess())
867 exit_code = RunSetup(configuration, archive_path.get(), setup_path.get()); 877 exit_code = RunSetup(configuration, archive_path.get(), setup_path.get());
868 878
869 if (ShouldDeleteExtractedFiles()) 879 if (ShouldDeleteExtractedFiles())
870 DeleteExtractedFiles(base_path.get(), archive_path.get(), setup_path.get()); 880 DeleteExtractedFiles(base_path.get(), archive_path.get(), setup_path.get());
871 881
882 #if defined(GOOGLE_CHROME_BUILD)
872 WriteInstallResults(configuration, exit_code); 883 WriteInstallResults(configuration, exit_code);
884 #endif
885
873 return exit_code; 886 return exit_code;
874 } 887 }
875 888
876 } // namespace mini_installer 889 } // namespace mini_installer
877 890
878 int MainEntryPoint() { 891 int MainEntryPoint() {
879 mini_installer::ProcessExitResult result = 892 mini_installer::ProcessExitResult result =
880 mini_installer::WMain(::GetModuleHandle(NULL)); 893 mini_installer::WMain(::GetModuleHandle(NULL));
881 894
882 ::ExitProcess(result.exit_code); 895 ::ExitProcess(result.exit_code);
(...skipping 12 matching lines...) Expand all
895 #pragma function(memset) 908 #pragma function(memset)
896 void* memset(void* dest, int c, size_t count) { 909 void* memset(void* dest, int c, size_t count) {
897 void* start = dest; 910 void* start = dest;
898 while (count--) { 911 while (count--) {
899 *reinterpret_cast<char*>(dest) = static_cast<char>(c); 912 *reinterpret_cast<char*>(dest) = static_cast<char>(c);
900 dest = reinterpret_cast<char*>(dest) + 1; 913 dest = reinterpret_cast<char*>(dest) + 1;
901 } 914 }
902 return start; 915 return start;
903 } 916 }
904 } // extern "C" 917 } // extern "C"
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698