| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 #include <windows.h> | 5 #include <windows.h> |
| 6 #include <msi.h> | 6 #include <msi.h> |
| 7 #include <shellapi.h> | 7 #include <shellapi.h> |
| 8 #include <shlobj.h> | 8 #include <shlobj.h> |
| 9 | 9 |
| 10 #include <string> | 10 #include <string> |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 43 #include "chrome/installer/util/util_constants.h" | 43 #include "chrome/installer/util/util_constants.h" |
| 44 | 44 |
| 45 #include "installer_util_strings.h" // NOLINT | 45 #include "installer_util_strings.h" // NOLINT |
| 46 | 46 |
| 47 using installer::Product; | 47 using installer::Product; |
| 48 using installer::ProductPackageMapping; | 48 using installer::ProductPackageMapping; |
| 49 using installer::Products; | 49 using installer::Products; |
| 50 using installer::Package; | 50 using installer::Package; |
| 51 using installer::Packages; | 51 using installer::Packages; |
| 52 using installer::Version; | 52 using installer::Version; |
| 53 using installer::MasterPreferences; | 53 using installer_util::MasterPreferences; |
| 54 | 54 |
| 55 namespace { | 55 namespace { |
| 56 | 56 |
| 57 // This method unpacks and uncompresses the given archive file. For Chrome | 57 // This method unpacks and uncompresses the given archive file. For Chrome |
| 58 // install we are creating a uncompressed archive that contains all the files | 58 // install we are creating a uncompressed archive that contains all the files |
| 59 // needed for the installer. This uncompressed archive is later compressed. | 59 // needed for the installer. This uncompressed archive is later compressed. |
| 60 // | 60 // |
| 61 // This method first uncompresses archive specified by parameter "archive" | 61 // This method first uncompresses archive specified by parameter "archive" |
| 62 // and assumes that it will result in an uncompressed full archive file | 62 // and assumes that it will result in an uncompressed full archive file |
| 63 // (chrome.7z) or uncompressed archive patch file (chrome_patch.diff). If it | 63 // (chrome.7z) or uncompressed archive patch file (chrome_patch.diff). If it |
| 64 // is patch file, it is applied to the old archive file that should be | 64 // is patch file, it is applied to the old archive file that should be |
| 65 // present on the system already. As the final step the new archive file | 65 // present on the system already. As the final step the new archive file |
| 66 // is unpacked in the path specified by parameter "output_directory". | 66 // is unpacked in the path specified by parameter "output_directory". |
| 67 DWORD UnPackArchive(const FilePath& archive, | 67 DWORD UnPackArchive(const FilePath& archive, |
| 68 const Package& installation, | 68 const Package& installation, |
| 69 const FilePath& temp_path, | 69 const FilePath& temp_path, |
| 70 const FilePath& output_directory, | 70 const FilePath& output_directory, |
| 71 bool& incremental_install) { | 71 bool& incremental_install) { |
| 72 // First uncompress the payload. This could be a differential | 72 // First uncompress the payload. This could be a differential |
| 73 // update (patch.7z) or full archive (chrome.7z). If this uncompress fails | 73 // update (patch.7z) or full archive (chrome.7z). If this uncompress fails |
| 74 // return with error. | 74 // return with error. |
| 75 std::wstring unpacked_file; | 75 std::wstring unpacked_file; |
| 76 int32 ret = LzmaUtil::UnPackArchive(archive.value(), temp_path.value(), | 76 int32 ret = LzmaUtil::UnPackArchive(archive.value(), temp_path.value(), |
| 77 &unpacked_file); | 77 &unpacked_file); |
| 78 if (ret != NO_ERROR) | 78 if (ret != NO_ERROR) |
| 79 return ret; | 79 return ret; |
| 80 | 80 |
| 81 FilePath uncompressed_archive(temp_path.Append(installer::kChromeArchive)); | 81 FilePath uncompressed_archive(temp_path.Append(installer::kChromeArchive)); |
| 82 scoped_ptr<Version> archive_version( | 82 scoped_ptr<Version> archive_version( |
| 83 installer::GetVersionFromArchiveDir(installation.path())); | 83 setup_util::GetVersionFromArchiveDir(installation.path())); |
| 84 | 84 |
| 85 // Check if this is differential update and if it is, patch it to the | 85 // Check if this is differential update and if it is, patch it to the |
| 86 // installer archive that should already be on the machine. We assume | 86 // installer archive that should already be on the machine. We assume |
| 87 // it is a differential installer if chrome.7z is not found. | 87 // it is a differential installer if chrome.7z is not found. |
| 88 if (!file_util::PathExists(uncompressed_archive)) { | 88 if (!file_util::PathExists(uncompressed_archive)) { |
| 89 incremental_install = true; | 89 incremental_install = true; |
| 90 VLOG(1) << "Differential patch found. Applying to existing archive."; | 90 VLOG(1) << "Differential patch found. Applying to existing archive."; |
| 91 if (!archive_version.get()) { | 91 if (!archive_version.get()) { |
| 92 LOG(ERROR) << "Can not use differential update when Chrome is not " | 92 LOG(ERROR) << "Can not use differential update when Chrome is not " |
| 93 << "installed on the system."; | 93 << "installed on the system."; |
| 94 return installer::CHROME_NOT_INSTALLED; | 94 return installer_util::CHROME_NOT_INSTALLED; |
| 95 } | 95 } |
| 96 | 96 |
| 97 FilePath existing_archive( | 97 FilePath existing_archive( |
| 98 installation.path().Append(archive_version->GetString())); | 98 installation.path().Append(archive_version->GetString())); |
| 99 existing_archive = existing_archive.Append(installer::kInstallerDir); | 99 existing_archive = existing_archive.Append(installer_util::kInstallerDir); |
| 100 existing_archive = existing_archive.Append(installer::kChromeArchive); | 100 existing_archive = existing_archive.Append(installer::kChromeArchive); |
| 101 if (int i = installer::ApplyDiffPatch(FilePath(existing_archive), | 101 if (int i = setup_util::ApplyDiffPatch(FilePath(existing_archive), |
| 102 FilePath(unpacked_file), | 102 FilePath(unpacked_file), |
| 103 FilePath(uncompressed_archive))) { | 103 FilePath(uncompressed_archive))) { |
| 104 LOG(ERROR) << "Binary patching failed with error " << i; | 104 LOG(ERROR) << "Binary patching failed with error " << i; |
| 105 return i; | 105 return i; |
| 106 } | 106 } |
| 107 } | 107 } |
| 108 | 108 |
| 109 // Unpack the uncompressed archive. | 109 // Unpack the uncompressed archive. |
| 110 return LzmaUtil::UnPackArchive(uncompressed_archive.value(), | 110 return LzmaUtil::UnPackArchive(uncompressed_archive.value(), |
| 111 output_directory.value(), &unpacked_file); | 111 output_directory.value(), &unpacked_file); |
| 112 } | 112 } |
| 113 | 113 |
| 114 | 114 |
| 115 // This function is called when --rename-chrome-exe option is specified on | 115 // This function is called when --rename-chrome-exe option is specified on |
| 116 // setup.exe command line. This function assumes an in-use update has happened | 116 // setup.exe command line. This function assumes an in-use update has happened |
| 117 // for Chrome so there should be a file called new_chrome.exe on the file | 117 // for Chrome so there should be a file called new_chrome.exe on the file |
| 118 // system and a key called 'opv' in the registry. This function will move | 118 // system and a key called 'opv' in the registry. This function will move |
| 119 // new_chrome.exe to chrome.exe and delete 'opv' key in one atomic operation. | 119 // new_chrome.exe to chrome.exe and delete 'opv' key in one atomic operation. |
| 120 installer::InstallStatus RenameChromeExecutables( | 120 installer_util::InstallStatus RenameChromeExecutables( |
| 121 const Package& installation) { | 121 const Package& installation) { |
| 122 FilePath chrome_exe(installation.path().Append(installer::kChromeExe)); | 122 FilePath chrome_exe(installation.path().Append(installer_util::kChromeExe)); |
| 123 FilePath chrome_old_exe(installation.path().Append( | 123 FilePath chrome_old_exe(installation.path().Append( |
| 124 installer::kChromeOldExe)); | 124 installer_util::kChromeOldExe)); |
| 125 FilePath chrome_new_exe(installation.path().Append( | 125 FilePath chrome_new_exe(installation.path().Append( |
| 126 installer::kChromeNewExe)); | 126 installer_util::kChromeNewExe)); |
| 127 | 127 |
| 128 scoped_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList()); | 128 scoped_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList()); |
| 129 install_list->AddDeleteTreeWorkItem(chrome_old_exe); | 129 install_list->AddDeleteTreeWorkItem(chrome_old_exe); |
| 130 FilePath temp_path; | 130 FilePath temp_path; |
| 131 if (!file_util::CreateNewTempDirectory(L"chrome_", &temp_path)) { | 131 if (!file_util::CreateNewTempDirectory(L"chrome_", &temp_path)) { |
| 132 LOG(ERROR) << "Failed to create Temp directory " << temp_path.value(); | 132 LOG(ERROR) << "Failed to create Temp directory " << temp_path.value(); |
| 133 return installer::RENAME_FAILED; | 133 return installer_util::RENAME_FAILED; |
| 134 } | 134 } |
| 135 | 135 |
| 136 install_list->AddCopyTreeWorkItem(chrome_new_exe.value(), | 136 install_list->AddCopyTreeWorkItem(chrome_new_exe.value(), |
| 137 chrome_exe.value(), | 137 chrome_exe.value(), |
| 138 temp_path.ToWStringHack(), | 138 temp_path.ToWStringHack(), |
| 139 WorkItem::IF_DIFFERENT, | 139 WorkItem::IF_DIFFERENT, |
| 140 std::wstring()); | 140 std::wstring()); |
| 141 install_list->AddDeleteTreeWorkItem(chrome_new_exe); | 141 install_list->AddDeleteTreeWorkItem(chrome_new_exe); |
| 142 | 142 |
| 143 HKEY reg_root = installation.system_level() ? HKEY_LOCAL_MACHINE : | 143 HKEY reg_root = installation.system_level() ? HKEY_LOCAL_MACHINE : |
| 144 HKEY_CURRENT_USER; | 144 HKEY_CURRENT_USER; |
| 145 const Products& products = installation.products(); | 145 const Products& products = installation.products(); |
| 146 for (size_t i = 0; i < products.size(); ++i) { | 146 for (size_t i = 0; i < products.size(); ++i) { |
| 147 const Product* product = products[i]; | 147 const Product* product = products[i]; |
| 148 BrowserDistribution* browser_dist = product->distribution(); | 148 BrowserDistribution* browser_dist = product->distribution(); |
| 149 std::wstring version_key(browser_dist->GetVersionKey()); | 149 std::wstring version_key(browser_dist->GetVersionKey()); |
| 150 install_list->AddDeleteRegValueWorkItem(reg_root, | 150 install_list->AddDeleteRegValueWorkItem(reg_root, |
| 151 version_key, | 151 version_key, |
| 152 google_update::kRegOldVersionField, | 152 google_update::kRegOldVersionField, |
| 153 true); | 153 true); |
| 154 install_list->AddDeleteRegValueWorkItem(reg_root, | 154 install_list->AddDeleteRegValueWorkItem(reg_root, |
| 155 version_key, | 155 version_key, |
| 156 google_update::kRegRenameCmdField, | 156 google_update::kRegRenameCmdField, |
| 157 true); | 157 true); |
| 158 } | 158 } |
| 159 installer::InstallStatus ret = installer::RENAME_SUCCESSFUL; | 159 installer_util::InstallStatus ret = installer_util::RENAME_SUCCESSFUL; |
| 160 if (!install_list->Do()) { | 160 if (!install_list->Do()) { |
| 161 LOG(ERROR) << "Renaming of executables failed. Rolling back any changes."; | 161 LOG(ERROR) << "Renaming of executables failed. Rolling back any changes."; |
| 162 install_list->Rollback(); | 162 install_list->Rollback(); |
| 163 ret = installer::RENAME_FAILED; | 163 ret = installer_util::RENAME_FAILED; |
| 164 } | 164 } |
| 165 file_util::Delete(temp_path, true); | 165 file_util::Delete(temp_path, true); |
| 166 return ret; | 166 return ret; |
| 167 } | 167 } |
| 168 | 168 |
| 169 bool CheckPreInstallConditions(const Package& installation, | 169 bool CheckPreInstallConditions(const Package& installation, |
| 170 installer::InstallStatus& status) { | 170 installer_util::InstallStatus& status) { |
| 171 const Products& products = installation.products(); | 171 const Products& products = installation.products(); |
| 172 DCHECK(products.size()); | 172 DCHECK(products.size()); |
| 173 | 173 |
| 174 bool is_first_install = true; | 174 bool is_first_install = true; |
| 175 | 175 |
| 176 for (size_t i = 0; i < products.size(); ++i) { | 176 for (size_t i = 0; i < products.size(); ++i) { |
| 177 const Product* product = products[i]; | 177 const Product* product = products[i]; |
| 178 BrowserDistribution* browser_dist = product->distribution(); | 178 BrowserDistribution* browser_dist = product->distribution(); |
| 179 scoped_ptr<Version> installed_version(product->GetInstalledVersion()); | 179 scoped_ptr<Version> installed_version(product->GetInstalledVersion()); |
| 180 // TODO(tommi): If the current install is for a different distribution than | 180 // TODO(tommi): If the current install is for a different distribution than |
| 181 // that might already be installed, then this check is incorrect. | 181 // that might already be installed, then this check is incorrect. |
| 182 if (installed_version.get()) | 182 if (installed_version.get()) |
| 183 is_first_install = false; | 183 is_first_install = false; |
| 184 | 184 |
| 185 // Check to avoid simultaneous per-user and per-machine installs. | 185 // Check to avoid simultaneous per-user and per-machine installs. |
| 186 scoped_ptr<Version> chrome_version( | 186 scoped_ptr<Version> chrome_version( |
| 187 InstallUtil::GetChromeVersion(browser_dist, !product->system_level())); | 187 InstallUtil::GetChromeVersion(browser_dist, !product->system_level())); |
| 188 | 188 |
| 189 if (chrome_version.get()) { | 189 if (chrome_version.get()) { |
| 190 LOG(ERROR) << "Already installed version " << chrome_version->GetString() | 190 LOG(ERROR) << "Already installed version " << chrome_version->GetString() |
| 191 << " conflicts with the current install mode."; | 191 << " conflicts with the current install mode."; |
| 192 if (!product->system_level() && is_first_install) { | 192 if (!product->system_level() && is_first_install) { |
| 193 // This is user-level install and there is a system-level chrome | 193 // This is user-level install and there is a system-level chrome |
| 194 // installation. Instruct Omaha to launch the existing one. There | 194 // installation. Instruct Omaha to launch the existing one. There |
| 195 // should be no error dialog. | 195 // should be no error dialog. |
| 196 FilePath chrome_exe(installer::GetChromeInstallPath( | 196 FilePath chrome_exe(installer::GetChromeInstallPath( |
| 197 !product->system_level(), browser_dist)); | 197 !product->system_level(), browser_dist)); |
| 198 if (chrome_exe.empty()) { | 198 if (chrome_exe.empty()) { |
| 199 // If we failed to construct install path. Give up. | 199 // If we failed to construct install path. Give up. |
| 200 status = installer::OS_ERROR; | 200 status = installer_util::OS_ERROR; |
| 201 product->WriteInstallerResult(status, IDS_INSTALL_OS_ERROR_BASE, | 201 product->WriteInstallerResult(status, IDS_INSTALL_OS_ERROR_BASE, |
| 202 NULL); | 202 NULL); |
| 203 } else { | 203 } else { |
| 204 status = installer::EXISTING_VERSION_LAUNCHED; | 204 status = installer_util::EXISTING_VERSION_LAUNCHED; |
| 205 chrome_exe = chrome_exe.Append(installer::kChromeExe); | 205 chrome_exe = chrome_exe.Append(installer_util::kChromeExe); |
| 206 CommandLine cmd(chrome_exe); | 206 CommandLine cmd(chrome_exe); |
| 207 cmd.AppendSwitch(switches::kFirstRun); | 207 cmd.AppendSwitch(switches::kFirstRun); |
| 208 product->WriteInstallerResult(status, 0, NULL); | 208 product->WriteInstallerResult(status, 0, NULL); |
| 209 VLOG(1) << "Launching existing system-level chrome instead."; | 209 VLOG(1) << "Launching existing system-level chrome instead."; |
| 210 base::LaunchApp(cmd, false, false, NULL); | 210 base::LaunchApp(cmd, false, false, NULL); |
| 211 } | 211 } |
| 212 return false; | 212 return false; |
| 213 } | 213 } |
| 214 | 214 |
| 215 // If the following compile assert fires it means that the InstallStatus | 215 // If the following compile assert fires it means that the InstallStatus |
| 216 // enumeration changed which will break the contract between the old | 216 // enumeration changed which will break the contract between the old |
| 217 // chrome installed and the new setup.exe that is trying to upgrade. | 217 // chrome installed and the new setup.exe that is trying to upgrade. |
| 218 COMPILE_ASSERT(installer::SXS_OPTION_NOT_SUPPORTED == 33, | 218 COMPILE_ASSERT(installer_util::SXS_OPTION_NOT_SUPPORTED == 33, |
| 219 dont_change_enum); | 219 dont_change_enum); |
| 220 | 220 |
| 221 // This is an update, not an install. Omaha should know the difference | 221 // This is an update, not an install. Omaha should know the difference |
| 222 // and not show a dialog. | 222 // and not show a dialog. |
| 223 status = product->system_level() ? | 223 status = product->system_level() ? |
| 224 installer::USER_LEVEL_INSTALL_EXISTS : | 224 installer_util::USER_LEVEL_INSTALL_EXISTS : |
| 225 installer::SYSTEM_LEVEL_INSTALL_EXISTS; | 225 installer_util::SYSTEM_LEVEL_INSTALL_EXISTS; |
| 226 int str_id = product->system_level() ? | 226 int str_id = product->system_level() ? |
| 227 IDS_INSTALL_USER_LEVEL_EXISTS_BASE : | 227 IDS_INSTALL_USER_LEVEL_EXISTS_BASE : |
| 228 IDS_INSTALL_SYSTEM_LEVEL_EXISTS_BASE; | 228 IDS_INSTALL_SYSTEM_LEVEL_EXISTS_BASE; |
| 229 product->WriteInstallerResult(status, str_id, NULL); | 229 product->WriteInstallerResult(status, str_id, NULL); |
| 230 return false; | 230 return false; |
| 231 } | 231 } |
| 232 } | 232 } |
| 233 | 233 |
| 234 // If no previous installation of Chrome, make sure installation directory | 234 // If no previous installation of Chrome, make sure installation directory |
| 235 // either does not exist or can be deleted (i.e. is not locked by some other | 235 // either does not exist or can be deleted (i.e. is not locked by some other |
| 236 // process). | 236 // process). |
| 237 if (is_first_install) { | 237 if (is_first_install) { |
| 238 if (file_util::PathExists(installation.path()) && | 238 if (file_util::PathExists(installation.path()) && |
| 239 !file_util::Delete(installation.path(), true)) { | 239 !file_util::Delete(installation.path(), true)) { |
| 240 LOG(ERROR) << "Installation directory " << installation.path().value() | 240 LOG(ERROR) << "Installation directory " << installation.path().value() |
| 241 << " exists and can not be deleted."; | 241 << " exists and can not be deleted."; |
| 242 status = installer::INSTALL_DIR_IN_USE; | 242 status = installer_util::INSTALL_DIR_IN_USE; |
| 243 int str_id = IDS_INSTALL_DIR_IN_USE_BASE; | 243 int str_id = IDS_INSTALL_DIR_IN_USE_BASE; |
| 244 WriteInstallerResult(products, status, str_id, NULL); | 244 WriteInstallerResult(products, status, str_id, NULL); |
| 245 return false; | 245 return false; |
| 246 } | 246 } |
| 247 } | 247 } |
| 248 | 248 |
| 249 return true; | 249 return true; |
| 250 } | 250 } |
| 251 | 251 |
| 252 installer::InstallStatus InstallChrome(const CommandLine& cmd_line, | 252 installer_util::InstallStatus InstallChrome(const CommandLine& cmd_line, |
| 253 const Package& installation, const MasterPreferences& prefs) { | 253 const Package& installation, const MasterPreferences& prefs) { |
| 254 installer::InstallStatus install_status = installer::UNKNOWN_STATUS; | 254 installer_util::InstallStatus install_status = installer_util::UNKNOWN_STATUS; |
| 255 if (!CheckPreInstallConditions(installation, install_status)) | 255 if (!CheckPreInstallConditions(installation, install_status)) |
| 256 return install_status; | 256 return install_status; |
| 257 | 257 |
| 258 // For install the default location for chrome.packed.7z is in current | 258 // For install the default location for chrome.packed.7z is in current |
| 259 // folder, so get that value first. | 259 // folder, so get that value first. |
| 260 FilePath archive(cmd_line.GetProgram().DirName().Append( | 260 FilePath archive(cmd_line.GetProgram().DirName().Append( |
| 261 installer::kChromeCompressedArchive)); | 261 installer::kChromeCompressedArchive)); |
| 262 | 262 |
| 263 // If --install-archive is given, get the user specified value | 263 // If --install-archive is given, get the user specified value |
| 264 if (cmd_line.HasSwitch(installer::switches::kInstallArchive)) { | 264 if (cmd_line.HasSwitch(installer_util::switches::kInstallArchive)) { |
| 265 archive = cmd_line.GetSwitchValuePath( | 265 archive = cmd_line.GetSwitchValuePath( |
| 266 installer::switches::kInstallArchive); | 266 installer_util::switches::kInstallArchive); |
| 267 } | 267 } |
| 268 VLOG(1) << "Archive found to install Chrome " << archive.value(); | 268 VLOG(1) << "Archive found to install Chrome " << archive.value(); |
| 269 bool system_level = installation.system_level(); | 269 bool system_level = installation.system_level(); |
| 270 const Products& products = installation.products(); | 270 const Products& products = installation.products(); |
| 271 | 271 |
| 272 // Create a temp folder where we will unpack Chrome archive. If it fails, | 272 // Create a temp folder where we will unpack Chrome archive. If it fails, |
| 273 // then we are doomed, so return immediately and no cleanup is required. | 273 // then we are doomed, so return immediately and no cleanup is required. |
| 274 FilePath temp_path; | 274 FilePath temp_path; |
| 275 if (!file_util::CreateNewTempDirectory(L"chrome_", &temp_path)) { | 275 if (!file_util::CreateNewTempDirectory(L"chrome_", &temp_path)) { |
| 276 LOG(ERROR) << "Could not create temporary path."; | 276 LOG(ERROR) << "Could not create temporary path."; |
| 277 WriteInstallerResult(products, installer::TEMP_DIR_FAILED, | 277 WriteInstallerResult(products, installer_util::TEMP_DIR_FAILED, |
| 278 IDS_INSTALL_TEMP_DIR_FAILED_BASE, NULL); | 278 IDS_INSTALL_TEMP_DIR_FAILED_BASE, NULL); |
| 279 return installer::TEMP_DIR_FAILED; | 279 return installer_util::TEMP_DIR_FAILED; |
| 280 } | 280 } |
| 281 VLOG(1) << "created path " << temp_path.value(); | 281 VLOG(1) << "created path " << temp_path.value(); |
| 282 | 282 |
| 283 FilePath unpack_path(temp_path.Append(installer::kInstallSourceDir)); | 283 FilePath unpack_path(temp_path.Append(installer::kInstallSourceDir)); |
| 284 bool incremental_install = false; | 284 bool incremental_install = false; |
| 285 if (UnPackArchive(archive, installation, temp_path, unpack_path, | 285 if (UnPackArchive(archive, installation, temp_path, unpack_path, |
| 286 incremental_install)) { | 286 incremental_install)) { |
| 287 install_status = installer::UNCOMPRESSION_FAILED; | 287 install_status = installer_util::UNCOMPRESSION_FAILED; |
| 288 WriteInstallerResult(products, install_status, | 288 WriteInstallerResult(products, install_status, |
| 289 IDS_INSTALL_UNCOMPRESSION_FAILED_BASE, NULL); | 289 IDS_INSTALL_UNCOMPRESSION_FAILED_BASE, NULL); |
| 290 } else { | 290 } else { |
| 291 VLOG(1) << "unpacked to " << unpack_path.value(); | 291 VLOG(1) << "unpacked to " << unpack_path.value(); |
| 292 FilePath src_path(unpack_path.Append(installer::kInstallSourceChromeDir)); | 292 FilePath src_path(unpack_path.Append(installer::kInstallSourceChromeDir)); |
| 293 scoped_ptr<Version> | 293 scoped_ptr<Version> |
| 294 installer_version(installer::GetVersionFromArchiveDir(src_path)); | 294 installer_version(setup_util::GetVersionFromArchiveDir(src_path)); |
| 295 if (!installer_version.get()) { | 295 if (!installer_version.get()) { |
| 296 LOG(ERROR) << "Did not find any valid version in installer."; | 296 LOG(ERROR) << "Did not find any valid version in installer."; |
| 297 install_status = installer::INVALID_ARCHIVE; | 297 install_status = installer_util::INVALID_ARCHIVE; |
| 298 WriteInstallerResult(products, install_status, | 298 WriteInstallerResult(products, install_status, |
| 299 IDS_INSTALL_INVALID_ARCHIVE_BASE, NULL); | 299 IDS_INSTALL_INVALID_ARCHIVE_BASE, NULL); |
| 300 } else { | 300 } else { |
| 301 // TODO(tommi): Move towards having only a single version that is common | 301 // TODO(tommi): Move towards having only a single version that is common |
| 302 // to all products. Only the package should have a version since it | 302 // to all products. Only the package should have a version since it |
| 303 // represents all the binaries. When a single product is upgraded, all | 303 // represents all the binaries. When a single product is upgraded, all |
| 304 // currently installed product for the shared binary installation, should | 304 // currently installed product for the shared binary installation, should |
| 305 // (or rather must) be upgraded. | 305 // (or rather must) be upgraded. |
| 306 VLOG(1) << "version to install: " << installer_version->GetString(); | 306 VLOG(1) << "version to install: " << installer_version->GetString(); |
| 307 bool higher_version_installed = false; | 307 bool higher_version_installed = false; |
| 308 for (size_t i = 0; i < installation.products().size(); ++i) { | 308 for (size_t i = 0; i < installation.products().size(); ++i) { |
| 309 const Product* product = installation.products()[i]; | 309 const Product* product = installation.products()[i]; |
| 310 scoped_ptr<Version> v(product->GetInstalledVersion()); | 310 scoped_ptr<Version> v(product->GetInstalledVersion()); |
| 311 if (v.get() && v->IsHigherThan(installer_version.get())) { | 311 if (v.get() && v->IsHigherThan(installer_version.get())) { |
| 312 LOG(ERROR) << "Higher version is already installed."; | 312 LOG(ERROR) << "Higher version is already installed."; |
| 313 higher_version_installed = true; | 313 higher_version_installed = true; |
| 314 install_status = installer::HIGHER_VERSION_EXISTS; | 314 install_status = installer_util::HIGHER_VERSION_EXISTS; |
| 315 | 315 |
| 316 if (product->distribution()->GetType() != | 316 if (product->distribution()->GetType() != |
| 317 BrowserDistribution::CHROME_BROWSER) { | 317 BrowserDistribution::CHROME_BROWSER) { |
| 318 // TODO(robertshield): We should take the installer result text | 318 // TODO(robertshield): We should take the installer result text |
| 319 // strings from the Product. | 319 // strings from the Product. |
| 320 product->WriteInstallerResult(install_status, | 320 product->WriteInstallerResult(install_status, |
| 321 IDS_INSTALL_HIGHER_VERSION_BASE, NULL); | 321 IDS_INSTALL_HIGHER_VERSION_BASE, NULL); |
| 322 } else { | 322 } else { |
| 323 product->WriteInstallerResult(install_status, | 323 product->WriteInstallerResult(install_status, |
| 324 IDS_INSTALL_HIGHER_VERSION_CF_BASE, NULL); | 324 IDS_INSTALL_HIGHER_VERSION_CF_BASE, NULL); |
| 325 } | 325 } |
| 326 } | 326 } |
| 327 } | 327 } |
| 328 | 328 |
| 329 if (!higher_version_installed) { | 329 if (!higher_version_installed) { |
| 330 // We want to keep uncompressed archive (chrome.7z) that we get after | 330 // We want to keep uncompressed archive (chrome.7z) that we get after |
| 331 // uncompressing and binary patching. Get the location for this file. | 331 // uncompressing and binary patching. Get the location for this file. |
| 332 FilePath archive_to_copy(temp_path.Append(installer::kChromeArchive)); | 332 FilePath archive_to_copy(temp_path.Append(installer::kChromeArchive)); |
| 333 FilePath prefs_source_path(cmd_line.GetSwitchValueNative( | 333 FilePath prefs_source_path(cmd_line.GetSwitchValueNative( |
| 334 installer::switches::kInstallerData)); | 334 installer_util::switches::kInstallerData)); |
| 335 install_status = installer::InstallOrUpdateChrome(cmd_line.GetProgram(), | 335 install_status = installer::InstallOrUpdateChrome(cmd_line.GetProgram(), |
| 336 archive_to_copy, temp_path, prefs_source_path, prefs, | 336 archive_to_copy, temp_path, prefs_source_path, prefs, |
| 337 *installer_version, installation); | 337 *installer_version, installation); |
| 338 | 338 |
| 339 int install_msg_base = IDS_INSTALL_FAILED_BASE; | 339 int install_msg_base = IDS_INSTALL_FAILED_BASE; |
| 340 std::wstring chrome_exe; | 340 std::wstring chrome_exe; |
| 341 if (install_status == installer::SAME_VERSION_REPAIR_FAILED) { | 341 if (install_status == installer_util::SAME_VERSION_REPAIR_FAILED) { |
| 342 if (FindProduct(products, BrowserDistribution::CHROME_FRAME)) { | 342 if (FindProduct(products, BrowserDistribution::CHROME_FRAME)) { |
| 343 install_msg_base = IDS_SAME_VERSION_REPAIR_FAILED_CF_BASE; | 343 install_msg_base = IDS_SAME_VERSION_REPAIR_FAILED_CF_BASE; |
| 344 } else { | 344 } else { |
| 345 install_msg_base = IDS_SAME_VERSION_REPAIR_FAILED_BASE; | 345 install_msg_base = IDS_SAME_VERSION_REPAIR_FAILED_BASE; |
| 346 } | 346 } |
| 347 } else if (install_status != installer::INSTALL_FAILED) { | 347 } else if (install_status != installer_util::INSTALL_FAILED) { |
| 348 if (installation.path().empty()) { | 348 if (installation.path().empty()) { |
| 349 // If we failed to construct install path, it means the OS call to | 349 // If we failed to construct install path, it means the OS call to |
| 350 // get %ProgramFiles% or %AppData% failed. Report this as failure. | 350 // get %ProgramFiles% or %AppData% failed. Report this as failure. |
| 351 install_msg_base = IDS_INSTALL_OS_ERROR_BASE; | 351 install_msg_base = IDS_INSTALL_OS_ERROR_BASE; |
| 352 install_status = installer::OS_ERROR; | 352 install_status = installer_util::OS_ERROR; |
| 353 } else { | 353 } else { |
| 354 chrome_exe = installation.path() | 354 chrome_exe = installation.path() |
| 355 .Append(installer::kChromeExe).value(); | 355 .Append(installer_util::kChromeExe).value(); |
| 356 chrome_exe = L"\"" + chrome_exe + L"\""; | 356 chrome_exe = L"\"" + chrome_exe + L"\""; |
| 357 install_msg_base = 0; | 357 install_msg_base = 0; |
| 358 } | 358 } |
| 359 } | 359 } |
| 360 | 360 |
| 361 const Product* chrome_install = | 361 const Product* chrome_install = |
| 362 FindProduct(products, BrowserDistribution::CHROME_BROWSER); | 362 FindProduct(products, BrowserDistribution::CHROME_BROWSER); |
| 363 | 363 |
| 364 bool value = false; | 364 bool value = false; |
| 365 if (chrome_install) { | 365 if (chrome_install) { |
| 366 prefs.GetBool( | 366 prefs.GetBool( |
| 367 installer::master_preferences::kDoNotRegisterForUpdateLaunch, | 367 installer_util::master_preferences::kDoNotRegisterForUpdateLaunch, |
| 368 &value); | 368 &value); |
| 369 } else { | 369 } else { |
| 370 value = true; // Never register. | 370 value = true; // Never register. |
| 371 } | 371 } |
| 372 | 372 |
| 373 bool write_chrome_launch_string = (!value) && | 373 bool write_chrome_launch_string = (!value) && |
| 374 (install_status != installer::IN_USE_UPDATED); | 374 (install_status != installer_util::IN_USE_UPDATED); |
| 375 | 375 |
| 376 WriteInstallerResult(products, install_status, | 376 WriteInstallerResult(products, install_status, |
| 377 install_msg_base, write_chrome_launch_string ? &chrome_exe : NULL); | 377 install_msg_base, write_chrome_launch_string ? &chrome_exe : NULL); |
| 378 | 378 |
| 379 if (install_status == installer::FIRST_INSTALL_SUCCESS) { | 379 if (install_status == installer_util::FIRST_INSTALL_SUCCESS) { |
| 380 VLOG(1) << "First install successful."; | 380 VLOG(1) << "First install successful."; |
| 381 if (chrome_install) { | 381 if (chrome_install) { |
| 382 // We never want to launch Chrome in system level install mode. | 382 // We never want to launch Chrome in system level install mode. |
| 383 bool do_not_launch_chrome = false; | 383 bool do_not_launch_chrome = false; |
| 384 prefs.GetBool( | 384 prefs.GetBool( |
| 385 installer::master_preferences::kDoNotLaunchChrome, | 385 installer_util::master_preferences::kDoNotLaunchChrome, |
| 386 &do_not_launch_chrome); | 386 &do_not_launch_chrome); |
| 387 if (!chrome_install->system_level() && !do_not_launch_chrome) | 387 if (!chrome_install->system_level() && !do_not_launch_chrome) |
| 388 chrome_install->LaunchChrome(); | 388 chrome_install->LaunchChrome(); |
| 389 } | 389 } |
| 390 } else if ((install_status == installer::NEW_VERSION_UPDATED) || | 390 } else if ((install_status == installer_util::NEW_VERSION_UPDATED) || |
| 391 (install_status == installer::IN_USE_UPDATED)) { | 391 (install_status == installer_util::IN_USE_UPDATED)) { |
| 392 for (size_t i = 0; i < products.size(); ++i) { | 392 for (size_t i = 0; i < products.size(); ++i) { |
| 393 installer::RemoveLegacyRegistryKeys( | 393 installer::RemoveLegacyRegistryKeys( |
| 394 products[i]->distribution()); | 394 products[i]->distribution()); |
| 395 } | 395 } |
| 396 } | 396 } |
| 397 } | 397 } |
| 398 } | 398 } |
| 399 // There might be an experiment (for upgrade usually) that needs to happen. | 399 // There might be an experiment (for upgrade usually) that needs to happen. |
| 400 // An experiment's outcome can include chrome's uninstallation. If that is | 400 // An experiment's outcome can include chrome's uninstallation. If that is |
| 401 // the case we would not do that directly at this point but in another | 401 // the case we would not do that directly at this point but in another |
| 402 // instance of setup.exe | 402 // instance of setup.exe |
| 403 // | 403 // |
| 404 // There is another way to reach this same function if this is a system | 404 // There is another way to reach this same function if this is a system |
| 405 // level install. See HandleNonInstallCmdLineOptions(). | 405 // level install. See HandleNonInstallCmdLineOptions(). |
| 406 for (size_t i = 0; i < products.size(); ++i) { | 406 for (size_t i = 0; i < products.size(); ++i) { |
| 407 const Product* product = products[i]; | 407 const Product* product = products[i]; |
| 408 product->distribution()->LaunchUserExperiment(install_status, | 408 product->distribution()->LaunchUserExperiment(install_status, |
| 409 *installer_version, *product, product->system_level()); | 409 *installer_version, *product, product->system_level()); |
| 410 } | 410 } |
| 411 } | 411 } |
| 412 | 412 |
| 413 // Delete temporary files. These include install temporary directory | 413 // Delete temporary files. These include install temporary directory |
| 414 // and master profile file if present. Note that we do not care about rollback | 414 // and master profile file if present. Note that we do not care about rollback |
| 415 // here and we schedule for deletion on reboot below if the deletes fail. As | 415 // here and we schedule for deletion on reboot below if the deletes fail. As |
| 416 // such, we do not use DeleteTreeWorkItem. | 416 // such, we do not use DeleteTreeWorkItem. |
| 417 VLOG(1) << "Deleting temporary directory " << temp_path.value(); | 417 VLOG(1) << "Deleting temporary directory " << temp_path.value(); |
| 418 bool cleanup_success = file_util::Delete(temp_path, true); | 418 bool cleanup_success = file_util::Delete(temp_path, true); |
| 419 if (cmd_line.HasSwitch(installer::switches::kInstallerData)) { | 419 if (cmd_line.HasSwitch(installer_util::switches::kInstallerData)) { |
| 420 std::wstring prefs_path = cmd_line.GetSwitchValueNative( | 420 std::wstring prefs_path = cmd_line.GetSwitchValueNative( |
| 421 installer::switches::kInstallerData); | 421 installer_util::switches::kInstallerData); |
| 422 cleanup_success = file_util::Delete(prefs_path, true) && cleanup_success; | 422 cleanup_success = file_util::Delete(prefs_path, true) && cleanup_success; |
| 423 } | 423 } |
| 424 | 424 |
| 425 // The above cleanup has been observed to fail on several users machines. | 425 // The above cleanup has been observed to fail on several users machines. |
| 426 // Specifically, it appears that the temp folder may be locked when we try | 426 // Specifically, it appears that the temp folder may be locked when we try |
| 427 // to delete it. This is Rather Bad in the case where we have failed updates | 427 // to delete it. This is Rather Bad in the case where we have failed updates |
| 428 // as we end up filling users' disks with large-ish temp files. To mitigate | 428 // as we end up filling users' disks with large-ish temp files. To mitigate |
| 429 // this, if we fail to delete the temp folders, then schedule them for | 429 // this, if we fail to delete the temp folders, then schedule them for |
| 430 // deletion at next reboot. | 430 // deletion at next reboot. |
| 431 if (!cleanup_success) { | 431 if (!cleanup_success) { |
| 432 ScheduleDirectoryForDeletion(temp_path.ToWStringHack().c_str()); | 432 ScheduleDirectoryForDeletion(temp_path.ToWStringHack().c_str()); |
| 433 if (cmd_line.HasSwitch(installer::switches::kInstallerData)) { | 433 if (cmd_line.HasSwitch(installer_util::switches::kInstallerData)) { |
| 434 std::wstring prefs_path = cmd_line.GetSwitchValueNative( | 434 std::wstring prefs_path = cmd_line.GetSwitchValueNative( |
| 435 installer::switches::kInstallerData); | 435 installer_util::switches::kInstallerData); |
| 436 ScheduleDirectoryForDeletion(prefs_path.c_str()); | 436 ScheduleDirectoryForDeletion(prefs_path.c_str()); |
| 437 } | 437 } |
| 438 } | 438 } |
| 439 | 439 |
| 440 for (size_t i = 0; i < products.size(); ++i) { | 440 for (size_t i = 0; i < products.size(); ++i) { |
| 441 const Product* product = products[i]; | 441 const Product* product = products[i]; |
| 442 product->distribution()->UpdateDiffInstallStatus(system_level, | 442 product->distribution()->UpdateDiffInstallStatus(system_level, |
| 443 incremental_install, install_status); | 443 incremental_install, install_status); |
| 444 } | 444 } |
| 445 | 445 |
| 446 return install_status; | 446 return install_status; |
| 447 } | 447 } |
| 448 | 448 |
| 449 installer::InstallStatus UninstallChrome(const CommandLine& cmd_line, | 449 installer_util::InstallStatus UninstallChrome(const CommandLine& cmd_line, |
| 450 const Product& product) { | 450 const Product& product) { |
| 451 VLOG(1) << "Uninstalling Chome"; | 451 VLOG(1) << "Uninstalling Chome"; |
| 452 | 452 |
| 453 scoped_ptr<Version> installed_version(product.GetInstalledVersion()); | 453 scoped_ptr<Version> installed_version(product.GetInstalledVersion()); |
| 454 if (installed_version.get()) | 454 if (installed_version.get()) |
| 455 VLOG(1) << "version on the system: " << installed_version->GetString(); | 455 VLOG(1) << "version on the system: " << installed_version->GetString(); |
| 456 | 456 |
| 457 bool force = cmd_line.HasSwitch(installer::switches::kForceUninstall); | 457 bool force = cmd_line.HasSwitch(installer_util::switches::kForceUninstall); |
| 458 if (!installed_version.get() && !force) { | 458 if (!installed_version.get() && !force) { |
| 459 LOG(ERROR) << "No Chrome installation found for uninstall."; | 459 LOG(ERROR) << "No Chrome installation found for uninstall."; |
| 460 product.WriteInstallerResult(installer::CHROME_NOT_INSTALLED, | 460 product.WriteInstallerResult(installer_util::CHROME_NOT_INSTALLED, |
| 461 IDS_UNINSTALL_FAILED_BASE, NULL); | 461 IDS_UNINSTALL_FAILED_BASE, NULL); |
| 462 return installer::CHROME_NOT_INSTALLED; | 462 return installer_util::CHROME_NOT_INSTALLED; |
| 463 } | 463 } |
| 464 | 464 |
| 465 bool remove_all = !cmd_line.HasSwitch( | 465 bool remove_all = !cmd_line.HasSwitch( |
| 466 installer::switches::kDoNotRemoveSharedItems); | 466 installer_util::switches::kDoNotRemoveSharedItems); |
| 467 | 467 |
| 468 return installer::UninstallChrome(cmd_line.GetProgram(), product, remove_all, | 468 return installer::UninstallChrome(cmd_line.GetProgram(), product, remove_all, |
| 469 force, cmd_line); | 469 force, cmd_line); |
| 470 } | 470 } |
| 471 | 471 |
| 472 installer::InstallStatus ShowEULADialog(const std::wstring& inner_frame) { | 472 installer_util::InstallStatus ShowEULADialog(const std::wstring& inner_frame) { |
| 473 VLOG(1) << "About to show EULA"; | 473 VLOG(1) << "About to show EULA"; |
| 474 std::wstring eula_path = installer::GetLocalizedEulaResource(); | 474 std::wstring eula_path = installer_util::GetLocalizedEulaResource(); |
| 475 if (eula_path.empty()) { | 475 if (eula_path.empty()) { |
| 476 LOG(ERROR) << "No EULA path available"; | 476 LOG(ERROR) << "No EULA path available"; |
| 477 return installer::EULA_REJECTED; | 477 return installer_util::EULA_REJECTED; |
| 478 } | 478 } |
| 479 // Newer versions of the caller pass an inner frame parameter that must | 479 // Newer versions of the caller pass an inner frame parameter that must |
| 480 // be given to the html page being launched. | 480 // be given to the html page being launched. |
| 481 if (!inner_frame.empty()) { | 481 if (!inner_frame.empty()) { |
| 482 eula_path += L"?innerframe="; | 482 eula_path += L"?innerframe="; |
| 483 eula_path += inner_frame; | 483 eula_path += inner_frame; |
| 484 } | 484 } |
| 485 installer::EulaHTMLDialog dlg(eula_path); | 485 installer::EulaHTMLDialog dlg(eula_path); |
| 486 installer::EulaHTMLDialog::Outcome outcome = dlg.ShowModal(); | 486 installer::EulaHTMLDialog::Outcome outcome = dlg.ShowModal(); |
| 487 if (installer::EulaHTMLDialog::REJECTED == outcome) { | 487 if (installer::EulaHTMLDialog::REJECTED == outcome) { |
| 488 LOG(ERROR) << "EULA rejected or EULA failure"; | 488 LOG(ERROR) << "EULA rejected or EULA failure"; |
| 489 return installer::EULA_REJECTED; | 489 return installer_util::EULA_REJECTED; |
| 490 } | 490 } |
| 491 if (installer::EulaHTMLDialog::ACCEPTED_OPT_IN == outcome) { | 491 if (installer::EulaHTMLDialog::ACCEPTED_OPT_IN == outcome) { |
| 492 VLOG(1) << "EULA accepted (opt-in)"; | 492 VLOG(1) << "EULA accepted (opt-in)"; |
| 493 return installer::EULA_ACCEPTED_OPT_IN; | 493 return installer_util::EULA_ACCEPTED_OPT_IN; |
| 494 } | 494 } |
| 495 VLOG(1) << "EULA accepted (no opt-in)"; | 495 VLOG(1) << "EULA accepted (no opt-in)"; |
| 496 return installer::EULA_ACCEPTED; | 496 return installer_util::EULA_ACCEPTED; |
| 497 } | 497 } |
| 498 | 498 |
| 499 // This method processes any command line options that make setup.exe do | 499 // This method processes any command line options that make setup.exe do |
| 500 // various tasks other than installation (renaming chrome.exe, showing eula | 500 // various tasks other than installation (renaming chrome.exe, showing eula |
| 501 // among others). This function returns true if any such command line option | 501 // among others). This function returns true if any such command line option |
| 502 // has been found and processed (so setup.exe should exit at that point). | 502 // has been found and processed (so setup.exe should exit at that point). |
| 503 bool HandleNonInstallCmdLineOptions(const CommandLine& cmd_line, | 503 bool HandleNonInstallCmdLineOptions(const CommandLine& cmd_line, |
| 504 int& exit_code, | 504 int& exit_code, |
| 505 const ProductPackageMapping& installs) { | 505 const ProductPackageMapping& installs) { |
| 506 DCHECK(installs.products().size()); | 506 DCHECK(installs.products().size()); |
| 507 if (cmd_line.HasSwitch(installer::switches::kUpdateSetupExe)) { | 507 if (cmd_line.HasSwitch(installer_util::switches::kUpdateSetupExe)) { |
| 508 installer::InstallStatus status = installer::SETUP_PATCH_FAILED; | 508 installer_util::InstallStatus status = installer_util::SETUP_PATCH_FAILED; |
| 509 // If --update-setup-exe command line option is given, we apply the given | 509 // If --update-setup-exe command line option is given, we apply the given |
| 510 // patch to current exe, and store the resulting binary in the path | 510 // patch to current exe, and store the resulting binary in the path |
| 511 // specified by --new-setup-exe. But we need to first unpack the file | 511 // specified by --new-setup-exe. But we need to first unpack the file |
| 512 // given in --update-setup-exe. | 512 // given in --update-setup-exe. |
| 513 FilePath temp_path; | 513 FilePath temp_path; |
| 514 if (!file_util::CreateNewTempDirectory(L"chrome_", &temp_path)) { | 514 if (!file_util::CreateNewTempDirectory(L"chrome_", &temp_path)) { |
| 515 LOG(ERROR) << "Could not create temporary path."; | 515 LOG(ERROR) << "Could not create temporary path."; |
| 516 } else { | 516 } else { |
| 517 std::wstring setup_patch = cmd_line.GetSwitchValueNative( | 517 std::wstring setup_patch = cmd_line.GetSwitchValueNative( |
| 518 installer::switches::kUpdateSetupExe); | 518 installer_util::switches::kUpdateSetupExe); |
| 519 VLOG(1) << "Opening archive " << setup_patch; | 519 VLOG(1) << "Opening archive " << setup_patch; |
| 520 std::wstring uncompressed_patch; | 520 std::wstring uncompressed_patch; |
| 521 if (LzmaUtil::UnPackArchive(setup_patch, temp_path.ToWStringHack(), | 521 if (LzmaUtil::UnPackArchive(setup_patch, temp_path.ToWStringHack(), |
| 522 &uncompressed_patch) == NO_ERROR) { | 522 &uncompressed_patch) == NO_ERROR) { |
| 523 FilePath old_setup_exe = cmd_line.GetProgram(); | 523 FilePath old_setup_exe = cmd_line.GetProgram(); |
| 524 FilePath new_setup_exe = cmd_line.GetSwitchValuePath( | 524 FilePath new_setup_exe = cmd_line.GetSwitchValuePath( |
| 525 installer::switches::kNewSetupExe); | 525 installer_util::switches::kNewSetupExe); |
| 526 if (!installer::ApplyDiffPatch(old_setup_exe, | 526 if (!setup_util::ApplyDiffPatch(old_setup_exe, |
| 527 FilePath(uncompressed_patch), | 527 FilePath(uncompressed_patch), |
| 528 new_setup_exe)) | 528 new_setup_exe)) |
| 529 status = installer::NEW_VERSION_UPDATED; | 529 status = installer_util::NEW_VERSION_UPDATED; |
| 530 } | 530 } |
| 531 } | 531 } |
| 532 | 532 |
| 533 exit_code = BrowserDistribution::GetInstallReturnCode(status); | 533 exit_code = BrowserDistribution::GetInstallReturnCode(status); |
| 534 if (exit_code) { | 534 if (exit_code) { |
| 535 LOG(WARNING) << "setup.exe patching failed."; | 535 LOG(WARNING) << "setup.exe patching failed."; |
| 536 WriteInstallerResult(installs.products(), status, | 536 WriteInstallerResult(installs.products(), status, |
| 537 IDS_SETUP_PATCH_FAILED_BASE, NULL); | 537 IDS_SETUP_PATCH_FAILED_BASE, NULL); |
| 538 } | 538 } |
| 539 file_util::Delete(temp_path, true); | 539 file_util::Delete(temp_path, true); |
| 540 return true; | 540 return true; |
| 541 } else if (cmd_line.HasSwitch(installer::switches::kShowEula)) { | 541 } else if (cmd_line.HasSwitch(installer_util::switches::kShowEula)) { |
| 542 // Check if we need to show the EULA. If it is passed as a command line | 542 // Check if we need to show the EULA. If it is passed as a command line |
| 543 // then the dialog is shown and regardless of the outcome setup exits here. | 543 // then the dialog is shown and regardless of the outcome setup exits here. |
| 544 std::wstring inner_frame = | 544 std::wstring inner_frame = |
| 545 cmd_line.GetSwitchValueNative(installer::switches::kShowEula); | 545 cmd_line.GetSwitchValueNative(installer_util::switches::kShowEula); |
| 546 exit_code = ShowEULADialog(inner_frame); | 546 exit_code = ShowEULADialog(inner_frame); |
| 547 if (installer::EULA_REJECTED != exit_code) | 547 if (installer_util::EULA_REJECTED != exit_code) |
| 548 GoogleUpdateSettings::SetEULAConsent(true); | 548 GoogleUpdateSettings::SetEULAConsent(true); |
| 549 return true; | 549 return true; |
| 550 } else if (cmd_line.HasSwitch( | 550 } else if (cmd_line.HasSwitch( |
| 551 installer::switches::kRegisterChromeBrowser)) { | 551 installer_util::switches::kRegisterChromeBrowser)) { |
| 552 const Product* chrome_install = | 552 const Product* chrome_install = |
| 553 FindProduct(installs.products(), BrowserDistribution::CHROME_BROWSER); | 553 FindProduct(installs.products(), BrowserDistribution::CHROME_BROWSER); |
| 554 DCHECK(chrome_install); | 554 DCHECK(chrome_install); |
| 555 if (chrome_install) { | 555 if (chrome_install) { |
| 556 // If --register-chrome-browser option is specified, register all | 556 // If --register-chrome-browser option is specified, register all |
| 557 // Chrome protocol/file associations as well as register it as a valid | 557 // Chrome protocol/file associations as well as register it as a valid |
| 558 // browser for Start Menu->Internet shortcut. This option should only | 558 // browser for Start Menu->Internet shortcut. This option should only |
| 559 // be used when setup.exe is launched with admin rights. We do not | 559 // be used when setup.exe is launched with admin rights. We do not |
| 560 // make any user specific changes in this option. | 560 // make any user specific changes in this option. |
| 561 std::wstring chrome_exe(cmd_line.GetSwitchValueNative( | 561 std::wstring chrome_exe(cmd_line.GetSwitchValueNative( |
| 562 installer::switches::kRegisterChromeBrowser)); | 562 installer_util::switches::kRegisterChromeBrowser)); |
| 563 std::wstring suffix; | 563 std::wstring suffix; |
| 564 if (cmd_line.HasSwitch( | 564 if (cmd_line.HasSwitch( |
| 565 installer::switches::kRegisterChromeBrowserSuffix)) { | 565 installer_util::switches::kRegisterChromeBrowserSuffix)) { |
| 566 suffix = cmd_line.GetSwitchValueNative( | 566 suffix = cmd_line.GetSwitchValueNative( |
| 567 installer::switches::kRegisterChromeBrowserSuffix); | 567 installer_util::switches::kRegisterChromeBrowserSuffix); |
| 568 } | 568 } |
| 569 exit_code = ShellUtil::RegisterChromeBrowser( | 569 exit_code = ShellUtil::RegisterChromeBrowser( |
| 570 chrome_install->distribution(), chrome_exe, suffix, false); | 570 chrome_install->distribution(), chrome_exe, suffix, false); |
| 571 } else { | 571 } else { |
| 572 LOG(ERROR) << "Can't register browser - Chrome distribution not found"; | 572 LOG(ERROR) << "Can't register browser - Chrome distribution not found"; |
| 573 exit_code = installer::UNKNOWN_STATUS; | 573 exit_code = installer_util::UNKNOWN_STATUS; |
| 574 } | 574 } |
| 575 return true; | 575 return true; |
| 576 } else if (cmd_line.HasSwitch(installer::switches::kRenameChromeExe)) { | 576 } else if (cmd_line.HasSwitch(installer_util::switches::kRenameChromeExe)) { |
| 577 // If --rename-chrome-exe is specified, we want to rename the executables | 577 // If --rename-chrome-exe is specified, we want to rename the executables |
| 578 // and exit. | 578 // and exit. |
| 579 const Packages& packages = installs.packages(); | 579 const Packages& packages = installs.packages(); |
| 580 DCHECK_EQ(1U, packages.size()); | 580 DCHECK_EQ(1U, packages.size()); |
| 581 for (size_t i = 0; i < packages.size(); ++i) | 581 for (size_t i = 0; i < packages.size(); ++i) |
| 582 exit_code = RenameChromeExecutables(*packages[i].get()); | 582 exit_code = RenameChromeExecutables(*packages[i].get()); |
| 583 return true; | 583 return true; |
| 584 } else if (cmd_line.HasSwitch( | 584 } else if (cmd_line.HasSwitch( |
| 585 installer::switches::kRemoveChromeRegistration)) { | 585 installer_util::switches::kRemoveChromeRegistration)) { |
| 586 // This is almost reverse of --register-chrome-browser option above. | 586 // This is almost reverse of --register-chrome-browser option above. |
| 587 // Here we delete Chrome browser registration. This option should only | 587 // Here we delete Chrome browser registration. This option should only |
| 588 // be used when setup.exe is launched with admin rights. We do not | 588 // be used when setup.exe is launched with admin rights. We do not |
| 589 // make any user specific changes in this option. | 589 // make any user specific changes in this option. |
| 590 std::wstring suffix; | 590 std::wstring suffix; |
| 591 if (cmd_line.HasSwitch( | 591 if (cmd_line.HasSwitch( |
| 592 installer::switches::kRegisterChromeBrowserSuffix)) { | 592 installer_util::switches::kRegisterChromeBrowserSuffix)) { |
| 593 suffix = cmd_line.GetSwitchValueNative( | 593 suffix = cmd_line.GetSwitchValueNative( |
| 594 installer::switches::kRegisterChromeBrowserSuffix); | 594 installer_util::switches::kRegisterChromeBrowserSuffix); |
| 595 } | 595 } |
| 596 installer::InstallStatus tmp = installer::UNKNOWN_STATUS; | 596 installer_util::InstallStatus tmp = installer_util::UNKNOWN_STATUS; |
| 597 const Product* chrome_install = | 597 const Product* chrome_install = |
| 598 FindProduct(installs.products(), BrowserDistribution::CHROME_BROWSER); | 598 FindProduct(installs.products(), BrowserDistribution::CHROME_BROWSER); |
| 599 DCHECK(chrome_install); | 599 DCHECK(chrome_install); |
| 600 if (chrome_install) { | 600 if (chrome_install) { |
| 601 installer::DeleteChromeRegistrationKeys(chrome_install->distribution(), | 601 installer::DeleteChromeRegistrationKeys(chrome_install->distribution(), |
| 602 HKEY_LOCAL_MACHINE, suffix, tmp); | 602 HKEY_LOCAL_MACHINE, suffix, tmp); |
| 603 } | 603 } |
| 604 exit_code = tmp; | 604 exit_code = tmp; |
| 605 return true; | 605 return true; |
| 606 } else if (cmd_line.HasSwitch(installer::switches::kInactiveUserToast)) { | 606 } else if (cmd_line.HasSwitch(installer_util::switches::kInactiveUserToast)) { |
| 607 // Launch the inactive user toast experiment. | 607 // Launch the inactive user toast experiment. |
| 608 int flavor = -1; | 608 int flavor = -1; |
| 609 base::StringToInt(cmd_line.GetSwitchValueNative( | 609 base::StringToInt(cmd_line.GetSwitchValueNative( |
| 610 installer::switches::kInactiveUserToast), &flavor); | 610 installer_util::switches::kInactiveUserToast), &flavor); |
| 611 DCHECK_NE(-1, flavor); | 611 DCHECK_NE(-1, flavor); |
| 612 if (flavor == -1) { | 612 if (flavor == -1) { |
| 613 exit_code = installer::UNKNOWN_STATUS; | 613 exit_code = installer_util::UNKNOWN_STATUS; |
| 614 } else { | 614 } else { |
| 615 const Products& products = installs.products(); | 615 const Products& products = installs.products(); |
| 616 for (size_t i = 0; i < products.size(); ++i) { | 616 for (size_t i = 0; i < products.size(); ++i) { |
| 617 const Product* product = products[i]; | 617 const Product* product = products[i]; |
| 618 BrowserDistribution* browser_dist = product->distribution(); | 618 BrowserDistribution* browser_dist = product->distribution(); |
| 619 browser_dist->InactiveUserToastExperiment(flavor, *product); | 619 browser_dist->InactiveUserToastExperiment(flavor, *product); |
| 620 } | 620 } |
| 621 } | 621 } |
| 622 return true; | 622 return true; |
| 623 } else if (cmd_line.HasSwitch(installer::switches::kSystemLevelToast)) { | 623 } else if (cmd_line.HasSwitch(installer_util::switches::kSystemLevelToast)) { |
| 624 const Products& products = installs.products(); | 624 const Products& products = installs.products(); |
| 625 for (size_t i = 0; i < products.size(); ++i) { | 625 for (size_t i = 0; i < products.size(); ++i) { |
| 626 const Product* product = products[i]; | 626 const Product* product = products[i]; |
| 627 BrowserDistribution* browser_dist = product->distribution(); | 627 BrowserDistribution* browser_dist = product->distribution(); |
| 628 // We started as system-level and have been re-launched as user level | 628 // We started as system-level and have been re-launched as user level |
| 629 // to continue with the toast experiment. | 629 // to continue with the toast experiment. |
| 630 scoped_ptr<Version> installed_version( | 630 scoped_ptr<Version> installed_version( |
| 631 InstallUtil::GetChromeVersion(browser_dist, installs.system_level())); | 631 InstallUtil::GetChromeVersion(browser_dist, installs.system_level())); |
| 632 browser_dist->LaunchUserExperiment(installer::REENTRY_SYS_UPDATE, | 632 browser_dist->LaunchUserExperiment(installer_util::REENTRY_SYS_UPDATE, |
| 633 *installed_version, *product, true); | 633 *installed_version, *product, true); |
| 634 } | 634 } |
| 635 return true; | 635 return true; |
| 636 } | 636 } |
| 637 return false; | 637 return false; |
| 638 } | 638 } |
| 639 | 639 |
| 640 bool ShowRebootDialog() { | 640 bool ShowRebootDialog() { |
| 641 // Get a token for this process. | 641 // Get a token for this process. |
| 642 HANDLE token; | 642 HANDLE token; |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 707 | 707 |
| 708 } // namespace | 708 } // namespace |
| 709 | 709 |
| 710 int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, | 710 int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prev_instance, |
| 711 wchar_t* command_line, int show_command) { | 711 wchar_t* command_line, int show_command) { |
| 712 // The exit manager is in charge of calling the dtors of singletons. | 712 // The exit manager is in charge of calling the dtors of singletons. |
| 713 base::AtExitManager exit_manager; | 713 base::AtExitManager exit_manager; |
| 714 CommandLine::Init(0, NULL); | 714 CommandLine::Init(0, NULL); |
| 715 | 715 |
| 716 const MasterPreferences& prefs = | 716 const MasterPreferences& prefs = |
| 717 installer::MasterPreferences::ForCurrentProcess(); | 717 installer_util::MasterPreferences::ForCurrentProcess(); |
| 718 installer::InitInstallerLogging(prefs); | 718 installer::InitInstallerLogging(prefs); |
| 719 | 719 |
| 720 const CommandLine& cmd_line = *CommandLine::ForCurrentProcess(); | 720 const CommandLine& cmd_line = *CommandLine::ForCurrentProcess(); |
| 721 VLOG(1) << "Command Line: " << cmd_line.command_line_string(); | 721 VLOG(1) << "Command Line: " << cmd_line.command_line_string(); |
| 722 | 722 |
| 723 bool system_install = false; | 723 bool system_install = false; |
| 724 prefs.GetBool(installer::master_preferences::kSystemLevel, | 724 prefs.GetBool(installer_util::master_preferences::kSystemLevel, |
| 725 &system_install); | 725 &system_install); |
| 726 VLOG(1) << "system install is " << system_install; | 726 VLOG(1) << "system install is " << system_install; |
| 727 | 727 |
| 728 ProductPackageMapping installations(system_install); | 728 ProductPackageMapping installations(system_install); |
| 729 PopulateInstallations(prefs, &installations); | 729 PopulateInstallations(prefs, &installations); |
| 730 | 730 |
| 731 // Check to make sure current system is WinXP or later. If not, log | 731 // Check to make sure current system is WinXP or later. If not, log |
| 732 // error message and get out. | 732 // error message and get out. |
| 733 if (!InstallUtil::IsOSSupported()) { | 733 if (!InstallUtil::IsOSSupported()) { |
| 734 LOG(ERROR) << "Chrome only supports Windows XP or later."; | 734 LOG(ERROR) << "Chrome only supports Windows XP or later."; |
| 735 WriteInstallerResult(installations.products(), | 735 WriteInstallerResult(installations.products(), |
| 736 installer::OS_NOT_SUPPORTED, IDS_INSTALL_OS_NOT_SUPPORTED_BASE, | 736 installer_util::OS_NOT_SUPPORTED, IDS_INSTALL_OS_NOT_SUPPORTED_BASE, |
| 737 NULL); | 737 NULL); |
| 738 return installer::OS_NOT_SUPPORTED; | 738 return installer_util::OS_NOT_SUPPORTED; |
| 739 } | 739 } |
| 740 | 740 |
| 741 // Initialize COM for use later. | 741 // Initialize COM for use later. |
| 742 AutoCom auto_com; | 742 AutoCom auto_com; |
| 743 if (!auto_com.Init(system_install)) { | 743 if (!auto_com.Init(system_install)) { |
| 744 WriteInstallerResult(installations.products(), | 744 WriteInstallerResult(installations.products(), |
| 745 installer::OS_ERROR, IDS_INSTALL_OS_ERROR_BASE, NULL); | 745 installer_util::OS_ERROR, IDS_INSTALL_OS_ERROR_BASE, NULL); |
| 746 return installer::OS_ERROR; | 746 return installer_util::OS_ERROR; |
| 747 } | 747 } |
| 748 | 748 |
| 749 // Some command line options don't work with SxS install/uninstall | 749 // Some command line options don't work with SxS install/uninstall |
| 750 if (InstallUtil::IsChromeSxSProcess()) { | 750 if (InstallUtil::IsChromeSxSProcess()) { |
| 751 if (system_install || | 751 if (system_install || |
| 752 cmd_line.HasSwitch(installer::switches::kForceUninstall) || | 752 cmd_line.HasSwitch(installer_util::switches::kForceUninstall) || |
| 753 cmd_line.HasSwitch(installer::switches::kMakeChromeDefault) || | 753 cmd_line.HasSwitch(installer_util::switches::kMakeChromeDefault) || |
| 754 cmd_line.HasSwitch(installer::switches::kRegisterChromeBrowser) || | 754 cmd_line.HasSwitch(installer_util::switches::kRegisterChromeBrowser) || |
| 755 cmd_line.HasSwitch( | 755 cmd_line.HasSwitch( |
| 756 installer::switches::kRemoveChromeRegistration) || | 756 installer_util::switches::kRemoveChromeRegistration) || |
| 757 cmd_line.HasSwitch(installer::switches::kInactiveUserToast) || | 757 cmd_line.HasSwitch(installer_util::switches::kInactiveUserToast) || |
| 758 cmd_line.HasSwitch(installer::switches::kSystemLevelToast)) { | 758 cmd_line.HasSwitch(installer_util::switches::kSystemLevelToast)) { |
| 759 return installer::SXS_OPTION_NOT_SUPPORTED; | 759 return installer_util::SXS_OPTION_NOT_SUPPORTED; |
| 760 } | 760 } |
| 761 } | 761 } |
| 762 | 762 |
| 763 int exit_code = 0; | 763 int exit_code = 0; |
| 764 if (HandleNonInstallCmdLineOptions(cmd_line, exit_code, installations)) | 764 if (HandleNonInstallCmdLineOptions(cmd_line, exit_code, installations)) |
| 765 return exit_code; | 765 return exit_code; |
| 766 | 766 |
| 767 if (system_install && !IsUserAnAdmin()) { | 767 if (system_install && !IsUserAnAdmin()) { |
| 768 if (base::win::GetVersion() >= base::win::VERSION_VISTA && | 768 if (base::win::GetVersion() >= base::win::VERSION_VISTA && |
| 769 !cmd_line.HasSwitch(installer::switches::kRunAsAdmin)) { | 769 !cmd_line.HasSwitch(installer_util::switches::kRunAsAdmin)) { |
| 770 CommandLine new_cmd(CommandLine::NO_PROGRAM); | 770 CommandLine new_cmd(CommandLine::NO_PROGRAM); |
| 771 new_cmd.AppendArguments(cmd_line, true); | 771 new_cmd.AppendArguments(cmd_line, true); |
| 772 // Append --run-as-admin flag to let the new instance of setup.exe know | 772 // Append --run-as-admin flag to let the new instance of setup.exe know |
| 773 // that we already tried to launch ourselves as admin. | 773 // that we already tried to launch ourselves as admin. |
| 774 new_cmd.AppendSwitch(installer::switches::kRunAsAdmin); | 774 new_cmd.AppendSwitch(installer_util::switches::kRunAsAdmin); |
| 775 DWORD exit_code = installer::UNKNOWN_STATUS; | 775 DWORD exit_code = installer_util::UNKNOWN_STATUS; |
| 776 InstallUtil::ExecuteExeAsAdmin(new_cmd, &exit_code); | 776 InstallUtil::ExecuteExeAsAdmin(new_cmd, &exit_code); |
| 777 return exit_code; | 777 return exit_code; |
| 778 } else { | 778 } else { |
| 779 LOG(ERROR) << "Non admin user can not install system level Chrome."; | 779 LOG(ERROR) << "Non admin user can not install system level Chrome."; |
| 780 WriteInstallerResult(installations.products(), | 780 WriteInstallerResult(installations.products(), |
| 781 installer::INSUFFICIENT_RIGHTS, | 781 installer_util::INSUFFICIENT_RIGHTS, |
| 782 IDS_INSTALL_INSUFFICIENT_RIGHTS_BASE, NULL); | 782 IDS_INSTALL_INSUFFICIENT_RIGHTS_BASE, NULL); |
| 783 return installer::INSUFFICIENT_RIGHTS; | 783 return installer_util::INSUFFICIENT_RIGHTS; |
| 784 } | 784 } |
| 785 } | 785 } |
| 786 | 786 |
| 787 bool is_uninstall = cmd_line.HasSwitch(installer::switches::kUninstall); | 787 bool is_uninstall = cmd_line.HasSwitch(installer_util::switches::kUninstall); |
| 788 | 788 |
| 789 installer::InstallStatus install_status = installer::UNKNOWN_STATUS; | 789 installer_util::InstallStatus install_status = installer_util::UNKNOWN_STATUS; |
| 790 // If --uninstall option is given, uninstall chrome | 790 // If --uninstall option is given, uninstall chrome |
| 791 if (is_uninstall) { | 791 if (is_uninstall) { |
| 792 DCHECK_EQ(1U, installations.products().size()) << | 792 DCHECK_EQ(1U, installations.products().size()) << |
| 793 "We currently really only support uninstalling one distribution " | 793 "We currently really only support uninstalling one distribution " |
| 794 "at a time"; | 794 "at a time"; |
| 795 for (size_t i = 0; i < installations.products().size(); ++i) { | 795 for (size_t i = 0; i < installations.products().size(); ++i) { |
| 796 install_status = UninstallChrome(cmd_line, | 796 install_status = UninstallChrome(cmd_line, |
| 797 *installations.products()[i]); | 797 *installations.products()[i]); |
| 798 } | 798 } |
| 799 } else { | 799 } else { |
| 800 // If --uninstall option is not specified, we assume it is install case. | 800 // If --uninstall option is not specified, we assume it is install case. |
| 801 const Packages& packages = installations.packages(); | 801 const Packages& packages = installations.packages(); |
| 802 VLOG(1) << "Installing to " << packages.size() << " target paths"; | 802 VLOG(1) << "Installing to " << packages.size() << " target paths"; |
| 803 for (size_t i = 0; i < packages.size(); ++i) { | 803 for (size_t i = 0; i < packages.size(); ++i) { |
| 804 install_status = InstallChrome(cmd_line, *packages[i].get(), prefs); | 804 install_status = InstallChrome(cmd_line, *packages[i].get(), prefs); |
| 805 } | 805 } |
| 806 } | 806 } |
| 807 | 807 |
| 808 const Product* cf_install = | 808 const Product* cf_install = |
| 809 FindProduct(installations.products(), BrowserDistribution::CHROME_FRAME); | 809 FindProduct(installations.products(), BrowserDistribution::CHROME_FRAME); |
| 810 | 810 |
| 811 if (cf_install && | 811 if (cf_install && |
| 812 !cmd_line.HasSwitch(installer::switches::kForceUninstall)) { | 812 !cmd_line.HasSwitch(installer_util::switches::kForceUninstall)) { |
| 813 if (install_status == installer::UNINSTALL_REQUIRES_REBOOT) { | 813 if (install_status == installer_util::UNINSTALL_REQUIRES_REBOOT) { |
| 814 ShowRebootDialog(); | 814 ShowRebootDialog(); |
| 815 } else if (is_uninstall) { | 815 } else if (is_uninstall) { |
| 816 ::MessageBoxW(NULL, | 816 ::MessageBoxW(NULL, |
| 817 installer::GetLocalizedString( | 817 installer_util::GetLocalizedString( |
| 818 IDS_UNINSTALL_COMPLETE_BASE).c_str(), | 818 IDS_UNINSTALL_COMPLETE_BASE).c_str(), |
| 819 cf_install->distribution()->GetApplicationName().c_str(), | 819 cf_install->distribution()->GetApplicationName().c_str(), |
| 820 MB_OK); | 820 MB_OK); |
| 821 } | 821 } |
| 822 } | 822 } |
| 823 | 823 |
| 824 int return_code = 0; | 824 int return_code = 0; |
| 825 // MSI demands that custom actions always return 0 (ERROR_SUCCESS) or it will | 825 // MSI demands that custom actions always return 0 (ERROR_SUCCESS) or it will |
| 826 // rollback the action. If we're uninstalling we want to avoid this, so always | 826 // rollback the action. If we're uninstalling we want to avoid this, so always |
| 827 // report success, squashing any more informative return codes. | 827 // report success, squashing any more informative return codes. |
| 828 // TODO(tommi): Fix this loop when IsMsi has been moved out of the Product | 828 // TODO(tommi): Fix this loop when IsMsi has been moved out of the Product |
| 829 // class. | 829 // class. |
| 830 for (size_t i = 0; i < installations.products().size(); ++i) { | 830 for (size_t i = 0; i < installations.products().size(); ++i) { |
| 831 const Product* product = installations.products()[i]; | 831 const Product* product = installations.products()[i]; |
| 832 if (!(product->IsMsi() && is_uninstall)) { | 832 if (!(product->IsMsi() && is_uninstall)) { |
| 833 // Note that we allow the status installer::UNINSTALL_REQUIRES_REBOOT | 833 // Note that we allow the status installer_util::UNINSTALL_REQUIRES_REBOOT |
| 834 // to pass through, since this is only returned on uninstall which is | 834 // to pass through, since this is only returned on uninstall which is |
| 835 // never invoked directly by Google Update. | 835 // never invoked directly by Google Update. |
| 836 return_code = BrowserDistribution::GetInstallReturnCode(install_status); | 836 return_code = BrowserDistribution::GetInstallReturnCode(install_status); |
| 837 } | 837 } |
| 838 } | 838 } |
| 839 | 839 |
| 840 VLOG(1) << "Installation complete, returning: " << return_code; | 840 VLOG(1) << "Installation complete, returning: " << return_code; |
| 841 | 841 |
| 842 return return_code; | 842 return return_code; |
| 843 } | 843 } |
| OLD | NEW |