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. |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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" |
OLD | NEW |