| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 12 matching lines...) Expand all Loading... |
| 23 #include "base/values.h" | 23 #include "base/values.h" |
| 24 #include "base/win/registry.h" | 24 #include "base/win/registry.h" |
| 25 #include "base/win/scoped_handle.h" | 25 #include "base/win/scoped_handle.h" |
| 26 #include "base/win/win_util.h" | 26 #include "base/win/win_util.h" |
| 27 #include "base/win/windows_version.h" | 27 #include "base/win/windows_version.h" |
| 28 #include "breakpad/src/client/windows/handler/exception_handler.h" | 28 #include "breakpad/src/client/windows/handler/exception_handler.h" |
| 29 #include "chrome/common/chrome_switches.h" | 29 #include "chrome/common/chrome_switches.h" |
| 30 #include "chrome/installer/setup/chrome_frame_quick_enable.h" | 30 #include "chrome/installer/setup/chrome_frame_quick_enable.h" |
| 31 #include "chrome/installer/setup/chrome_frame_ready_mode.h" | 31 #include "chrome/installer/setup/chrome_frame_ready_mode.h" |
| 32 #include "chrome/installer/setup/install.h" | 32 #include "chrome/installer/setup/install.h" |
| 33 #include "chrome/installer/setup/install_worker.h" |
| 33 #include "chrome/installer/setup/setup_constants.h" | 34 #include "chrome/installer/setup/setup_constants.h" |
| 34 #include "chrome/installer/setup/setup_util.h" | 35 #include "chrome/installer/setup/setup_util.h" |
| 35 #include "chrome/installer/setup/uninstall.h" | 36 #include "chrome/installer/setup/uninstall.h" |
| 36 #include "chrome/installer/util/browser_distribution.h" | 37 #include "chrome/installer/util/browser_distribution.h" |
| 37 #include "chrome/installer/util/channel_info.h" | 38 #include "chrome/installer/util/channel_info.h" |
| 38 #include "chrome/installer/util/delete_after_reboot_helper.h" | 39 #include "chrome/installer/util/delete_after_reboot_helper.h" |
| 39 #include "chrome/installer/util/delete_tree_work_item.h" | 40 #include "chrome/installer/util/delete_tree_work_item.h" |
| 40 #include "chrome/installer/util/google_update_constants.h" | 41 #include "chrome/installer/util/google_update_constants.h" |
| 41 #include "chrome/installer/util/google_update_settings.h" | 42 #include "chrome/installer/util/google_update_settings.h" |
| 42 #include "chrome/installer/util/helper.h" | 43 #include "chrome/installer/util/helper.h" |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 162 } | 163 } |
| 163 } | 164 } |
| 164 } | 165 } |
| 165 } | 166 } |
| 166 | 167 |
| 167 // This function is called when --rename-chrome-exe option is specified on | 168 // This function is called when --rename-chrome-exe option is specified on |
| 168 // setup.exe command line. This function assumes an in-use update has happened | 169 // setup.exe command line. This function assumes an in-use update has happened |
| 169 // for Chrome so there should be a file called new_chrome.exe on the file | 170 // for Chrome so there should be a file called new_chrome.exe on the file |
| 170 // system and a key called 'opv' in the registry. This function will move | 171 // system and a key called 'opv' in the registry. This function will move |
| 171 // new_chrome.exe to chrome.exe and delete 'opv' key in one atomic operation. | 172 // new_chrome.exe to chrome.exe and delete 'opv' key in one atomic operation. |
| 173 // This function also deletes elevation policies associated with the old version |
| 174 // if they exist. |
| 172 installer::InstallStatus RenameChromeExecutables( | 175 installer::InstallStatus RenameChromeExecutables( |
| 173 const InstallationState& original_state, | 176 const InstallationState& original_state, |
| 174 InstallerState* installer_state) { | 177 InstallerState* installer_state) { |
| 175 // See what products are already installed in multi mode. When we do the | 178 // See what products are already installed in multi mode. When we do the |
| 176 // rename for multi installs, we must update all installations since they | 179 // rename for multi installs, we must update all installations since they |
| 177 // share the binaries. | 180 // share the binaries. |
| 178 AddExistingMultiInstalls(original_state, installer_state); | 181 AddExistingMultiInstalls(original_state, installer_state); |
| 179 const FilePath &target_path = installer_state->target_path(); | 182 const FilePath &target_path = installer_state->target_path(); |
| 180 FilePath chrome_exe(target_path.Append(installer::kChromeExe)); | 183 FilePath chrome_exe(target_path.Append(installer::kChromeExe)); |
| 181 FilePath chrome_new_exe(target_path.Append(installer::kChromeNewExe)); | 184 FilePath chrome_new_exe(target_path.Append(installer::kChromeNewExe)); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 195 // Move chrome.exe to old_chrome.exe, then move new_chrome.exe to chrome.exe. | 198 // Move chrome.exe to old_chrome.exe, then move new_chrome.exe to chrome.exe. |
| 196 install_list->AddMoveTreeWorkItem(chrome_exe.value(), | 199 install_list->AddMoveTreeWorkItem(chrome_exe.value(), |
| 197 chrome_old_exe.value(), | 200 chrome_old_exe.value(), |
| 198 temp_path.path().value(), | 201 temp_path.path().value(), |
| 199 WorkItem::ALWAYS_MOVE); | 202 WorkItem::ALWAYS_MOVE); |
| 200 install_list->AddMoveTreeWorkItem(chrome_new_exe.value(), | 203 install_list->AddMoveTreeWorkItem(chrome_new_exe.value(), |
| 201 chrome_exe.value(), | 204 chrome_exe.value(), |
| 202 temp_path.path().value(), | 205 temp_path.path().value(), |
| 203 WorkItem::ALWAYS_MOVE); | 206 WorkItem::ALWAYS_MOVE); |
| 204 install_list->AddDeleteTreeWorkItem(chrome_new_exe, temp_path.path()); | 207 install_list->AddDeleteTreeWorkItem(chrome_new_exe, temp_path.path()); |
| 208 // Delete an elevation policy associated with the old version, should one |
| 209 // exist. |
| 210 if (installer_state->FindProduct(BrowserDistribution::CHROME_FRAME)) { |
| 211 installer::AddDeleteOldIELowRightsPolicyWorkItems(*installer_state, |
| 212 install_list.get()); |
| 213 } |
| 205 // old_chrome.exe is still in use in most cases, so ignore failures here. | 214 // old_chrome.exe is still in use in most cases, so ignore failures here. |
| 206 install_list->AddDeleteTreeWorkItem(chrome_old_exe, temp_path.path()) | 215 install_list->AddDeleteTreeWorkItem(chrome_old_exe, temp_path.path()) |
| 207 ->set_ignore_failure(true); | 216 ->set_ignore_failure(true); |
| 208 | 217 |
| 209 // Collect the set of distributions we need to update, which is the | 218 // Collect the set of distributions we need to update, which is the |
| 210 // multi-install binaries (if this is a multi-install operation) and all | 219 // multi-install binaries (if this is a multi-install operation) and all |
| 211 // products we're operating on. | 220 // products we're operating on. |
| 212 BrowserDistribution* dists[BrowserDistribution::NUM_TYPES]; | 221 BrowserDistribution* dists[BrowserDistribution::NUM_TYPES]; |
| 213 int num_dists = 0; | 222 int num_dists = 0; |
| 214 // First, add the multi-install binaries, if relevant. | 223 // First, add the multi-install binaries, if relevant. |
| (...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 583 VLOG(1) << "unpacked to " << unpack_path.value(); | 592 VLOG(1) << "unpacked to " << unpack_path.value(); |
| 584 FilePath src_path(unpack_path.Append(installer::kInstallSourceChromeDir)); | 593 FilePath src_path(unpack_path.Append(installer::kInstallSourceChromeDir)); |
| 585 scoped_ptr<Version> | 594 scoped_ptr<Version> |
| 586 installer_version(installer::GetMaxVersionFromArchiveDir(src_path)); | 595 installer_version(installer::GetMaxVersionFromArchiveDir(src_path)); |
| 587 if (!installer_version.get()) { | 596 if (!installer_version.get()) { |
| 588 LOG(ERROR) << "Did not find any valid version in installer."; | 597 LOG(ERROR) << "Did not find any valid version in installer."; |
| 589 install_status = installer::INVALID_ARCHIVE; | 598 install_status = installer::INVALID_ARCHIVE; |
| 590 installer_state.WriteInstallerResult(install_status, | 599 installer_state.WriteInstallerResult(install_status, |
| 591 IDS_INSTALL_INVALID_ARCHIVE_BASE, NULL); | 600 IDS_INSTALL_INVALID_ARCHIVE_BASE, NULL); |
| 592 } else { | 601 } else { |
| 593 // TODO(tommi): Move towards having only a single version that is common | |
| 594 // to all products. Only the package should have a version since it | |
| 595 // represents all the binaries. When a single product is upgraded, all | |
| 596 // currently installed product for the shared binary installation, should | |
| 597 // (or rather must) be upgraded. | |
| 598 VLOG(1) << "version to install: " << installer_version->GetString(); | 602 VLOG(1) << "version to install: " << installer_version->GetString(); |
| 599 bool proceed_with_installation = true; | 603 bool proceed_with_installation = true; |
| 600 for (size_t i = 0; i < installer_state.products().size(); ++i) { | 604 for (size_t i = 0; i < installer_state.products().size(); ++i) { |
| 601 const Product* product = installer_state.products()[i]; | 605 const Product* product = installer_state.products()[i]; |
| 602 const ProductState* product_state = | 606 const ProductState* product_state = |
| 603 original_state.GetProductState(system_install, | 607 original_state.GetProductState(system_install, |
| 604 product->distribution()->GetType()); | 608 product->distribution()->GetType()); |
| 605 if (product_state != NULL && | 609 if (product_state != NULL && |
| 606 (product_state->version().CompareTo(*installer_version) > 0)) { | 610 (product_state->version().CompareTo(*installer_version) > 0)) { |
| 607 LOG(ERROR) << "Higher version is already installed."; | 611 LOG(ERROR) << "Higher version is already installed."; |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 782 } | 786 } |
| 783 | 787 |
| 784 installer_state->UpdateStage(installer::NO_STAGE); | 788 installer_state->UpdateStage(installer::NO_STAGE); |
| 785 return install_status; | 789 return install_status; |
| 786 } | 790 } |
| 787 | 791 |
| 788 installer::InstallStatus UninstallProduct( | 792 installer::InstallStatus UninstallProduct( |
| 789 const InstallationState& original_state, | 793 const InstallationState& original_state, |
| 790 const InstallerState& installer_state, | 794 const InstallerState& installer_state, |
| 791 const CommandLine& cmd_line, | 795 const CommandLine& cmd_line, |
| 796 bool remove_all, |
| 797 bool force_uninstall, |
| 792 const Product& product) { | 798 const Product& product) { |
| 793 bool force = cmd_line.HasSwitch(installer::switches::kForceUninstall); | |
| 794 const ProductState* product_state = | 799 const ProductState* product_state = |
| 795 original_state.GetProductState(installer_state.system_install(), | 800 original_state.GetProductState(installer_state.system_install(), |
| 796 product.distribution()->GetType()); | 801 product.distribution()->GetType()); |
| 797 if (product_state != NULL) { | 802 if (product_state != NULL) { |
| 798 VLOG(1) << "version on the system: " | 803 VLOG(1) << "version on the system: " |
| 799 << product_state->version().GetString(); | 804 << product_state->version().GetString(); |
| 800 } else if (!force) { | 805 } else if (!force_uninstall) { |
| 801 LOG(ERROR) << "No Chrome installation found for uninstall."; | 806 LOG(ERROR) << product.distribution()->GetAppShortCutName() |
| 807 << " not found for uninstall."; |
| 802 return installer::CHROME_NOT_INSTALLED; | 808 return installer::CHROME_NOT_INSTALLED; |
| 803 } | 809 } |
| 804 | 810 |
| 805 bool remove_all = !cmd_line.HasSwitch( | 811 return installer::UninstallProduct(original_state, installer_state, |
| 812 cmd_line.GetProgram(), product, remove_all, force_uninstall, cmd_line); |
| 813 } |
| 814 |
| 815 installer::InstallStatus UninstallProducts( |
| 816 const InstallationState& original_state, |
| 817 const InstallerState& installer_state, |
| 818 const CommandLine& cmd_line) { |
| 819 const Products& products = installer_state.products(); |
| 820 // InstallerState::Initialize always puts Chrome first, and we rely on that |
| 821 // here for this reason: if Chrome is in-use, the user will be prompted to |
| 822 // confirm uninstallation. Upon cancel, we should not continue with the |
| 823 // other products. |
| 824 DCHECK(products.size() < 2 || products[0]->is_chrome()); |
| 825 installer::InstallStatus install_status = installer::UNINSTALL_SUCCESSFUL; |
| 826 installer::InstallStatus prod_status = installer::UNKNOWN_STATUS; |
| 827 const bool force = cmd_line.HasSwitch(installer::switches::kForceUninstall); |
| 828 const bool remove_all = !cmd_line.HasSwitch( |
| 806 installer::switches::kDoNotRemoveSharedItems); | 829 installer::switches::kDoNotRemoveSharedItems); |
| 807 | 830 |
| 808 return installer::UninstallProduct(original_state, installer_state, | 831 for (size_t i = 0; |
| 809 cmd_line.GetProgram(), product, remove_all, force, cmd_line); | 832 install_status != installer::UNINSTALL_CANCELLED && |
| 833 i < products.size(); |
| 834 ++i) { |
| 835 prod_status = UninstallProduct(original_state, installer_state, |
| 836 cmd_line, remove_all, force, *products[i]); |
| 837 if (prod_status != installer::UNINSTALL_SUCCESSFUL) |
| 838 install_status = prod_status; |
| 839 } |
| 840 |
| 841 return install_status; |
| 810 } | 842 } |
| 811 | 843 |
| 812 installer::InstallStatus ShowEULADialog(const std::wstring& inner_frame) { | 844 installer::InstallStatus ShowEULADialog(const std::wstring& inner_frame) { |
| 813 VLOG(1) << "About to show EULA"; | 845 VLOG(1) << "About to show EULA"; |
| 814 std::wstring eula_path = installer::GetLocalizedEulaResource(); | 846 std::wstring eula_path = installer::GetLocalizedEulaResource(); |
| 815 if (eula_path.empty()) { | 847 if (eula_path.empty()) { |
| 816 LOG(ERROR) << "No EULA path available"; | 848 LOG(ERROR) << "No EULA path available"; |
| 817 return installer::EULA_REJECTED; | 849 return installer::EULA_REJECTED; |
| 818 } | 850 } |
| 819 // Newer versions of the caller pass an inner frame parameter that must | 851 // Newer versions of the caller pass an inner frame parameter that must |
| (...skipping 414 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1234 LOG(ERROR) << "Non admin user can not install system level Chrome."; | 1266 LOG(ERROR) << "Non admin user can not install system level Chrome."; |
| 1235 installer_state.WriteInstallerResult(installer::INSUFFICIENT_RIGHTS, | 1267 installer_state.WriteInstallerResult(installer::INSUFFICIENT_RIGHTS, |
| 1236 IDS_INSTALL_INSUFFICIENT_RIGHTS_BASE, NULL); | 1268 IDS_INSTALL_INSUFFICIENT_RIGHTS_BASE, NULL); |
| 1237 return installer::INSUFFICIENT_RIGHTS; | 1269 return installer::INSUFFICIENT_RIGHTS; |
| 1238 } | 1270 } |
| 1239 } | 1271 } |
| 1240 | 1272 |
| 1241 installer::InstallStatus install_status = installer::UNKNOWN_STATUS; | 1273 installer::InstallStatus install_status = installer::UNKNOWN_STATUS; |
| 1242 // If --uninstall option is given, uninstall the identified product(s) | 1274 // If --uninstall option is given, uninstall the identified product(s) |
| 1243 if (is_uninstall) { | 1275 if (is_uninstall) { |
| 1244 const Products& products = installer_state.products(); | 1276 install_status = UninstallProducts(original_state, installer_state, |
| 1245 // InstallerState::Initialize always puts Chrome first, and we rely on that | 1277 cmd_line); |
| 1246 // here for this reason: if Chrome is in-use, the user will be prompted to | |
| 1247 // confirm uninstallation. Upon cancel, we should not continue with the | |
| 1248 // other products. | |
| 1249 DCHECK(products.size() < 2 || products[0]->is_chrome()); | |
| 1250 install_status = installer::UNINSTALL_SUCCESSFUL; // I'm an optimist. | |
| 1251 installer::InstallStatus prod_status = installer::UNKNOWN_STATUS; | |
| 1252 for (size_t i = 0; | |
| 1253 install_status != installer::UNINSTALL_CANCELLED && | |
| 1254 i < products.size(); | |
| 1255 ++i) { | |
| 1256 prod_status = UninstallProduct(original_state, installer_state, | |
| 1257 cmd_line, *products[i]); | |
| 1258 if (prod_status != installer::UNINSTALL_SUCCESSFUL) | |
| 1259 install_status = prod_status; | |
| 1260 } | |
| 1261 } else { | 1278 } else { |
| 1262 // If --uninstall option is not specified, we assume it is install case. | 1279 // If --uninstall option is not specified, we assume it is install case. |
| 1263 install_status = InstallProducts(original_state, cmd_line, prefs, | 1280 install_status = InstallProducts(original_state, cmd_line, prefs, |
| 1264 &installer_state); | 1281 &installer_state); |
| 1265 } | 1282 } |
| 1266 | 1283 |
| 1267 // Validate that the machine is now in a good state following the operation. | 1284 // Validate that the machine is now in a good state following the operation. |
| 1268 // TODO(grt): change this to log at DFATAL once we're convinced that the | 1285 // TODO(grt): change this to log at DFATAL once we're convinced that the |
| 1269 // validator handles all cases properly. | 1286 // validator handles all cases properly. |
| 1270 InstallationValidator::InstallationType installation_type = | 1287 InstallationValidator::InstallationType installation_type = |
| (...skipping 29 matching lines...) Expand all Loading... |
| 1300 if (!(installer_state.is_msi() && is_uninstall)) | 1317 if (!(installer_state.is_msi() && is_uninstall)) |
| 1301 // Note that we allow the status installer::UNINSTALL_REQUIRES_REBOOT | 1318 // Note that we allow the status installer::UNINSTALL_REQUIRES_REBOOT |
| 1302 // to pass through, since this is only returned on uninstall which is | 1319 // to pass through, since this is only returned on uninstall which is |
| 1303 // never invoked directly by Google Update. | 1320 // never invoked directly by Google Update. |
| 1304 return_code = InstallUtil::GetInstallReturnCode(install_status); | 1321 return_code = InstallUtil::GetInstallReturnCode(install_status); |
| 1305 | 1322 |
| 1306 VLOG(1) << "Installation complete, returning: " << return_code; | 1323 VLOG(1) << "Installation complete, returning: " << return_code; |
| 1307 | 1324 |
| 1308 return return_code; | 1325 return return_code; |
| 1309 } | 1326 } |
| OLD | NEW |