Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(23)

Side by Side Diff: chrome/installer/setup/uninstall.cc

Issue 11412015: Copy setup when quick-enabling app host to user-level from system-level. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Comments / move helpers to anonymous namespace. Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
174 174
175 // If chrome has been reactivated, clear all events for this brand as well. 175 // If chrome has been reactivated, clear all events for this brand as well.
176 string16 reactivation_brand_wide; 176 string16 reactivation_brand_wide;
177 if (GoogleUpdateSettings::GetReactivationBrand(&reactivation_brand_wide)) { 177 if (GoogleUpdateSettings::GetReactivationBrand(&reactivation_brand_wide)) {
178 std::string reactivation_brand(WideToASCII(reactivation_brand_wide)); 178 std::string reactivation_brand(WideToASCII(reactivation_brand_wide));
179 rlz_lib::SupplementaryBranding branding(reactivation_brand.c_str()); 179 rlz_lib::SupplementaryBranding branding(reactivation_brand.c_str());
180 rlz_lib::ClearProductState(rlz_lib::CHROME, points); 180 rlz_lib::ClearProductState(rlz_lib::CHROME, points);
181 } 181 }
182 } 182 }
183 183
184 // Decides whether setup.exe and the installer archive should be removed based
185 // on the original and installer states:
186 // * non-multi product being uninstalled: remove both
187 // * any multi product left besides App Host: keep both
188 // * only App Host left: keep setup.exe
189 void CheckShouldRemoveSetupAndArchive(
190 const installer::InstallationState& original_state,
191 const installer::InstallerState& installer_state,
192 bool* remove_setup,
193 bool* remove_archive) {
194 *remove_setup = true;
195 *remove_archive = true;
196
197 // If any multi-install product is left (other than App Host) we must leave
198 // the installer and archive. For the App Host, we only leave the installer.
199 if (!installer_state.is_multi_install()) {
200 VLOG(1) << "Removing all installer files for a non-multi installation.";
201 } else {
202 for (size_t i = 0; i < BrowserDistribution::NUM_TYPES; ++i) {
gab 2012/11/21 22:55:55 Could add (*remove_setup || *remove_archive) as on
erikwright (departed) 2012/11/23 18:54:13 Redundant with the return on 215.
203 BrowserDistribution::Type dist_type =
204 static_cast<BrowserDistribution::Type>(i);
gab 2012/11/21 22:55:55 I'm not a big fan of looping over all the potentia
erikwright (departed) 2012/11/23 18:54:13 Product is from InstallerState. See the Installat
205 const installer::ProductState* product_state =
206 original_state.GetProductState(
207 installer_state.system_install(), dist_type);
208 if (product_state && product_state->is_multi_install() &&
209 !installer_state.FindProduct(dist_type)) {
210 *remove_setup = false;
211 if (dist_type != BrowserDistribution::CHROME_APP_HOST) {
212 VLOG(1) << "Keeping all installer files due to a remaining "
213 << "multi-install product.";
214 *remove_archive = false;
215 return;
216 }
217 VLOG(1) << "Keeping setup.exe due to a remaining "
gab 2012/11/21 22:55:55 Put the log beside *remove_setup = false; to keep
erikwright (departed) 2012/11/23 18:54:13 The thing is, it's only true if the condition on 2
gab 2012/11/30 15:19:45 Ah ok I see, the logic is essentially: i
218 << "app-host installation.";
219 }
220 }
221 VLOG(1) << "Removing the installer archive.";
222 if (remove_setup)
223 VLOG(1) << "Removing setup.exe.";
224 }
225 }
226
227 // Determines the version that this uninstall operation is operating on.
228 Version GetUninstallVersion(
229 const installer::InstallationState& original_state,
230 bool system_level) {
231 // Find a product version - any product should do.
232 for (size_t i = 0; i < BrowserDistribution::NUM_TYPES; ++i) {
233 const installer::ProductState* product_state =
234 original_state.GetProductState(
235 system_level, static_cast<BrowserDistribution::Type>(i));
gab 2012/11/21 22:55:55 Same comment about getting installed products, if
erikwright (departed) 2012/11/23 18:54:13 Removed this instance.
236 if (product_state)
237 return product_state->version();
238 }
239 NOTREACHED();
240 return Version();
gab 2012/11/21 22:55:55 How about: Version version; for (...) { ...
erikwright (departed) 2012/11/23 18:54:13 Removed this.
241 }
242
243 // Removes all files from the installer directory, leaving setup.exe iff
gab 2012/11/21 22:55:55 s/installer/Installer
erikwright (departed) 2012/11/23 18:54:13 IMHO this is a generic, not the specific name 'Ins
244 // |remove_setup| is true.
grt (UTC plus 2) 2012/11/21 20:40:26 true -> false?
erikwright (departed) 2012/11/23 18:54:13 Done.
245 // Returns false in case of an error.
246 bool RemoveInstallerFiles(const FilePath& install_directory,
247 bool remove_setup) {
248 using file_util::FileEnumerator;
249 FileEnumerator file_enumerator(
250 install_directory,
251 false,
252 FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
253 while (true) {
254 FilePath to_delete(file_enumerator.Next());
255 if (to_delete.empty())
256 break;
257 if (!remove_setup && to_delete.BaseName().value() == installer::kSetupExe)
gab 2012/11/21 22:55:55 I prefer comparing FilePaths to string16s, i.e. to
erikwright (departed) 2012/11/23 18:54:13 That's awesome.
258 continue;
259
260 VLOG(1) << "Deleting install path " << to_delete.value();
261 if (!file_util::Delete(to_delete, true)) {
262 LOG(ERROR) << "Failed to delete path: " << to_delete.value();
263 return false;
gab 2012/11/21 22:55:55 Is an early exit intended here? We usually operate
264 }
265 }
266 return true;
267 }
268
184 } // namespace 269 } // namespace
185 270
186 namespace installer { 271 namespace installer {
187 272
188 // This functions checks for any Chrome instances that are 273 // This functions checks for any Chrome instances that are
189 // running and first asks them to close politely by sending a Windows message. 274 // running and first asks them to close politely by sending a Windows message.
190 // If there is an error while sending message or if there are still Chrome 275 // If there is an error while sending message or if there are still Chrome
191 // procesess active after the message has been sent, this function will try 276 // procesess active after the message has been sent, this function will try
192 // to kill them. 277 // to kill them.
193 void CloseAllChromeProcesses() { 278 void CloseAllChromeProcesses() {
(...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after
464 } 549 }
465 550
466 DeleteInstallTempDir(target_path); 551 DeleteInstallTempDir(target_path);
467 552
468 DeleteResult result = DELETE_SUCCEEDED; 553 DeleteResult result = DELETE_SUCCEEDED;
469 554
470 FilePath app_host_exe(target_path.Append(installer::kChromeAppHostExe)); 555 FilePath app_host_exe(target_path.Append(installer::kChromeAppHostExe));
471 if (!file_util::Delete(app_host_exe, false)) { 556 if (!file_util::Delete(app_host_exe, false)) {
472 result = DELETE_FAILED; 557 result = DELETE_FAILED;
473 LOG(ERROR) << "Failed to delete path: " << app_host_exe.value(); 558 LOG(ERROR) << "Failed to delete path: " << app_host_exe.value();
474 } else {
475 result = DeleteApplicationProductAndVendorDirectories(target_path);
476 } 559 }
477 560
478 return result; 561 return result;
479 } 562 }
480 563
481 DeleteResult DeleteChromeFilesAndFolders(const InstallerState& installer_state, 564 DeleteResult DeleteChromeFilesAndFolders(const InstallerState& installer_state,
482 const Version& installed_version) { 565 const Version& installed_version) {
483 const FilePath& target_path = installer_state.target_path(); 566 const FilePath& target_path = installer_state.target_path();
484 if (target_path.empty()) { 567 if (target_path.empty()) {
485 LOG(ERROR) << "DeleteChromeFilesAndFolders: no installation destination " 568 LOG(ERROR) << "DeleteChromeFilesAndFolders: no installation destination "
486 << "path."; 569 << "path.";
487 return DELETE_FAILED; // Nothing else we can do to uninstall, so we return. 570 return DELETE_FAILED; // Nothing else we can do to uninstall, so we return.
488 } 571 }
489 572
490 DeleteInstallTempDir(target_path); 573 DeleteInstallTempDir(target_path);
491 574
492 DeleteResult result = DELETE_SUCCEEDED; 575 DeleteResult result = DELETE_SUCCEEDED;
493 576
494 using file_util::FileEnumerator; 577 using file_util::FileEnumerator;
495 FileEnumerator file_enumerator(target_path, false, 578 FileEnumerator file_enumerator(
496 FileEnumerator::FILES | FileEnumerator::DIRECTORIES); 579 target_path, true, FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
grt (UTC plus 2) 2012/11/21 20:40:26 i find this change impenetrable. could you explain
erikwright (departed) 2012/11/21 21:51:10 Previously, we went through the top-level entries
580
581 const FilePath installer_directory =
582 installer_state.GetInstallerDirectory(installed_version);
497 while (true) { 583 while (true) {
498 FilePath to_delete(file_enumerator.Next()); 584 FilePath to_delete(file_enumerator.Next());
499 if (to_delete.empty()) 585 if (to_delete.empty())
500 break; 586 break;
501 if (to_delete.BaseName().value() == installer::kChromeAppHostExe) 587 if (to_delete.BaseName().value() == installer::kChromeAppHostExe)
502 continue; 588 continue;
589 if (to_delete == installer_directory ||
590 installer_directory.IsParent(to_delete) ||
591 to_delete.IsParent(installer_directory)) {
592 continue;
593 }
503 594
504 VLOG(1) << "Deleting install path " << to_delete.value(); 595 VLOG(1) << "Deleting install path " << to_delete.value();
505 if (!file_util::Delete(to_delete, true)) { 596 if (!file_util::Delete(to_delete, true)) {
506 LOG(ERROR) << "Failed to delete path (1st try): " << to_delete.value(); 597 LOG(ERROR) << "Failed to delete path (1st try): " << to_delete.value();
507 if (installer_state.FindProduct(BrowserDistribution::CHROME_FRAME)) { 598 if (installer_state.FindProduct(BrowserDistribution::CHROME_FRAME)) {
508 // We don't try killing Chrome processes for Chrome Frame builds since 599 // We don't try killing Chrome processes for Chrome Frame builds since
509 // that is unlikely to help. Instead, schedule files for deletion and 600 // that is unlikely to help. Instead, schedule files for deletion and
510 // return a value that will trigger a reboot prompt. 601 // return a value that will trigger a reboot prompt.
511 FileEnumerator::FindInfo find_info; 602 FileEnumerator::FindInfo find_info;
512 file_enumerator.GetFindInfo(&find_info); 603 file_enumerator.GetFindInfo(&find_info);
513 if (FileEnumerator::IsDirectory(find_info)) 604 if (FileEnumerator::IsDirectory(find_info))
514 ScheduleDirectoryForDeletion(to_delete.value().c_str()); 605 ScheduleDirectoryForDeletion(to_delete.value().c_str());
515 else 606 else
516 ScheduleFileSystemEntityForDeletion(to_delete.value().c_str()); 607 ScheduleFileSystemEntityForDeletion(to_delete.value().c_str());
517 result = DELETE_REQUIRES_REBOOT; 608 result = DELETE_REQUIRES_REBOOT;
518 } else { 609 } else {
519 // Try closing any running Chrome processes and deleting files once 610 // Try closing any running Chrome processes and deleting files once
520 // again. 611 // again.
521 CloseAllChromeProcesses(); 612 CloseAllChromeProcesses();
522 if (!file_util::Delete(to_delete, true)) { 613 if (!file_util::Delete(to_delete, true)) {
523 LOG(ERROR) << "Failed to delete path (2nd try): " 614 LOG(ERROR) << "Failed to delete path (2nd try): "
524 << to_delete.value(); 615 << to_delete.value();
525 result = DELETE_FAILED; 616 result = DELETE_FAILED;
526 break; 617 break;
527 } 618 }
528 } 619 }
529 } 620 }
530 } 621 }
531 622
532 if (result == DELETE_REQUIRES_REBOOT) {
533 // Delete the Application directory at reboot if empty.
534 ScheduleFileSystemEntityForDeletion(target_path.value().c_str());
535
536 // If we need a reboot to continue, schedule the parent directories for
537 // deletion unconditionally. If they are not empty, the session manager
538 // will not delete them on reboot.
539 ScheduleParentAndGrandparentForDeletion(target_path);
540 } else {
541 result = DeleteApplicationProductAndVendorDirectories(target_path);
542 }
543 return result; 623 return result;
544 } 624 }
545 625
546 // This method checks if Chrome is currently running or if the user has 626 // This method checks if Chrome is currently running or if the user has
547 // cancelled the uninstall operation by clicking Cancel on the confirmation 627 // cancelled the uninstall operation by clicking Cancel on the confirmation
548 // box that Chrome pops up. 628 // box that Chrome pops up.
549 InstallStatus IsChromeActiveOrUserCancelled( 629 InstallStatus IsChromeActiveOrUserCancelled(
550 const InstallerState& installer_state, 630 const InstallerState& installer_state,
551 const Product& product) { 631 const Product& product) {
552 int32 exit_code = content::RESULT_CODE_NORMAL_EXIT; 632 int32 exit_code = content::RESULT_CODE_NORMAL_EXIT;
(...skipping 674 matching lines...) Expand 10 before | Expand all | Expand 10 after
1227 product); 1307 product);
1228 ret = installer::UNINSTALL_SUCCESSFUL; 1308 ret = installer::UNINSTALL_SUCCESSFUL;
1229 1309
1230 // When deleting files, we must make sure that we're either a "single" 1310 // When deleting files, we must make sure that we're either a "single"
1231 // (aka non-multi) installation or we are the Chrome Binaries. 1311 // (aka non-multi) installation or we are the Chrome Binaries.
1232 1312
1233 std::vector<FilePath> local_state_folders; 1313 std::vector<FilePath> local_state_folders;
1234 GetLocalStateFolders(product, &local_state_folders); 1314 GetLocalStateFolders(product, &local_state_folders);
1235 FilePath backup_state_file(BackupLocalStateFile(local_state_folders)); 1315 FilePath backup_state_file(BackupLocalStateFile(local_state_folders));
1236 1316
1237 DeleteResult delete_result = DELETE_SUCCEEDED;
1238
1239 if (product.is_chrome_app_host()) { 1317 if (product.is_chrome_app_host()) {
1240 DeleteAppHostFilesAndFolders(installer_state, product_state->version()); 1318 DeleteAppHostFilesAndFolders(installer_state, product_state->version());
1241 } else if (!installer_state.is_multi_install() || 1319 } else if (!installer_state.is_multi_install() ||
1242 product.is_chrome_binaries()) { 1320 product.is_chrome_binaries()) {
1243 1321 DeleteResult delete_result = DeleteChromeFilesAndFolders(
1244 // In order to be able to remove the folder in which we're running, we 1322 installer_state, product_state->version());
1245 // need to move setup.exe out of the install folder. 1323 if (delete_result == DELETE_FAILED) {
1246 // TODO(tommi): What if the temp folder is on a different volume? 1324 ret = installer::UNINSTALL_FAILED;
1247 MoveSetupOutOfInstallFolder(installer_state, setup_path, 1325 } else if (delete_result == DELETE_REQUIRES_REBOOT) {
1248 product_state->version()); 1326 ret = installer::UNINSTALL_REQUIRES_REBOOT;
1249 delete_result = DeleteChromeFilesAndFolders(installer_state, 1327 }
1250 product_state->version());
1251 } 1328 }
1252 1329
1253 if (delete_profile) 1330 if (delete_profile)
1254 DeleteLocalState(local_state_folders, product.is_chrome_frame()); 1331 DeleteLocalState(local_state_folders, product.is_chrome_frame());
1255 1332
1256 if (delete_result == DELETE_FAILED) {
1257 ret = installer::UNINSTALL_FAILED;
1258 } else if (delete_result == DELETE_REQUIRES_REBOOT) {
1259 ret = installer::UNINSTALL_REQUIRES_REBOOT;
1260 }
1261
1262 if (!force_uninstall) { 1333 if (!force_uninstall) {
1263 VLOG(1) << "Uninstallation complete. Launching post-uninstall operations."; 1334 VLOG(1) << "Uninstallation complete. Launching post-uninstall operations.";
1264 browser_dist->DoPostUninstallOperations(product_state->version(), 1335 browser_dist->DoPostUninstallOperations(product_state->version(),
1265 backup_state_file, distribution_data); 1336 backup_state_file, distribution_data);
1266 } 1337 }
1267 1338
1268 // Try and delete the preserved local state once the post-install 1339 // Try and delete the preserved local state once the post-install
1269 // operations are complete. 1340 // operations are complete.
1270 if (!backup_state_file.empty()) 1341 if (!backup_state_file.empty())
1271 file_util::Delete(backup_state_file, false); 1342 file_util::Delete(backup_state_file, false);
1272 1343
1273 return ret; 1344 return ret;
1274 } 1345 }
1275 1346
1347 installer::InstallStatus CleanUpInstallationDirectoryAfterUninstall(
1348 const InstallationState& original_state,
1349 const InstallerState& installer_state,
1350 const CommandLine& cmd_line,
1351 installer::InstallStatus uninstall_status) {
1352 if (uninstall_status != installer::UNINSTALL_SUCCESSFUL &&
1353 uninstall_status != installer::UNINSTALL_REQUIRES_REBOOT) {
1354 return uninstall_status;
gab 2012/11/21 22:55:55 Is the goal on UNINSTALL_FAILED to halt the uninst
erikwright (departed) 2012/11/23 18:54:13 Previously, if we failed to delete a file in Delet
1355 }
1356
1357 bool remove_setup = true;
1358 bool remove_archive = true;
1359 CheckShouldRemoveSetupAndArchive(original_state, installer_state,
1360 &remove_setup, &remove_archive);
1361 if (!remove_archive)
1362 return uninstall_status;
1363
1364 Version uninstall_version(
grt (UTC plus 2) 2012/11/21 20:40:26 it seems safer to me to get the path to setup.exe
erikwright (departed) 2012/11/21 21:51:10 Done naively, that actually seems more dangerous t
1365 GetUninstallVersion(original_state, installer_state.system_install()));
1366 if (!uninstall_version.IsValid())
1367 return installer::UNINSTALL_FAILED;
1368
1369 if (remove_setup) {
1370 // In order to be able to remove the folder in which we're running, we
1371 // need to move setup.exe out of the install folder.
1372 // TODO(tommi): What if the temp folder is on a different volume?
1373 MoveSetupOutOfInstallFolder(installer_state,
1374 cmd_line.GetProgram(),
1375 uninstall_version);
1376 }
1377
1378 FilePath install_directory(
1379 installer_state.GetInstallerDirectory(uninstall_version));
1380 if (!RemoveInstallerFiles(install_directory, remove_setup))
1381 return installer::UNINSTALL_FAILED;
1382
1383 if (remove_setup) {
1384 const FilePath& target_path = installer_state.target_path();
1385 if (target_path.empty()) {
1386 LOG(ERROR) << "No installation destination path.";
1387 return installer::UNINSTALL_FAILED;
1388 }
1389
1390 if (DELETE_SUCCEEDED != DeleteEmptyDir(install_directory))
grt (UTC plus 2) 2012/11/21 20:40:26 i think chromium style says to swap these
erikwright (departed) 2012/11/23 18:54:13 Done.
1391 return installer::UNINSTALL_FAILED;
1392 FilePath to_delete = install_directory.DirName();
1393 while (to_delete != target_path) {
1394 DeleteResult delete_result = DeleteEmptyDir(to_delete);
1395 if (delete_result == DELETE_SUCCEEDED) {
1396 to_delete = to_delete.DirName();
1397 continue;
1398 }
1399 if (delete_result == DELETE_NOT_EMPTY &&
gab 2012/11/21 22:55:55 else if? This doesn't actually change the flow, b
1400 uninstall_status == installer::UNINSTALL_REQUIRES_REBOOT) {
1401 break;
1402 }
1403 return installer::UNINSTALL_FAILED;
1404
1405 }
1406
1407
1408 if (uninstall_status == installer::UNINSTALL_REQUIRES_REBOOT) {
1409 // Delete the Application directory at reboot if empty.
1410 ScheduleFileSystemEntityForDeletion(target_path.value().c_str());
1411
1412 // If we need a reboot to continue, schedule the parent directories for
1413 // deletion unconditionally. If they are not empty, the session manager
1414 // will not delete them on reboot.
1415 ScheduleParentAndGrandparentForDeletion(target_path);
1416 return installer::UNINSTALL_REQUIRES_REBOOT;
1417 }
1418
1419 if (installer::DELETE_FAILED ==
grt (UTC plus 2) 2012/11/21 20:40:26 swap here, too
erikwright (departed) 2012/11/23 18:54:13 Done.
1420 DeleteApplicationProductAndVendorDirectories(target_path)) {
1421 return installer::UNINSTALL_FAILED;
1422 }
1423 }
1424
1425 return installer::UNINSTALL_SUCCESSFUL;
1426 }
1427
1276 } // namespace installer 1428 } // namespace installer
OLDNEW
« chrome/installer/setup/uninstall.h ('K') | « chrome/installer/setup/uninstall.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698