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 // 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 |