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 // This file defines the methods useful for uninstalling Chrome. | 5 // This file defines the methods useful for uninstalling Chrome. |
6 | 6 |
7 #include "chrome/installer/setup/uninstall.h" | 7 #include "chrome/installer/setup/uninstall.h" |
8 | 8 |
9 #include <windows.h> | 9 #include <windows.h> |
10 | 10 |
11 #include <vector> | 11 #include <vector> |
12 | 12 |
13 #include "base/base_paths.h" | 13 #include "base/base_paths.h" |
14 #include "base/files/file_enumerator.h" | 14 #include "base/files/file_enumerator.h" |
15 #include "base/files/file_util.h" | 15 #include "base/files/file_util.h" |
16 #include "base/path_service.h" | 16 #include "base/path_service.h" |
17 #include "base/process/kill.h" | 17 #include "base/process/kill.h" |
18 #include "base/strings/string16.h" | 18 #include "base/strings/string16.h" |
19 #include "base/strings/string_number_conversions.h" | 19 #include "base/strings/string_number_conversions.h" |
20 #include "base/strings/string_util.h" | 20 #include "base/strings/string_util.h" |
21 #include "base/strings/utf_string_conversions.h" | 21 #include "base/strings/utf_string_conversions.h" |
22 #include "base/win/registry.h" | 22 #include "base/win/registry.h" |
23 #include "base/win/scoped_handle.h" | 23 #include "base/win/scoped_handle.h" |
24 #include "base/win/shortcut.h" | 24 #include "base/win/shortcut.h" |
25 #include "base/win/windows_version.h" | 25 #include "base/win/windows_version.h" |
26 #include "chrome/common/chrome_constants.h" | 26 #include "chrome/common/chrome_constants.h" |
27 #include "chrome/common/chrome_paths.h" | 27 #include "chrome/common/chrome_paths.h" |
28 #include "chrome/common/chrome_result_codes.h" | 28 #include "chrome/common/chrome_result_codes.h" |
29 #include "chrome/installer/setup/app_launcher_installer.h" | |
29 #include "chrome/installer/setup/install.h" | 30 #include "chrome/installer/setup/install.h" |
30 #include "chrome/installer/setup/install_worker.h" | 31 #include "chrome/installer/setup/install_worker.h" |
31 #include "chrome/installer/setup/setup_constants.h" | 32 #include "chrome/installer/setup/setup_constants.h" |
32 #include "chrome/installer/setup/setup_util.h" | 33 #include "chrome/installer/setup/setup_util.h" |
33 #include "chrome/installer/util/auto_launch_util.h" | 34 #include "chrome/installer/util/auto_launch_util.h" |
34 #include "chrome/installer/util/browser_distribution.h" | 35 #include "chrome/installer/util/browser_distribution.h" |
35 #include "chrome/installer/util/channel_info.h" | 36 #include "chrome/installer/util/channel_info.h" |
36 #include "chrome/installer/util/delete_after_reboot_helper.h" | 37 #include "chrome/installer/util/delete_after_reboot_helper.h" |
37 #include "chrome/installer/util/firewall_manager_win.h" | 38 #include "chrome/installer/util/firewall_manager_win.h" |
38 #include "chrome/installer/util/google_update_constants.h" | 39 #include "chrome/installer/util/google_update_constants.h" |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
181 if (GoogleUpdateSettings::GetReactivationBrand(&reactivation_brand_wide)) { | 182 if (GoogleUpdateSettings::GetReactivationBrand(&reactivation_brand_wide)) { |
182 std::string reactivation_brand(base::UTF16ToASCII(reactivation_brand_wide)); | 183 std::string reactivation_brand(base::UTF16ToASCII(reactivation_brand_wide)); |
183 rlz_lib::SupplementaryBranding branding(reactivation_brand.c_str()); | 184 rlz_lib::SupplementaryBranding branding(reactivation_brand.c_str()); |
184 rlz_lib::ClearProductState(rlz_lib::CHROME, points); | 185 rlz_lib::ClearProductState(rlz_lib::CHROME, points); |
185 } | 186 } |
186 } | 187 } |
187 | 188 |
188 // Decides whether setup.exe and the installer archive should be removed based | 189 // Decides whether setup.exe and the installer archive should be removed based |
189 // on the original and installer states: | 190 // on the original and installer states: |
190 // * non-multi product being uninstalled: remove both | 191 // * non-multi product being uninstalled: remove both |
191 // * any multi product left besides App Host: keep both | 192 // * any multi product left: keep both |
192 // * only App Host left: keep setup.exe | |
193 void CheckShouldRemoveSetupAndArchive(const InstallationState& original_state, | 193 void CheckShouldRemoveSetupAndArchive(const InstallationState& original_state, |
194 const InstallerState& installer_state, | 194 const InstallerState& installer_state, |
195 bool* remove_setup, | 195 bool* remove_setup, |
196 bool* remove_archive) { | 196 bool* remove_archive) { |
grt (UTC plus 2)
2014/12/18 19:27:36
remove_archive is now effectively unused. please r
huangs
2015/01/05 06:01:12
Done, updated comments and returning via "return".
| |
197 *remove_setup = true; | 197 *remove_setup = true; |
198 *remove_archive = true; | 198 *remove_archive = true; |
199 | 199 |
200 // If any multi-install product is left (other than App Host) we must leave | 200 // If any multi-install product is left we must leave the installer and |
201 // the installer and archive. For the App Host, we only leave the installer. | 201 // archive. |
202 if (!installer_state.is_multi_install()) { | 202 if (!installer_state.is_multi_install()) { |
203 VLOG(1) << "Removing all installer files for a non-multi installation."; | 203 VLOG(1) << "Removing all installer files for a non-multi installation."; |
204 } else { | 204 } else { |
205 // Loop through all known products... | 205 // Loop through all known products... |
206 for (size_t i = 0; i < BrowserDistribution::NUM_TYPES; ++i) { | 206 for (size_t i = 0; i < BrowserDistribution::NUM_TYPES; ++i) { |
207 BrowserDistribution::Type dist_type = | 207 BrowserDistribution::Type dist_type = |
208 static_cast<BrowserDistribution::Type>(i); | 208 static_cast<BrowserDistribution::Type>(i); |
209 const ProductState* product_state = original_state.GetProductState( | 209 const ProductState* product_state = original_state.GetProductState( |
210 installer_state.system_install(), dist_type); | 210 installer_state.system_install(), dist_type); |
211 // If the product is installed, in multi mode, and is not part of the | 211 // If the product is installed, in multi mode, and is not part of the |
212 // active uninstallation... | 212 // active uninstallation... |
213 if (product_state && product_state->is_multi_install() && | 213 if (product_state && product_state->is_multi_install() && |
214 !installer_state.FindProduct(dist_type)) { | 214 !installer_state.FindProduct(dist_type)) { |
215 // setup.exe will not be removed as there is a remaining multi-install | 215 // setup.exe will not be removed as there is a remaining multi-install |
216 // product. | 216 // product. |
217 *remove_setup = false; | 217 *remove_setup = false; |
218 // As a special case, we can still remove the actual archive if the | 218 VLOG(1) << "Keeping all installer files due to a remaining " |
219 // only remaining product is the App Host. | 219 << "multi-install product."; |
220 if (dist_type != BrowserDistribution::CHROME_APP_HOST) { | 220 return; |
221 VLOG(1) << "Keeping all installer files due to a remaining " | |
222 << "multi-install product."; | |
223 *remove_archive = false; | |
224 return; | |
225 } | |
226 VLOG(1) << "Keeping setup.exe due to a remaining " | |
227 << "app-host installation."; | |
228 } | 221 } |
229 } | 222 } |
230 VLOG(1) << "Removing the installer archive."; | 223 VLOG(1) << "Removing the installer archive."; |
231 if (remove_setup) | 224 if (remove_setup) |
232 VLOG(1) << "Removing setup.exe."; | 225 VLOG(1) << "Removing setup.exe."; |
233 } | 226 } |
234 } | 227 } |
235 | 228 |
236 // Removes all files from the installer directory, leaving setup.exe iff | 229 // Removes all files from the installer directory, leaving setup.exe iff |
237 // |remove_setup| is false. | 230 // |remove_setup| is false. |
(...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
506 // We cannot delete the file right away, but try to delete it some other | 499 // We cannot delete the file right away, but try to delete it some other |
507 // way. Either with the help of a different process or the system. | 500 // way. Either with the help of a different process or the system. |
508 if (!base::DeleteFileAfterReboot(temp_file)) { | 501 if (!base::DeleteFileAfterReboot(temp_file)) { |
509 const uint32 kDeleteAfterMs = 10 * 1000; | 502 const uint32 kDeleteAfterMs = 10 * 1000; |
510 installer::DeleteFileFromTempProcess(temp_file, kDeleteAfterMs); | 503 installer::DeleteFileFromTempProcess(temp_file, kDeleteAfterMs); |
511 } | 504 } |
512 } | 505 } |
513 return true; | 506 return true; |
514 } | 507 } |
515 | 508 |
516 DeleteResult DeleteAppHostFilesAndFolders(const InstallerState& installer_state, | |
517 const Version& installed_version) { | |
518 const base::FilePath& target_path = installer_state.target_path(); | |
519 if (target_path.empty()) { | |
520 LOG(ERROR) << "DeleteAppHostFilesAndFolders: no installation destination " | |
521 << "path."; | |
522 return DELETE_FAILED; // Nothing else we can do to uninstall, so we return. | |
523 } | |
524 | |
525 DeleteInstallTempDir(target_path); | |
526 | |
527 DeleteResult result = DELETE_SUCCEEDED; | |
528 | |
529 base::FilePath app_host_exe(target_path.Append(installer::kChromeAppHostExe)); | |
530 if (!base::DeleteFile(app_host_exe, false)) { | |
531 result = DELETE_FAILED; | |
532 LOG(ERROR) << "Failed to delete path: " << app_host_exe.value(); | |
533 } | |
534 | |
535 return result; | |
536 } | |
537 | |
538 DeleteResult DeleteChromeFilesAndFolders(const InstallerState& installer_state, | 509 DeleteResult DeleteChromeFilesAndFolders(const InstallerState& installer_state, |
539 const base::FilePath& setup_exe) { | 510 const base::FilePath& setup_exe) { |
540 const base::FilePath& target_path = installer_state.target_path(); | 511 const base::FilePath& target_path = installer_state.target_path(); |
541 if (target_path.empty()) { | 512 if (target_path.empty()) { |
542 LOG(ERROR) << "DeleteChromeFilesAndFolders: no installation destination " | 513 LOG(ERROR) << "DeleteChromeFilesAndFolders: no installation destination " |
543 << "path."; | 514 << "path."; |
544 return DELETE_FAILED; // Nothing else we can do to uninstall, so we return. | 515 return DELETE_FAILED; // Nothing else we can do to uninstall, so we return. |
545 } | 516 } |
546 | 517 |
547 DeleteInstallTempDir(target_path); | 518 DeleteInstallTempDir(target_path); |
548 | 519 |
549 DeleteResult result = DELETE_SUCCEEDED; | 520 DeleteResult result = DELETE_SUCCEEDED; |
550 | 521 |
551 base::FilePath installer_directory; | 522 base::FilePath installer_directory; |
552 if (target_path.IsParent(setup_exe)) | 523 if (target_path.IsParent(setup_exe)) |
553 installer_directory = setup_exe.DirName(); | 524 installer_directory = setup_exe.DirName(); |
554 | 525 |
555 // Enumerate all the files in target_path recursively (breadth-first). | 526 // Enumerate all the files in target_path recursively (breadth-first). |
556 // We delete a file or folder unless it is a parent/child of the installer | 527 // We delete a file or folder unless it is a parent/child of the installer |
557 // directory. For parents of the installer directory, we will later recurse | 528 // directory. For parents of the installer directory, we will later recurse |
558 // and delete all the children (that are not also parents/children of the | 529 // and delete all the children (that are not also parents/children of the |
559 // installer directory). | 530 // installer directory). |
560 base::FileEnumerator file_enumerator(target_path, true, | 531 base::FileEnumerator file_enumerator(target_path, true, |
561 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES); | 532 base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES); |
562 for (base::FilePath to_delete = file_enumerator.Next(); !to_delete.empty(); | 533 for (base::FilePath to_delete = file_enumerator.Next(); !to_delete.empty(); |
563 to_delete = file_enumerator.Next()) { | 534 to_delete = file_enumerator.Next()) { |
564 if (to_delete.BaseName().value() == installer::kChromeAppHostExe) | |
565 continue; | |
566 if (!installer_directory.empty() && | 535 if (!installer_directory.empty() && |
567 (to_delete == installer_directory || | 536 (to_delete == installer_directory || |
568 installer_directory.IsParent(to_delete) || | 537 installer_directory.IsParent(to_delete) || |
569 to_delete.IsParent(installer_directory))) { | 538 to_delete.IsParent(installer_directory))) { |
570 continue; | 539 continue; |
571 } | 540 } |
572 | 541 |
573 VLOG(1) << "Deleting install path " << to_delete.value(); | 542 VLOG(1) << "Deleting install path " << to_delete.value(); |
574 if (!base::DeleteFile(to_delete, true)) { | 543 if (!base::DeleteFile(to_delete, true)) { |
575 LOG(ERROR) << "Failed to delete path (1st try): " << to_delete.value(); | 544 LOG(ERROR) << "Failed to delete path (1st try): " << to_delete.value(); |
(...skipping 694 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1270 UninstallActiveSetupEntries(installer_state, product); | 1239 UninstallActiveSetupEntries(installer_state, product); |
1271 | 1240 |
1272 UninstallFirewallRules(browser_dist, chrome_exe); | 1241 UninstallFirewallRules(browser_dist, chrome_exe); |
1273 | 1242 |
1274 RemoveBlacklistState(); | 1243 RemoveBlacklistState(); |
1275 | 1244 |
1276 // Notify the shell that associations have changed since Chrome was likely | 1245 // Notify the shell that associations have changed since Chrome was likely |
1277 // unregistered. | 1246 // unregistered. |
1278 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); | 1247 SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL); |
1279 | 1248 |
1280 // TODO(huangs): Implement actual migration code and remove the hack below. | |
1281 // Remove the "shadow" App Launcher registry keys. | |
1282 // TODO(hunags): Management of this key should not be conditional on | |
1283 // multi-install since the app list feature is available regardless of how | |
1284 // chrome is installed. | |
1285 if (installer_state.is_multi_install()) { | 1249 if (installer_state.is_multi_install()) { |
1286 // Delete the "shadow" keys. | 1250 AppLauncherInstaller::OnUninstall(reg_root); |
grt (UTC plus 2)
2014/12/18 19:27:36
this should be done in the "if (is_chrome)" block
huangs
2015/01/05 06:01:12
Done.
| |
1287 BrowserDistribution* shadow_app_launcher_dist = | |
1288 BrowserDistribution::GetSpecificDistribution( | |
1289 BrowserDistribution::CHROME_APP_HOST); | |
1290 InstallUtil::DeleteRegistryKey( | |
1291 reg_root, | |
1292 shadow_app_launcher_dist->GetVersionKey(), | |
1293 KEY_WOW64_32KEY); | |
1294 } | 1251 } |
1295 } | 1252 } |
1296 | 1253 |
1297 if (installer_state.is_multi_install()) | 1254 if (installer_state.is_multi_install()) |
1298 ProcessGoogleUpdateItems(original_state, installer_state, product); | 1255 ProcessGoogleUpdateItems(original_state, installer_state, product); |
1299 | 1256 |
1300 // Get the state of the installed product (if any) | 1257 // Get the state of the installed product (if any) |
1301 const ProductState* product_state = | 1258 const ProductState* product_state = |
1302 original_state.GetProductState(installer_state.system_install(), | 1259 original_state.GetProductState(installer_state.system_install(), |
1303 browser_dist->GetType()); | 1260 browser_dist->GetType()); |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1361 base::FilePath user_data_dir(GetUserDataDir(product)); | 1318 base::FilePath user_data_dir(GetUserDataDir(product)); |
1362 base::FilePath backup_state_file; | 1319 base::FilePath backup_state_file; |
1363 if (!user_data_dir.empty()) { | 1320 if (!user_data_dir.empty()) { |
1364 backup_state_file = BackupLocalStateFile(user_data_dir); | 1321 backup_state_file = BackupLocalStateFile(user_data_dir); |
1365 } else { | 1322 } else { |
1366 LOG(ERROR) << "Could not retrieve the user's profile directory."; | 1323 LOG(ERROR) << "Could not retrieve the user's profile directory."; |
1367 ret = installer::UNINSTALL_FAILED; | 1324 ret = installer::UNINSTALL_FAILED; |
1368 delete_profile = false; | 1325 delete_profile = false; |
1369 } | 1326 } |
1370 | 1327 |
1371 if (product.is_chrome_app_host()) { | 1328 if (!installer_state.is_multi_install() || product.is_chrome_binaries()) { |
1372 DeleteAppHostFilesAndFolders(installer_state, product_state->version()); | |
1373 } else if (!installer_state.is_multi_install() || | |
1374 product.is_chrome_binaries()) { | |
1375 DeleteResult delete_result = DeleteChromeFilesAndFolders( | 1329 DeleteResult delete_result = DeleteChromeFilesAndFolders( |
1376 installer_state, base::MakeAbsoluteFilePath(setup_exe)); | 1330 installer_state, base::MakeAbsoluteFilePath(setup_exe)); |
1377 if (delete_result == DELETE_FAILED) { | 1331 if (delete_result == DELETE_FAILED) { |
1378 ret = installer::UNINSTALL_FAILED; | 1332 ret = installer::UNINSTALL_FAILED; |
1379 } else if (delete_result == DELETE_REQUIRES_REBOOT) { | 1333 } else if (delete_result == DELETE_REQUIRES_REBOOT) { |
1380 ret = installer::UNINSTALL_REQUIRES_REBOOT; | 1334 ret = installer::UNINSTALL_REQUIRES_REBOOT; |
1381 } | 1335 } |
1382 } | 1336 } |
1383 | 1337 |
1384 if (delete_profile) | 1338 if (delete_profile) |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1466 // If we need a reboot to continue, schedule the parent directories for | 1420 // If we need a reboot to continue, schedule the parent directories for |
1467 // deletion unconditionally. If they are not empty, the session manager | 1421 // deletion unconditionally. If they are not empty, the session manager |
1468 // will not delete them on reboot. | 1422 // will not delete them on reboot. |
1469 ScheduleParentAndGrandparentForDeletion(target_path); | 1423 ScheduleParentAndGrandparentForDeletion(target_path); |
1470 } else if (DeleteChromeDirectoriesIfEmpty(target_path) == DELETE_FAILED) { | 1424 } else if (DeleteChromeDirectoriesIfEmpty(target_path) == DELETE_FAILED) { |
1471 *uninstall_status = UNINSTALL_FAILED; | 1425 *uninstall_status = UNINSTALL_FAILED; |
1472 } | 1426 } |
1473 } | 1427 } |
1474 | 1428 |
1475 } // namespace installer | 1429 } // namespace installer |
OLD | NEW |