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 // |
| 11 // In order to be really small the app doesn't link against the CRT and | 11 // In order to be really small the app doesn't link against the CRT and |
| 12 // defines the following compiler/linker flags: | 12 // defines the following compiler/linker flags: |
| 13 // EnableIntrinsicFunctions="true" compiler: /Oi | 13 // EnableIntrinsicFunctions="true" compiler: /Oi |
| 14 // BasicRuntimeChecks="0" | 14 // BasicRuntimeChecks="0" |
| 15 // BufferSecurityCheck="false" compiler: /GS- | 15 // BufferSecurityCheck="false" compiler: /GS- |
| 16 // EntryPointSymbol="MainEntryPoint" linker: /ENTRY | 16 // EntryPointSymbol="MainEntryPoint" linker: /ENTRY |
| 17 // IgnoreAllDefaultLibraries="true" linker: /NODEFAULTLIB | 17 // IgnoreAllDefaultLibraries="true" linker: /NODEFAULTLIB |
| 18 // OptimizeForWindows98="1" liker: /OPT:NOWIN98 | 18 // OptimizeForWindows98="1" liker: /OPT:NOWIN98 |
| 19 // linker: /SAFESEH:NO | 19 // linker: /SAFESEH:NO |
| 20 | 20 |
| 21 // have the linker merge the sections, saving us ~500 bytes. | 21 // have the linker merge the sections, saving us ~500 bytes. |
| 22 #pragma comment(linker, "/MERGE:.rdata=.text") | 22 #pragma comment(linker, "/MERGE:.rdata=.text") |
| 23 | 23 |
| 24 #include <windows.h> | 24 #include <windows.h> |
| 25 #include <shellapi.h> | 25 #include <shellapi.h> |
| 26 | 26 |
| 27 #include "chrome/installer/mini_installer/appid.h" | 27 #include "chrome/installer/mini_installer/appid.h" |
| 28 #include "chrome/installer/mini_installer/configuration.h" | 28 #include "chrome/installer/mini_installer/configuration.h" |
| 29 #include "chrome/installer/mini_installer/decompress.h" | 29 #include "chrome/installer/mini_installer/decompress.h" |
| 30 #include "chrome/installer/mini_installer/mini_installer.h" | 30 #include "chrome/installer/mini_installer/exit_code.h" |
| 31 #include "chrome/installer/mini_installer/mini_installer_constants.h" | |
| 31 #include "chrome/installer/mini_installer/mini_string.h" | 32 #include "chrome/installer/mini_installer/mini_string.h" |
| 32 #include "chrome/installer/mini_installer/pe_resource.h" | 33 #include "chrome/installer/mini_installer/pe_resource.h" |
| 33 | 34 |
| 34 namespace mini_installer { | 35 namespace mini_installer { |
| 35 | 36 |
| 37 // The type of a process exit code. | |
|
gab
2014/07/07 13:45:01
Remove this comment, the variable name is explicit
grt (UTC plus 2)
2014/07/07 14:24:06
Done.
| |
| 38 typedef DWORD ProcessExitCode; | |
| 36 typedef StackString<MAX_PATH> PathString; | 39 typedef StackString<MAX_PATH> PathString; |
| 37 typedef StackString<MAX_PATH * 4> CommandString; | 40 typedef StackString<MAX_PATH * 4> CommandString; |
| 38 | 41 |
| 39 // This structure passes data back and forth for the processing | 42 // This structure passes data back and forth for the processing |
| 40 // of resource callbacks. | 43 // of resource callbacks. |
| 41 struct Context { | 44 struct Context { |
| 42 // Input to the call back method. Specifies the dir to save resources. | 45 // Input to the call back method. Specifies the dir to save resources. |
| 43 const wchar_t* base_path; | 46 const wchar_t* base_path; |
| 44 // First output from call back method. Full path of Chrome archive. | 47 // First output from call back method. Full path of Chrome archive. |
| 45 PathString* chrome_resource_path; | 48 PathString* chrome_resource_path; |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 136 key.ReadValue(value_name, value, size) == ERROR_SUCCESS) { | 139 key.ReadValue(value_name, value, size) == ERROR_SUCCESS) { |
| 137 return true; | 140 return true; |
| 138 } | 141 } |
| 139 return false; | 142 return false; |
| 140 } | 143 } |
| 141 | 144 |
| 142 // Opens the Google Update ClientState key for a product. | 145 // Opens the Google Update ClientState key for a product. |
| 143 bool OpenClientStateKey(HKEY root_key, const wchar_t* app_guid, REGSAM access, | 146 bool OpenClientStateKey(HKEY root_key, const wchar_t* app_guid, REGSAM access, |
| 144 RegKey* key) { | 147 RegKey* key) { |
| 145 PathString client_state_key; | 148 PathString client_state_key; |
| 146 return client_state_key.assign(kApRegistryKeyBase) && | 149 return client_state_key.assign(kClientStateKeyBase) && |
| 147 client_state_key.append(app_guid) && | 150 client_state_key.append(app_guid) && |
| 148 (key->Open(root_key, | 151 (key->Open(root_key, |
| 149 client_state_key.get(), | 152 client_state_key.get(), |
| 150 access | KEY_WOW64_32KEY) == ERROR_SUCCESS); | 153 access | KEY_WOW64_32KEY) == ERROR_SUCCESS); |
| 151 } | 154 } |
| 152 | 155 |
| 153 // This function sets the flag in registry to indicate that Google Update | 156 // This function sets the flag in registry to indicate that Google Update |
| 154 // should try full installer next time. If the current installer works, this | 157 // should try full installer next time. If the current installer works, this |
| 155 // flag is cleared by setup.exe at the end of install. The flag will by default | 158 // flag is cleared by setup.exe at the end of install. The flag will by default |
| 156 // be written to HKCU, but if --system-level is included in the command line, | 159 // be written to HKCU, but if --system-level is included in the command line, |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 177 // ClientState key in the registry. Only it need be modified. | 180 // ClientState key in the registry. Only it need be modified. |
| 178 // 3. Migrating a single-install into a multi-install. The product will have | 181 // 3. Migrating a single-install into a multi-install. The product will have |
| 179 // a ClientState key in the registry. Only it need be modified. | 182 // a ClientState key in the registry. Only it need be modified. |
| 180 // To handle all cases, we inspect the product's ClientState to see if it | 183 // To handle all cases, we inspect the product's ClientState to see if it |
| 181 // exists and its "ap" value does not contain "-multi". This is case 3, so we | 184 // exists and its "ap" value does not contain "-multi". This is case 3, so we |
| 182 // modify the product's ClientState. Otherwise, we check the | 185 // modify the product's ClientState. Otherwise, we check the |
| 183 // multi-installer's ClientState and modify it if it exists. | 186 // multi-installer's ClientState and modify it if it exists. |
| 184 if (configuration.is_multi_install()) { | 187 if (configuration.is_multi_install()) { |
| 185 if (OpenClientStateKey(root_key, app_guid, key_access, &key)) { | 188 if (OpenClientStateKey(root_key, app_guid, key_access, &key)) { |
| 186 // The product has a client state key. See if it's a single-install. | 189 // The product has a client state key. See if it's a single-install. |
| 187 ret = key.ReadValue(kApRegistryValueName, value.get(), value.capacity()); | 190 ret = key.ReadValue(kApRegistryValue, value.get(), value.capacity()); |
| 188 if (ret != ERROR_FILE_NOT_FOUND && | 191 if (ret != ERROR_FILE_NOT_FOUND && |
| 189 (ret != ERROR_SUCCESS || | 192 (ret != ERROR_SUCCESS || |
| 190 FindTagInStr(value.get(), kMultiInstallTag, NULL))) { | 193 FindTagInStr(value.get(), kMultiInstallTag, NULL))) { |
| 191 // Error or case 2: modify the multi-installer's value. | 194 // Error or case 2: modify the multi-installer's value. |
| 192 key.Close(); | 195 key.Close(); |
| 193 app_guid = google_update::kMultiInstallAppGuid; | 196 app_guid = google_update::kMultiInstallAppGuid; |
| 194 } // else case 3: modify this value. | 197 } // else case 3: modify this value. |
| 195 } else { | 198 } else { |
| 196 // case 1 or 2: modify the multi-installer's value. | 199 // case 1 or 2: modify the multi-installer's value. |
| 197 key.Close(); | 200 key.Close(); |
| 198 app_guid = google_update::kMultiInstallAppGuid; | 201 app_guid = google_update::kMultiInstallAppGuid; |
| 199 } | 202 } |
| 200 } | 203 } |
| 201 | 204 |
| 202 if (!key.is_valid()) { | 205 if (!key.is_valid()) { |
| 203 if (!OpenClientStateKey(root_key, app_guid, key_access, &key)) | 206 if (!OpenClientStateKey(root_key, app_guid, key_access, &key)) |
| 204 return; | 207 return; |
| 205 | 208 |
| 206 value.clear(); | 209 value.clear(); |
| 207 ret = key.ReadValue(kApRegistryValueName, value.get(), value.capacity()); | 210 ret = key.ReadValue(kApRegistryValue, value.get(), value.capacity()); |
| 208 } | 211 } |
| 209 | 212 |
| 210 // The conditions below are handling two cases: | 213 // The conditions below are handling two cases: |
| 211 // 1. When ap value is present, we want to add the required tag only if it is | 214 // 1. When ap value is present, we want to add the required tag only if it is |
| 212 // not present. | 215 // not present. |
| 213 // 2. When ap value is missing, we are going to create it with the required | 216 // 2. When ap value is missing, we are going to create it with the required |
| 214 // tag. | 217 // tag. |
| 215 if ((ret == ERROR_SUCCESS) || (ret == ERROR_FILE_NOT_FOUND)) { | 218 if ((ret == ERROR_SUCCESS) || (ret == ERROR_FILE_NOT_FOUND)) { |
| 216 if (ret == ERROR_FILE_NOT_FOUND) | 219 if (ret == ERROR_FILE_NOT_FOUND) |
| 217 value.clear(); | 220 value.clear(); |
| 218 | 221 |
| 219 if (!StrEndsWith(value.get(), kFullInstallerSuffix) && | 222 if (!StrEndsWith(value.get(), kFullInstallerSuffix) && |
| 220 value.append(kFullInstallerSuffix)) { | 223 value.append(kFullInstallerSuffix)) { |
| 221 key.WriteValue(kApRegistryValueName, value.get()); | 224 key.WriteValue(kApRegistryValue, value.get()); |
| 222 } | 225 } |
| 223 } | 226 } |
| 224 } | 227 } |
| 225 | 228 |
| 226 // Gets the setup.exe path from Registry by looking the value of Uninstall | 229 // Gets the setup.exe path from Registry by looking the value of Uninstall |
| 227 // string. |size| is measured in wchar_t units. | 230 // string. |size| is measured in wchar_t units. |
| 228 bool GetSetupExePathForGuidFromRegistry(bool system_level, | 231 bool GetSetupExePathForGuidFromRegistry(bool system_level, |
| 229 const wchar_t* app_guid, | 232 const wchar_t* app_guid, |
| 230 wchar_t* path, | 233 wchar_t* path, |
| 231 size_t size) { | 234 size_t size) { |
| 232 const HKEY root_key = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; | 235 const HKEY root_key = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; |
| 233 RegKey key; | 236 RegKey key; |
| 234 return OpenClientStateKey(root_key, app_guid, KEY_QUERY_VALUE, &key) && | 237 return OpenClientStateKey(root_key, app_guid, KEY_QUERY_VALUE, &key) && |
| 235 (key.ReadValue(kUninstallRegistryValueName, path, size) == ERROR_SUCCESS); | 238 (key.ReadValue(kUninstallRegistryValue, path, size) == ERROR_SUCCESS); |
| 236 } | 239 } |
| 237 | 240 |
| 238 // Gets the setup.exe path from Registry by looking the value of Uninstall | 241 // Gets the setup.exe path from Registry by looking the value of Uninstall |
| 239 // string. |size| is measured in wchar_t units. | 242 // string. |size| is measured in wchar_t units. |
| 240 bool GetSetupExePathFromRegistry(const Configuration& configuration, | 243 bool GetSetupExePathFromRegistry(const Configuration& configuration, |
| 241 wchar_t* path, | 244 wchar_t* path, |
| 242 size_t size) { | 245 size_t size) { |
| 243 bool system_level = configuration.is_system_level(); | 246 bool system_level = configuration.is_system_level(); |
| 244 | 247 |
| 245 // If this is a multi install, first try looking in the binaries for the path. | 248 // If this is a multi install, first try looking in the binaries for the path. |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 262 return true; | 265 return true; |
| 263 } | 266 } |
| 264 if (configuration.has_app_host() && GetSetupExePathForGuidFromRegistry( | 267 if (configuration.has_app_host() && GetSetupExePathForGuidFromRegistry( |
| 265 system_level, google_update::kChromeAppHostAppGuid, path, size)) { | 268 system_level, google_update::kChromeAppHostAppGuid, path, size)) { |
| 266 return true; | 269 return true; |
| 267 } | 270 } |
| 268 | 271 |
| 269 return false; | 272 return false; |
| 270 } | 273 } |
| 271 | 274 |
| 272 // Calls CreateProcess with good default parameters and waits for the process | 275 // Calls CreateProcess with good default parameters and waits for the process to |
| 273 // to terminate returning the process exit code. | 276 // terminate returning the process exit code. |exit_code|, if non-NULL, is |
| 277 // populated with the process exit code. | |
| 274 bool RunProcessAndWait(const wchar_t* exe_path, wchar_t* cmdline, | 278 bool RunProcessAndWait(const wchar_t* exe_path, wchar_t* cmdline, |
| 275 int* exit_code) { | 279 ProcessExitCode* exit_code) { |
| 276 STARTUPINFOW si = {sizeof(si)}; | 280 STARTUPINFOW si = {sizeof(si)}; |
| 277 PROCESS_INFORMATION pi = {0}; | 281 PROCESS_INFORMATION pi = {0}; |
| 278 if (!::CreateProcess(exe_path, cmdline, NULL, NULL, FALSE, CREATE_NO_WINDOW, | 282 if (!::CreateProcess(exe_path, cmdline, NULL, NULL, FALSE, CREATE_NO_WINDOW, |
| 279 NULL, NULL, &si, &pi)) { | 283 NULL, NULL, &si, &pi)) { |
| 280 return false; | 284 return false; |
| 281 } | 285 } |
| 282 | 286 |
| 283 ::CloseHandle(pi.hThread); | 287 ::CloseHandle(pi.hThread); |
| 284 | 288 |
| 285 bool ret = true; | 289 bool ret = true; |
| 286 DWORD wr = ::WaitForSingleObject(pi.hProcess, INFINITE); | 290 DWORD wr = ::WaitForSingleObject(pi.hProcess, INFINITE); |
| 287 if (WAIT_OBJECT_0 != wr) { | 291 if (WAIT_OBJECT_0 != wr) { |
| 288 ret = false; | 292 ret = false; |
| 289 } else if (exit_code) { | 293 } else if (exit_code) { |
| 290 if (!::GetExitCodeProcess(pi.hProcess, | 294 if (!::GetExitCodeProcess(pi.hProcess, exit_code)) |
| 291 reinterpret_cast<DWORD*>(exit_code))) { | |
| 292 ret = false; | 295 ret = false; |
| 293 } | |
| 294 } | 296 } |
| 295 | 297 |
| 296 ::CloseHandle(pi.hProcess); | 298 ::CloseHandle(pi.hProcess); |
| 297 | 299 |
| 298 return ret; | 300 return ret; |
| 299 } | 301 } |
| 300 | 302 |
| 301 // Append any command line params passed to mini_installer to the given buffer | 303 // Append any command line params passed to mini_installer to the given buffer |
| 302 // so that they can be passed on to setup.exe. We do not return any error from | 304 // so that they can be passed on to setup.exe. We do not return any error from |
| 303 // this method and simply skip making any changes in case of error. | 305 // this method and simply skip making any changes in case of error. |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 345 (resource.Size() > kMaxResourceSize)) { | 347 (resource.Size() > kMaxResourceSize)) { |
| 346 return FALSE; | 348 return FALSE; |
| 347 } | 349 } |
| 348 | 350 |
| 349 PathString full_path; | 351 PathString full_path; |
| 350 if (!full_path.assign(ctx->base_path) || | 352 if (!full_path.assign(ctx->base_path) || |
| 351 !full_path.append(name) || | 353 !full_path.append(name) || |
| 352 !resource.WriteToDisk(full_path.get())) | 354 !resource.WriteToDisk(full_path.get())) |
| 353 return FALSE; | 355 return FALSE; |
| 354 | 356 |
| 355 if (StrStartsWith(name, kChromePrefix)) { | 357 if (StrStartsWith(name, kChromeArchivePrefix)) { |
| 356 if (!ctx->chrome_resource_path->assign(full_path.get())) | 358 if (!ctx->chrome_resource_path->assign(full_path.get())) |
| 357 return FALSE; | 359 return FALSE; |
| 358 } else if (StrStartsWith(name, kSetupPrefix)) { | 360 } else if (StrStartsWith(name, kSetupPrefix)) { |
| 359 if (!ctx->setup_resource_path->assign(full_path.get())) | 361 if (!ctx->setup_resource_path->assign(full_path.get())) |
| 360 return FALSE; | 362 return FALSE; |
| 361 } else { | 363 } else { |
| 362 // Resources should either start with 'chrome' or 'setup'. We don't handle | 364 // Resources should either start with 'chrome' or 'setup'. We don't handle |
| 363 // anything else. | 365 // anything else. |
| 364 return FALSE; | 366 return FALSE; |
| 365 } | 367 } |
| 366 | 368 |
| 367 return TRUE; | 369 return TRUE; |
| 368 } | 370 } |
| 369 | 371 |
| 370 // Finds and writes to disk resources of various types. Returns false | 372 // Finds and writes to disk resources of various types. Returns false |
| 371 // if there is a problem in writing any resource to disk. setup.exe resource | 373 // if there is a problem in writing any resource to disk. setup.exe resource |
| 372 // can come in one of three possible forms: | 374 // can come in one of three possible forms: |
| 373 // - Resource type 'B7', compressed using LZMA (*.7z) | 375 // - Resource type 'B7', compressed using LZMA (*.7z) |
| 374 // - Resource type 'BL', compressed using LZ (*.ex_) | 376 // - Resource type 'BL', compressed using LZ (*.ex_) |
| 375 // - Resource type 'BN', uncompressed (*.exe) | 377 // - Resource type 'BN', uncompressed (*.exe) |
| 376 // If setup.exe is present in more than one form, the precedence order is | 378 // If setup.exe is present in more than one form, the precedence order is |
| 377 // BN < BL < B7 | 379 // BN < BL < B7 |
| 378 // For more details see chrome/tools/build/win/create_installer_archive.py. | 380 // For more details see chrome/tools/build/win/create_installer_archive.py. |
| 379 bool UnpackBinaryResources(const Configuration& configuration, HMODULE module, | 381 bool UnpackBinaryResources(const Configuration& configuration, HMODULE module, |
| 380 const wchar_t* base_path, PathString* archive_path, | 382 const wchar_t* base_path, PathString* archive_path, |
| 381 PathString* setup_path) { | 383 PathString* setup_path) { |
| 382 // Generate the setup.exe path where we patch/uncompress setup resource. | 384 // Generate the setup.exe path where we patch/uncompress setup resource. |
| 383 PathString setup_dest_path; | 385 PathString setup_dest_path; |
| 384 if (!setup_dest_path.assign(base_path) || | 386 if (!setup_dest_path.assign(base_path) || |
| 385 !setup_dest_path.append(kSetupName)) | 387 !setup_dest_path.append(kSetupExe)) |
| 386 return false; | 388 return false; |
| 387 | 389 |
| 388 // Prepare the input to OnResourceFound method that needs a location where | 390 // Prepare the input to OnResourceFound method that needs a location where |
| 389 // it will write all the resources. | 391 // it will write all the resources. |
| 390 Context context = { | 392 Context context = { |
| 391 base_path, | 393 base_path, |
| 392 archive_path, | 394 archive_path, |
| 393 setup_path, | 395 setup_path, |
| 394 }; | 396 }; |
| 395 | 397 |
| 396 // Get the resources of type 'B7' (7zip archive). | 398 // Get the resources of type 'B7' (7zip archive). |
| 397 // We need a chrome archive to do the installation. So if there | 399 // We need a chrome archive to do the installation. So if there |
| 398 // is a problem in fetching B7 resource, just return an error. | 400 // is a problem in fetching B7 resource, just return an error. |
| 399 if (!::EnumResourceNames(module, kLZMAResourceType, OnResourceFound, | 401 if (!::EnumResourceNames(module, kLZMAResourceType, OnResourceFound, |
| 400 reinterpret_cast<LONG_PTR>(&context)) || | 402 reinterpret_cast<LONG_PTR>(&context)) || |
| 401 archive_path->length() == 0) | 403 archive_path->length() == 0) |
| 402 return false; | 404 return false; |
| 403 | 405 |
| 404 // If we found setup 'B7' resource, handle it. | 406 // If we found setup 'B7' resource, handle it. |
| 405 if (setup_path->length() > 0) { | 407 if (setup_path->length() > 0) { |
| 406 CommandString cmd_line; | 408 CommandString cmd_line; |
| 407 // Get the path to setup.exe first. | 409 // Get the path to setup.exe first. |
| 408 bool success = true; | 410 bool success = true; |
| 409 if (!GetSetupExePathFromRegistry(configuration, cmd_line.get(), | 411 if (!GetSetupExePathFromRegistry(configuration, cmd_line.get(), |
| 410 cmd_line.capacity()) || | 412 cmd_line.capacity()) || |
| 413 !cmd_line.append(L" --") || | |
| 411 !cmd_line.append(kCmdUpdateSetupExe) || | 414 !cmd_line.append(kCmdUpdateSetupExe) || |
| 412 !cmd_line.append(L"=\"") || | 415 !cmd_line.append(L"=\"") || |
| 413 !cmd_line.append(setup_path->get()) || | 416 !cmd_line.append(setup_path->get()) || |
| 414 !cmd_line.append(L"\"") || | 417 !cmd_line.append(L"\" --") || |
| 415 !cmd_line.append(kCmdNewSetupExe) || | 418 !cmd_line.append(kCmdNewSetupExe) || |
| 416 !cmd_line.append(L"=\"") || | 419 !cmd_line.append(L"=\"") || |
| 417 !cmd_line.append(setup_dest_path.get()) || | 420 !cmd_line.append(setup_dest_path.get()) || |
| 418 !cmd_line.append(L"\"")) { | 421 !cmd_line.append(L"\"")) { |
|
gab
2014/07/07 13:45:01
Use the CommandLine API to build the command line
grt (UTC plus 2)
2014/07/07 14:24:06
base/ is not available here.
| |
| 419 success = false; | 422 success = false; |
| 420 } | 423 } |
| 421 | 424 |
| 422 // Get any command line option specified for mini_installer and pass them | 425 // Get any command line option specified for mini_installer and pass them |
| 423 // on to setup.exe. This is important since switches such as | 426 // on to setup.exe. This is important since switches such as |
| 424 // --multi-install and --chrome-frame affect where setup.exe will write | 427 // --multi-install and --chrome-frame affect where setup.exe will write |
| 425 // installer results for consumption by Google Update. | 428 // installer results for consumption by Google Update. |
| 426 AppendCommandLineFlags(configuration, &cmd_line); | 429 AppendCommandLineFlags(configuration, &cmd_line); |
| 427 | 430 |
| 428 int exit_code = 0; | 431 ProcessExitCode exit_code = SUCCESS_EXIT_CODE; |
| 429 if (success && | 432 if (success && |
| 430 (!RunProcessAndWait(NULL, cmd_line.get(), &exit_code) || | 433 (!RunProcessAndWait(NULL, cmd_line.get(), &exit_code) || |
| 431 exit_code != ERROR_SUCCESS)) { | 434 exit_code != SUCCESS_EXIT_CODE)) { |
| 432 success = false; | 435 success = false; |
| 433 } | 436 } |
| 434 | 437 |
| 435 if (!success) | 438 if (!success) |
| 436 DeleteFile(setup_path->get()); | 439 DeleteFile(setup_path->get()); |
| 437 | 440 |
| 438 return success && setup_path->assign(setup_dest_path.get()); | 441 return success && setup_path->assign(setup_dest_path.get()); |
| 439 } | 442 } |
| 440 | 443 |
| 441 // setup.exe wasn't sent as 'B7', lets see if it was sent as 'BL' | 444 // setup.exe wasn't sent as 'B7', lets see if it was sent as 'BL' |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 480 ::DeleteFile(setup_dest_path.get()); | 483 ::DeleteFile(setup_dest_path.get()); |
| 481 } | 484 } |
| 482 } | 485 } |
| 483 } | 486 } |
| 484 | 487 |
| 485 return setup_path->length() > 0; | 488 return setup_path->length() > 0; |
| 486 } | 489 } |
| 487 | 490 |
| 488 // Executes setup.exe, waits for it to finish and returns the exit code. | 491 // Executes setup.exe, waits for it to finish and returns the exit code. |
| 489 bool RunSetup(const Configuration& configuration, const wchar_t* archive_path, | 492 bool RunSetup(const Configuration& configuration, const wchar_t* archive_path, |
| 490 const wchar_t* setup_path, int* exit_code) { | 493 const wchar_t* setup_path, ProcessExitCode* exit_code) { |
| 491 // There could be three full paths in the command line for setup.exe (path | 494 // There could be three full paths in the command line for setup.exe (path |
| 492 // to exe itself, path to archive and path to log file), so we declare | 495 // to exe itself, path to archive and path to log file), so we declare |
| 493 // total size as three + one additional to hold command line options. | 496 // total size as three + one additional to hold command line options. |
| 494 CommandString cmd_line; | 497 CommandString cmd_line; |
| 495 | 498 |
| 496 // Get the path to setup.exe first. | 499 // Get the path to setup.exe first. |
| 497 if (::lstrlen(setup_path) > 0) { | 500 if (::lstrlen(setup_path) > 0) { |
| 498 if (!cmd_line.assign(L"\"") || | 501 if (!cmd_line.assign(L"\"") || |
| 499 !cmd_line.append(setup_path) || | 502 !cmd_line.append(setup_path) || |
| 500 !cmd_line.append(L"\"")) | 503 !cmd_line.append(L"\"")) |
| 501 return false; | 504 return false; |
| 502 } else if (!GetSetupExePathFromRegistry(configuration, cmd_line.get(), | 505 } else if (!GetSetupExePathFromRegistry(configuration, cmd_line.get(), |
| 503 cmd_line.capacity())) { | 506 cmd_line.capacity())) { |
| 504 return false; | 507 return false; |
| 505 } | 508 } |
| 506 | 509 |
| 507 // Append the command line param for chrome archive file | 510 // Append the command line param for chrome archive file |
| 508 if (!cmd_line.append(kCmdInstallArchive) || | 511 if (!cmd_line.append(L" --") || |
| 512 !cmd_line.append(kCmdInstallArchive) || | |
| 509 !cmd_line.append(L"=\"") || | 513 !cmd_line.append(L"=\"") || |
| 510 !cmd_line.append(archive_path) || | 514 !cmd_line.append(archive_path) || |
| 511 !cmd_line.append(L"\"")) | 515 !cmd_line.append(L"\"")) |
|
gab
2014/07/07 13:45:01
Use CommandLine API here too.
grt (UTC plus 2)
2014/07/07 14:24:06
same comment
| |
| 512 return false; | 516 return false; |
| 513 | 517 |
| 514 // Get any command line option specified for mini_installer and pass them | 518 // Get any command line option specified for mini_installer and pass them |
| 515 // on to setup.exe | 519 // on to setup.exe |
| 516 AppendCommandLineFlags(configuration, &cmd_line); | 520 AppendCommandLineFlags(configuration, &cmd_line); |
| 517 | 521 |
| 518 return RunProcessAndWait(NULL, cmd_line.get(), exit_code); | 522 return RunProcessAndWait(NULL, cmd_line.get(), exit_code); |
| 519 } | 523 } |
| 520 | 524 |
| 521 // Deletes given files and working dir. | 525 // Deletes given files and working dir. |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 707 for (int i = 0; i < arraysize(kDirectoryPrefixes); ++i) { | 711 for (int i = 0; i < arraysize(kDirectoryPrefixes); ++i) { |
| 708 DeleteDirectoriesWithPrefix(temp.get(), kDirectoryPrefixes[i]); | 712 DeleteDirectoriesWithPrefix(temp.get(), kDirectoryPrefixes[i]); |
| 709 } | 713 } |
| 710 } | 714 } |
| 711 | 715 |
| 712 // Checks the command line for specific mini installer flags. | 716 // Checks the command line for specific mini installer flags. |
| 713 // If the function returns true, the command line has been processed and all | 717 // If the function returns true, the command line has been processed and all |
| 714 // required actions taken. The installer must exit and return the returned | 718 // required actions taken. The installer must exit and return the returned |
| 715 // |exit_code|. | 719 // |exit_code|. |
| 716 bool ProcessNonInstallOperations(const Configuration& configuration, | 720 bool ProcessNonInstallOperations(const Configuration& configuration, |
| 717 int* exit_code) { | 721 ProcessExitCode* exit_code) { |
| 718 bool ret = false; | 722 bool ret = false; |
| 719 | 723 |
| 720 switch (configuration.operation()) { | 724 switch (configuration.operation()) { |
| 721 case Configuration::CLEANUP: | 725 case Configuration::CLEANUP: |
| 722 // Cleanup has already taken place in DeleteOldChromeTempDirectories at | 726 // Cleanup has already taken place in DeleteOldChromeTempDirectories at |
| 723 // this point, so just tell our caller to exit early. | 727 // this point, so just tell our caller to exit early. |
| 724 *exit_code = 0; | 728 *exit_code = SUCCESS_EXIT_CODE; |
| 725 ret = true; | 729 ret = true; |
| 726 break; | 730 break; |
| 727 | 731 |
| 728 default: break; | 732 default: break; |
| 729 } | 733 } |
| 730 | 734 |
| 731 return ret; | 735 return ret; |
| 732 } | 736 } |
| 733 | 737 |
| 734 // Returns true if we should delete the temp files we create (default). | 738 // Returns true if we should delete the temp files we create (default). |
| 735 // Returns false iff the user has manually created a ChromeInstallerCleanup | 739 // Returns false iff the user has manually created a ChromeInstallerCleanup |
| 736 // string value in the registry under HKCU\\Software\\[Google|Chromium] | 740 // string value in the registry under HKCU\\Software\\[Google|Chromium] |
| 737 // and set its value to "0". That explicitly forbids the mini installer from | 741 // and set its value to "0". That explicitly forbids the mini installer from |
| 738 // deleting these files. | 742 // deleting these files. |
| 739 // Support for this has been publicly mentioned in troubleshooting tips so | 743 // Support for this has been publicly mentioned in troubleshooting tips so |
| 740 // we continue to support it. | 744 // we continue to support it. |
| 741 bool ShouldDeleteExtractedFiles() { | 745 bool ShouldDeleteExtractedFiles() { |
| 742 wchar_t value[2] = {0}; | 746 wchar_t value[2] = {0}; |
| 743 if (ReadValueFromRegistry(HKEY_CURRENT_USER, kCleanupRegistryKey, | 747 if (ReadValueFromRegistry(HKEY_CURRENT_USER, kCleanupRegistryKey, |
| 744 kCleanupRegistryValueName, value, | 748 kCleanupRegistryValue, value, arraysize(value)) && |
| 745 arraysize(value)) && | |
| 746 value[0] == L'0') { | 749 value[0] == L'0') { |
| 747 return false; | 750 return false; |
| 748 } | 751 } |
| 749 | 752 |
| 750 return true; | 753 return true; |
| 751 } | 754 } |
| 752 | 755 |
| 753 // Main function. First gets a working dir, unpacks the resources and finally | 756 // Main function. First gets a working dir, unpacks the resources and finally |
| 754 // executes setup.exe to do the install/upgrade. | 757 // executes setup.exe to do the install/upgrade. |
| 755 int WMain(HMODULE module) { | 758 ProcessExitCode WMain(HMODULE module) { |
| 756 #if defined(COMPONENT_BUILD) | 759 #if defined(COMPONENT_BUILD) |
| 757 if (::GetEnvironmentVariable(L"MINI_INSTALLER_TEST", NULL, 0) == 0) { | 760 if (::GetEnvironmentVariable(L"MINI_INSTALLER_TEST", NULL, 0) == 0) { |
| 758 static const wchar_t kComponentBuildIncompatibleMessage[] = | 761 static const wchar_t kComponentBuildIncompatibleMessage[] = |
| 759 L"mini_installer.exe is incompatible with the component build, please" | 762 L"mini_installer.exe is incompatible with the component build, please" |
| 760 L" run setup.exe with the same command line instead. See" | 763 L" run setup.exe with the same command line instead. See" |
| 761 L" http://crbug.com/127233#c17 for details."; | 764 L" http://crbug.com/127233#c17 for details."; |
| 762 ::MessageBox(NULL, kComponentBuildIncompatibleMessage, NULL, MB_ICONERROR); | 765 ::MessageBox(NULL, kComponentBuildIncompatibleMessage, NULL, MB_ICONERROR); |
| 763 return 1; | 766 return GENERIC_ERROR; |
| 764 } | 767 } |
| 765 #endif | 768 #endif |
| 766 | 769 |
| 767 // Always start with deleting potential leftovers from previous installations. | 770 // Always start with deleting potential leftovers from previous installations. |
| 768 // This can make the difference between success and failure. We've seen | 771 // This can make the difference between success and failure. We've seen |
| 769 // many installations out in the field fail due to out of disk space problems | 772 // many installations out in the field fail due to out of disk space problems |
| 770 // so this could buy us some space. | 773 // so this could buy us some space. |
| 771 DeleteOldChromeTempDirectories(); | 774 DeleteOldChromeTempDirectories(); |
| 772 | 775 |
| 773 // TODO(grt): Make the exit codes more granular so we know where the popular | 776 // TODO(grt): Make the exit codes more granular so we know where the popular |
| 774 // errors truly are. | 777 // errors truly are. |
| 775 int exit_code = 101; | 778 ProcessExitCode exit_code = GENERIC_INITIALIZATION_FAILURE; |
| 776 | 779 |
| 777 // Parse the command line. | 780 // Parse the command line. |
| 778 Configuration configuration; | 781 Configuration configuration; |
| 779 if (!configuration.Initialize()) | 782 if (!configuration.Initialize()) |
| 780 return exit_code; | 783 return exit_code; |
| 781 | 784 |
| 782 if (configuration.query_component_build()) { | 785 if (configuration.query_component_build()) { |
| 783 // Exit immediately with an exit code of 1 to indicate component build and 0 | 786 // Exit immediately with an exit code of 1 to indicate component build and 0 |
| 784 // to indicate static build. This is used by the tests in | 787 // to indicate static build. This is used by the tests in |
| 785 // /src/chrome/test/mini_installer/. | 788 // /src/chrome/test/mini_installer/. |
| 786 #if defined(COMPONENT_BUILD) | 789 #if defined(COMPONENT_BUILD) |
| 787 return 1; | 790 return GENERIC_ERROR; |
|
gab
2014/07/07 13:45:01
This doesn't match what the comment above says (i.
grt (UTC plus 2)
2014/07/07 14:24:06
0/1 are the generic success/error codes for any ex
| |
| 788 #else | 791 #else |
| 789 return 0; | 792 return SUCCESS_EXIT_CODE; |
| 790 #endif | 793 #endif |
| 791 } | 794 } |
| 792 | 795 |
| 793 // If the --cleanup switch was specified on the command line, then that means | 796 // If the --cleanup switch was specified on the command line, then that means |
| 794 // we should only do the cleanup and then exit. | 797 // we should only do the cleanup and then exit. |
| 795 if (ProcessNonInstallOperations(configuration, &exit_code)) | 798 if (ProcessNonInstallOperations(configuration, &exit_code)) |
| 796 return exit_code; | 799 return exit_code; |
| 797 | 800 |
| 798 // First get a path where we can extract payload | 801 // First get a path where we can extract payload |
| 799 PathString base_path; | 802 PathString base_path; |
| 800 if (!GetWorkDir(module, &base_path)) | 803 if (!GetWorkDir(module, &base_path)) |
| 801 return 101; | 804 return GENERIC_INITIALIZATION_FAILURE; |
| 802 | 805 |
| 803 #if defined(GOOGLE_CHROME_BUILD) | 806 #if defined(GOOGLE_CHROME_BUILD) |
| 804 // Set the magic suffix in registry to try full installer next time. We ignore | 807 // Set the magic suffix in registry to try full installer next time. We ignore |
| 805 // any errors here and we try to set the suffix for user level unless | 808 // any errors here and we try to set the suffix for user level unless |
| 806 // --system-level is on the command line in which case we set it for system | 809 // --system-level is on the command line in which case we set it for system |
| 807 // level instead. This only applies to the Google Chrome distribution. | 810 // level instead. This only applies to the Google Chrome distribution. |
| 808 SetInstallerFlags(configuration); | 811 SetInstallerFlags(configuration); |
| 809 #endif | 812 #endif |
| 810 | 813 |
| 811 PathString archive_path; | 814 PathString archive_path; |
| 812 PathString setup_path; | 815 PathString setup_path; |
| 813 if (!UnpackBinaryResources(configuration, module, base_path.get(), | 816 if (!UnpackBinaryResources(configuration, module, base_path.get(), |
| 814 &archive_path, &setup_path)) { | 817 &archive_path, &setup_path)) { |
| 815 exit_code = 102; | 818 exit_code = GENERIC_UNPACKING_FAILURE; |
| 816 } else { | 819 } else { |
| 817 // While unpacking the binaries, we paged in a whole bunch of memory that | 820 // While unpacking the binaries, we paged in a whole bunch of memory that |
| 818 // we don't need anymore. Let's give it back to the pool before running | 821 // we don't need anymore. Let's give it back to the pool before running |
| 819 // setup. | 822 // setup. |
| 820 ::SetProcessWorkingSetSize(::GetCurrentProcess(), -1, -1); | 823 ::SetProcessWorkingSetSize(::GetCurrentProcess(), -1, -1); |
| 821 if (!RunSetup(configuration, archive_path.get(), setup_path.get(), | 824 if (!RunSetup(configuration, archive_path.get(), setup_path.get(), |
| 822 &exit_code)) { | 825 &exit_code)) { |
| 823 exit_code = 103; | 826 exit_code = GENERIC_SETUP_FAILURE; |
| 824 } | 827 } |
| 825 } | 828 } |
| 826 | 829 |
| 827 if (ShouldDeleteExtractedFiles()) | 830 if (ShouldDeleteExtractedFiles()) |
| 828 DeleteExtractedFiles(base_path.get(), archive_path.get(), setup_path.get()); | 831 DeleteExtractedFiles(base_path.get(), archive_path.get(), setup_path.get()); |
| 829 | 832 |
| 830 return exit_code; | 833 return exit_code; |
| 831 } | 834 } |
| 832 | 835 |
| 833 } // namespace mini_installer | 836 } // namespace mini_installer |
| 834 | 837 |
| 835 int MainEntryPoint() { | 838 int MainEntryPoint() { |
| 836 int result = mini_installer::WMain(::GetModuleHandle(NULL)); | 839 mini_installer::ProcessExitCode result = |
| 840 mini_installer::WMain(::GetModuleHandle(NULL)); | |
| 837 ::ExitProcess(result); | 841 ::ExitProcess(result); |
| 838 } | 842 } |
| 839 | 843 |
| 840 // VC Express editions don't come with the memset CRT obj file and linking to | 844 // VC Express editions don't come with the memset CRT obj file and linking to |
| 841 // the obj files between versions becomes a bit problematic. Therefore, | 845 // the obj files between versions becomes a bit problematic. Therefore, |
| 842 // simply implement memset. | 846 // simply implement memset. |
| 843 // | 847 // |
| 844 // This also avoids having to explicitly set the __sse2_available hack when | 848 // This also avoids having to explicitly set the __sse2_available hack when |
| 845 // linking with both the x64 and x86 obj files which is required when not | 849 // linking with both the x64 and x86 obj files which is required when not |
| 846 // linking with the std C lib in certain instances (including Chromium) with | 850 // linking with the std C lib in certain instances (including Chromium) with |
| 847 // MSVC. __sse2_available determines whether to use SSE2 intructions with | 851 // MSVC. __sse2_available determines whether to use SSE2 intructions with |
| 848 // std C lib routines, and is set by MSVC's std C lib implementation normally. | 852 // std C lib routines, and is set by MSVC's std C lib implementation normally. |
| 849 extern "C" { | 853 extern "C" { |
| 850 #pragma function(memset) | 854 #pragma function(memset) |
| 851 void* memset(void* dest, int c, size_t count) { | 855 void* memset(void* dest, int c, size_t count) { |
| 852 void* start = dest; | 856 void* start = dest; |
| 853 while (count--) { | 857 while (count--) { |
| 854 *reinterpret_cast<char*>(dest) = static_cast<char>(c); | 858 *reinterpret_cast<char*>(dest) = static_cast<char>(c); |
| 855 dest = reinterpret_cast<char*>(dest) + 1; | 859 dest = reinterpret_cast<char*>(dest) + 1; |
| 856 } | 860 } |
| 857 return start; | 861 return start; |
| 858 } | 862 } |
| 859 } // extern "C" | 863 } // extern "C" |
| OLD | NEW |