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 // 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 Loading... | |
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. |
huangs
2017/01/31 17:40:04
NIT: "opens the key for the binaries" at end: Mayb
grt (UTC plus 2)
2017/02/02 08:17:16
Done.
| |
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, |
huangs
2017/01/31 17:40:04
NIT: Rename to WriteInstallResultsToGoogleUpdate()
grt (UTC plus 2)
2017/02/02 08:17:16
I've added a TODO above the #if above for where I
| |
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. |
105 if (OpenInstallStateKey(configuration, &key)) { | 109 for (int i = 0; i < 2; ++i) { |
huangs
2017/01/31 17:40:04
NIT: Maybe be move explicit?
for (bool binaries
grt (UTC plus 2)
2017/02/02 08:17:16
Awesome. I wasn't sure this was permitted by the s
| |
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) { |
huangs
2017/01/31 17:40:04
NIT: Same as above.
| |
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 // Failing that, look in Chrome Frame's client state key if --chrome-frame was | 198 // Failing that, check the binaries if updating multi-install Chrome. |
190 // specified. | 199 if (!exit_code.IsSuccess() && configuration.is_updating_multi_chrome()) { |
191 if (!exit_code.IsSuccess() && configuration.has_chrome_frame()) { | 200 exit_code = GetSetupExePathForAppGuid(system_level, |
192 exit_code = GetSetupExePathForAppGuid( | 201 google_update::kMultiInstallAppGuid, |
193 system_level, google_update::kChromeFrameAppGuid, previous_version, | 202 previous_version, path, size); |
194 path, size); | |
195 } | |
196 | |
197 // Make a last-ditch effort to look in the Chrome client state key. | |
198 if (!exit_code.IsSuccess()) { | |
199 exit_code = GetSetupExePathForAppGuid( | |
200 system_level, configuration.chrome_app_guid(), previous_version, | |
201 path, size); | |
202 } | 203 } |
203 | 204 |
204 return exit_code; | 205 return exit_code; |
205 } | 206 } |
206 | 207 |
207 // 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 |
208 // 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 |
209 // populated with the process exit code. | 210 // populated with the process exit code. |
210 ProcessExitResult RunProcessAndWait(const wchar_t* exe_path, wchar_t* cmdline) { | 211 ProcessExitResult RunProcessAndWait(const wchar_t* exe_path, wchar_t* cmdline) { |
211 STARTUPINFOW si = {sizeof(si)}; | 212 STARTUPINFOW si = {sizeof(si)}; |
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
454 return ProcessExitResult(UNABLE_TO_EXTRACT_SETUP, ::GetLastError()); | 455 return ProcessExitResult(UNABLE_TO_EXTRACT_SETUP, ::GetLastError()); |
455 } | 456 } |
456 } | 457 } |
457 #endif | 458 #endif |
458 | 459 |
459 return exit_code; | 460 return exit_code; |
460 } | 461 } |
461 | 462 |
462 // Executes setup.exe, waits for it to finish and returns the exit code. | 463 // Executes setup.exe, waits for it to finish and returns the exit code. |
463 ProcessExitResult RunSetup(const Configuration& configuration, | 464 ProcessExitResult RunSetup(const Configuration& configuration, |
464 const wchar_t* archive_path, | 465 const wchar_t* archive_path, |
465 const wchar_t* setup_path) { | 466 const wchar_t* setup_path) { |
466 // There could be three full paths in the command line for setup.exe (path | 467 // There could be three full paths in the command line for setup.exe (path |
467 // to exe itself, path to archive and path to log file), so we declare | 468 // to exe itself, path to archive and path to log file), so we declare |
468 // total size as three + one additional to hold command line options. | 469 // total size as three + one additional to hold command line options. |
469 CommandString cmd_line; | 470 CommandString cmd_line; |
470 | 471 |
471 // Get the path to setup.exe first. | 472 // Get the path to setup.exe first. |
472 if (::lstrlen(setup_path) > 0) { | 473 if (::lstrlen(setup_path) > 0) { |
473 if (!cmd_line.assign(L"\"") || | 474 if (!cmd_line.assign(L"\"") || |
474 !cmd_line.append(setup_path) || | 475 !cmd_line.append(setup_path) || |
475 !cmd_line.append(L"\"")) | 476 !cmd_line.append(L"\"")) |
(...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
846 return exit_code; | 847 return exit_code; |
847 | 848 |
848 // First get a path where we can extract payload | 849 // First get a path where we can extract payload |
849 PathString base_path; | 850 PathString base_path; |
850 if (!GetWorkDir(module, &base_path, &exit_code)) | 851 if (!GetWorkDir(module, &base_path, &exit_code)) |
851 return exit_code; | 852 return exit_code; |
852 | 853 |
853 #if defined(GOOGLE_CHROME_BUILD) | 854 #if defined(GOOGLE_CHROME_BUILD) |
854 // Set the magic suffix in registry to try full installer next time. We ignore | 855 // Set the magic suffix in registry to try full installer next time. We ignore |
855 // any errors here and we try to set the suffix for user level unless | 856 // any errors here and we try to set the suffix for user level unless |
856 // --system-level is on the command line in which case we set it for system | 857 // GoogleUpdateIsMachine=1 is present in the environment or --system-level is |
857 // level instead. This only applies to the Google Chrome distribution. | 858 // on the command line in which case we set it for system level instead. This |
859 // only applies to the Google Chrome distribution. | |
858 SetInstallerFlags(configuration); | 860 SetInstallerFlags(configuration); |
859 #endif | 861 #endif |
860 | 862 |
861 PathString archive_path; | 863 PathString archive_path; |
862 PathString setup_path; | 864 PathString setup_path; |
863 exit_code = UnpackBinaryResources(configuration, module, base_path.get(), | 865 exit_code = UnpackBinaryResources(configuration, module, base_path.get(), |
864 &archive_path, &setup_path); | 866 &archive_path, &setup_path); |
865 | 867 |
866 // While unpacking the binaries, we paged in a whole bunch of memory that | 868 // While unpacking the binaries, we paged in a whole bunch of memory that |
867 // we don't need anymore. Let's give it back to the pool before running | 869 // we don't need anymore. Let's give it back to the pool before running |
868 // setup. | 870 // setup. |
869 ::SetProcessWorkingSetSize(::GetCurrentProcess(), (SIZE_T)-1, (SIZE_T)-1); | 871 ::SetProcessWorkingSetSize(::GetCurrentProcess(), (SIZE_T)-1, (SIZE_T)-1); |
870 | 872 |
871 if (exit_code.IsSuccess()) | 873 if (exit_code.IsSuccess()) |
872 exit_code = RunSetup(configuration, archive_path.get(), setup_path.get()); | 874 exit_code = RunSetup(configuration, archive_path.get(), setup_path.get()); |
873 | 875 |
874 if (ShouldDeleteExtractedFiles()) | 876 if (ShouldDeleteExtractedFiles()) |
875 DeleteExtractedFiles(base_path.get(), archive_path.get(), setup_path.get()); | 877 DeleteExtractedFiles(base_path.get(), archive_path.get(), setup_path.get()); |
876 | 878 |
879 #if defined(GOOGLE_CHROME_BUILD) | |
877 WriteInstallResults(configuration, exit_code); | 880 WriteInstallResults(configuration, exit_code); |
881 #endif | |
882 | |
878 return exit_code; | 883 return exit_code; |
879 } | 884 } |
880 | 885 |
881 } // namespace mini_installer | 886 } // namespace mini_installer |
882 | 887 |
883 int MainEntryPoint() { | 888 int MainEntryPoint() { |
884 mini_installer::ProcessExitResult result = | 889 mini_installer::ProcessExitResult result = |
885 mini_installer::WMain(::GetModuleHandle(NULL)); | 890 mini_installer::WMain(::GetModuleHandle(NULL)); |
886 | 891 |
887 ::ExitProcess(result.exit_code); | 892 ::ExitProcess(result.exit_code); |
(...skipping 12 matching lines...) Expand all Loading... | |
900 #pragma function(memset) | 905 #pragma function(memset) |
901 void* memset(void* dest, int c, size_t count) { | 906 void* memset(void* dest, int c, size_t count) { |
902 void* start = dest; | 907 void* start = dest; |
903 while (count--) { | 908 while (count--) { |
904 *reinterpret_cast<char*>(dest) = static_cast<char>(c); | 909 *reinterpret_cast<char*>(dest) = static_cast<char>(c); |
905 dest = reinterpret_cast<char*>(dest) + 1; | 910 dest = reinterpret_cast<char*>(dest) + 1; |
906 } | 911 } |
907 return start; | 912 return start; |
908 } | 913 } |
909 } // extern "C" | 914 } // extern "C" |
OLD | NEW |