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

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: sync Created 7 years, 12 months 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
« no previous file with comments | « chrome/installer/setup/uninstall.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 179 matching lines...) Expand 10 before | Expand all | Expand 10 after
190 190
191 // If chrome has been reactivated, clear all events for this brand as well. 191 // If chrome has been reactivated, clear all events for this brand as well.
192 string16 reactivation_brand_wide; 192 string16 reactivation_brand_wide;
193 if (GoogleUpdateSettings::GetReactivationBrand(&reactivation_brand_wide)) { 193 if (GoogleUpdateSettings::GetReactivationBrand(&reactivation_brand_wide)) {
194 std::string reactivation_brand(WideToASCII(reactivation_brand_wide)); 194 std::string reactivation_brand(WideToASCII(reactivation_brand_wide));
195 rlz_lib::SupplementaryBranding branding(reactivation_brand.c_str()); 195 rlz_lib::SupplementaryBranding branding(reactivation_brand.c_str());
196 rlz_lib::ClearProductState(rlz_lib::CHROME, points); 196 rlz_lib::ClearProductState(rlz_lib::CHROME, points);
197 } 197 }
198 } 198 }
199 199
200 // Decides whether setup.exe and the installer archive should be removed based
201 // on the original and installer states:
202 // * non-multi product being uninstalled: remove both
203 // * any multi product left besides App Host: keep both
204 // * only App Host left: keep setup.exe
205 void CheckShouldRemoveSetupAndArchive(
206 const installer::InstallationState& original_state,
207 const installer::InstallerState& installer_state,
208 bool* remove_setup,
209 bool* remove_archive) {
210 *remove_setup = true;
211 *remove_archive = true;
212
213 // If any multi-install product is left (other than App Host) we must leave
214 // the installer and archive. For the App Host, we only leave the installer.
215 if (!installer_state.is_multi_install()) {
216 VLOG(1) << "Removing all installer files for a non-multi installation.";
217 } else {
218 for (size_t i = 0; i < BrowserDistribution::NUM_TYPES; ++i) {
219 BrowserDistribution::Type dist_type =
220 static_cast<BrowserDistribution::Type>(i);
221 const installer::ProductState* product_state =
222 original_state.GetProductState(
223 installer_state.system_install(), dist_type);
224 if (product_state && product_state->is_multi_install() &&
225 !installer_state.FindProduct(dist_type)) {
226 // setup.exe will not be removed as there is a remaining multi-install
227 // product.
228 *remove_setup = false;
229 // As a special case, we can still remove the actual archive if the
230 // only remaining product is the App Host.
231 if (dist_type != BrowserDistribution::CHROME_APP_HOST) {
232 VLOG(1) << "Keeping all installer files due to a remaining "
233 << "multi-install product.";
234 *remove_archive = false;
235 return;
236 }
237 VLOG(1) << "Keeping setup.exe due to a remaining "
238 << "app-host installation.";
239 }
240 }
241 VLOG(1) << "Removing the installer archive.";
242 if (remove_setup)
243 VLOG(1) << "Removing setup.exe.";
244 }
245 }
246
247 // Removes all files from the installer directory, leaving setup.exe iff
248 // |remove_setup| is false.
249 // Returns false in case of an error.
250 bool RemoveInstallerFiles(const FilePath& install_directory,
251 bool remove_setup) {
252 using file_util::FileEnumerator;
253 FileEnumerator file_enumerator(
254 install_directory,
255 false,
256 FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
257 bool success = true;
258
259 FilePath setup_exe_base_name(installer::kSetupExe);
260
261 while (true) {
262 FilePath to_delete(file_enumerator.Next());
263 if (to_delete.empty())
264 break;
265 if (!remove_setup && to_delete.BaseName() == setup_exe_base_name)
266 continue;
267
268 VLOG(1) << "Deleting install path " << to_delete.value();
269 if (!file_util::Delete(to_delete, true)) {
270 LOG(ERROR) << "Failed to delete path: " << to_delete.value();
271 success = false;
272 }
273 }
274
275 return success;
276 }
277
200 } // namespace 278 } // namespace
201 279
202 namespace installer { 280 namespace installer {
203 281
204 // Kills all Chrome processes, immediately. 282 // Kills all Chrome processes, immediately.
205 void CloseAllChromeProcesses() { 283 void CloseAllChromeProcesses() {
206 base::CleanupProcesses(installer::kChromeExe, base::TimeDelta(), 284 base::CleanupProcesses(installer::kChromeExe, base::TimeDelta(),
207 content::RESULT_CODE_HUNG, NULL); 285 content::RESULT_CODE_HUNG, NULL);
208 base::CleanupProcesses(installer::kNaClExe, base::TimeDelta(), 286 base::CleanupProcesses(installer::kNaClExe, base::TimeDelta(),
209 content::RESULT_CODE_HUNG, NULL); 287 content::RESULT_CODE_HUNG, NULL);
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
392 const FilePath product_dir(user_data_dir.DirName()); 470 const FilePath product_dir(user_data_dir.DirName());
393 if (!product_dir.empty()) 471 if (!product_dir.empty())
394 DeleteEmptyDir(product_dir); 472 DeleteEmptyDir(product_dir);
395 } 473 }
396 } 474 }
397 475
398 return result; 476 return result;
399 } 477 }
400 478
401 bool MoveSetupOutOfInstallFolder(const InstallerState& installer_state, 479 bool MoveSetupOutOfInstallFolder(const InstallerState& installer_state,
402 const FilePath& setup_path, 480 const FilePath& setup_exe) {
403 const Version& installed_version) {
404 bool ret = false; 481 bool ret = false;
405 FilePath setup_exe(installer_state.GetInstallerDirectory(installed_version)
406 .Append(setup_path.BaseName()));
407 FilePath temp_file; 482 FilePath temp_file;
408 if (!file_util::CreateTemporaryFile(&temp_file)) { 483 if (!file_util::CreateTemporaryFile(&temp_file)) {
409 LOG(ERROR) << "Failed to create temporary file for setup.exe."; 484 LOG(ERROR) << "Failed to create temporary file for setup.exe.";
410 } else { 485 } else {
411 VLOG(1) << "Attempting to move setup to: " << temp_file.value(); 486 VLOG(1) << "Attempting to move setup to: " << temp_file.value();
412 ret = file_util::Move(setup_exe, temp_file); 487 ret = file_util::Move(setup_exe, temp_file);
413 PLOG_IF(ERROR, !ret) << "Failed to move setup to " << temp_file.value(); 488 PLOG_IF(ERROR, !ret) << "Failed to move setup to " << temp_file.value();
414 489
415 // We cannot delete the file right away, but try to delete it some other 490 // We cannot delete the file right away, but try to delete it some other
416 // way. Either with the help of a different process or the system. 491 // way. Either with the help of a different process or the system.
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
453 } 528 }
454 529
455 DeleteInstallTempDir(target_path); 530 DeleteInstallTempDir(target_path);
456 531
457 DeleteResult result = DELETE_SUCCEEDED; 532 DeleteResult result = DELETE_SUCCEEDED;
458 533
459 FilePath app_host_exe(target_path.Append(installer::kChromeAppHostExe)); 534 FilePath app_host_exe(target_path.Append(installer::kChromeAppHostExe));
460 if (!file_util::Delete(app_host_exe, false)) { 535 if (!file_util::Delete(app_host_exe, false)) {
461 result = DELETE_FAILED; 536 result = DELETE_FAILED;
462 LOG(ERROR) << "Failed to delete path: " << app_host_exe.value(); 537 LOG(ERROR) << "Failed to delete path: " << app_host_exe.value();
463 } else {
464 result = DeleteApplicationProductAndVendorDirectories(target_path);
465 } 538 }
466 539
467 return result; 540 return result;
468 } 541 }
469 542
470 DeleteResult DeleteChromeFilesAndFolders(const InstallerState& installer_state, 543 DeleteResult DeleteChromeFilesAndFolders(const InstallerState& installer_state,
471 const Version& installed_version) { 544 const FilePath& installer_path) {
472 const FilePath& target_path = installer_state.target_path(); 545 const FilePath& target_path = installer_state.target_path();
473 if (target_path.empty()) { 546 if (target_path.empty()) {
474 LOG(ERROR) << "DeleteChromeFilesAndFolders: no installation destination " 547 LOG(ERROR) << "DeleteChromeFilesAndFolders: no installation destination "
475 << "path."; 548 << "path.";
476 return DELETE_FAILED; // Nothing else we can do to uninstall, so we return. 549 return DELETE_FAILED; // Nothing else we can do to uninstall, so we return.
477 } 550 }
478 551
479 DeleteInstallTempDir(target_path); 552 DeleteInstallTempDir(target_path);
480 553
481 DeleteResult result = DELETE_SUCCEEDED; 554 DeleteResult result = DELETE_SUCCEEDED;
482 555
556 FilePath installer_directory;
557 if (target_path.IsParent(installer_path))
558 installer_directory = installer_path.DirName();
559
560 // Enumerate all the files in target_path recursively (breadth-first).
561 // We delete a file or folder unless it is a parent/child of the installer
562 // directory. For parents of the installer directory, we will later recurse
563 // and delete all the children (that are not also parents/children of the
564 // installer directory).
483 using file_util::FileEnumerator; 565 using file_util::FileEnumerator;
484 FileEnumerator file_enumerator(target_path, false, 566 FileEnumerator file_enumerator(
485 FileEnumerator::FILES | FileEnumerator::DIRECTORIES); 567 target_path, true, FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
486 while (true) { 568 while (true) {
487 FilePath to_delete(file_enumerator.Next()); 569 FilePath to_delete(file_enumerator.Next());
488 if (to_delete.empty()) 570 if (to_delete.empty())
489 break; 571 break;
490 if (to_delete.BaseName().value() == installer::kChromeAppHostExe) 572 if (to_delete.BaseName().value() == installer::kChromeAppHostExe)
491 continue; 573 continue;
574 if (!installer_directory.empty() &&
575 (to_delete == installer_directory ||
576 installer_directory.IsParent(to_delete) ||
577 to_delete.IsParent(installer_directory))) {
578 continue;
579 }
492 580
493 VLOG(1) << "Deleting install path " << to_delete.value(); 581 VLOG(1) << "Deleting install path " << to_delete.value();
494 if (!file_util::Delete(to_delete, true)) { 582 if (!file_util::Delete(to_delete, true)) {
495 LOG(ERROR) << "Failed to delete path (1st try): " << to_delete.value(); 583 LOG(ERROR) << "Failed to delete path (1st try): " << to_delete.value();
496 if (installer_state.FindProduct(BrowserDistribution::CHROME_FRAME)) { 584 if (installer_state.FindProduct(BrowserDistribution::CHROME_FRAME)) {
497 // We don't try killing Chrome processes for Chrome Frame builds since 585 // We don't try killing Chrome processes for Chrome Frame builds since
498 // that is unlikely to help. Instead, schedule files for deletion and 586 // that is unlikely to help. Instead, schedule files for deletion and
499 // return a value that will trigger a reboot prompt. 587 // return a value that will trigger a reboot prompt.
500 FileEnumerator::FindInfo find_info; 588 FileEnumerator::FindInfo find_info;
501 file_enumerator.GetFindInfo(&find_info); 589 file_enumerator.GetFindInfo(&find_info);
502 if (FileEnumerator::IsDirectory(find_info)) 590 if (FileEnumerator::IsDirectory(find_info))
503 ScheduleDirectoryForDeletion(to_delete.value().c_str()); 591 ScheduleDirectoryForDeletion(to_delete.value().c_str());
504 else 592 else
505 ScheduleFileSystemEntityForDeletion(to_delete.value().c_str()); 593 ScheduleFileSystemEntityForDeletion(to_delete.value().c_str());
506 result = DELETE_REQUIRES_REBOOT; 594 result = DELETE_REQUIRES_REBOOT;
507 } else { 595 } else {
508 // Try closing any running Chrome processes and deleting files once 596 // Try closing any running Chrome processes and deleting files once
509 // again. 597 // again.
510 CloseAllChromeProcesses(); 598 CloseAllChromeProcesses();
511 if (!file_util::Delete(to_delete, true)) { 599 if (!file_util::Delete(to_delete, true)) {
512 LOG(ERROR) << "Failed to delete path (2nd try): " 600 LOG(ERROR) << "Failed to delete path (2nd try): "
513 << to_delete.value(); 601 << to_delete.value();
514 result = DELETE_FAILED; 602 result = DELETE_FAILED;
515 break; 603 break;
516 } 604 }
517 } 605 }
518 } 606 }
519 } 607 }
520 608
521 if (result == DELETE_REQUIRES_REBOOT) {
522 // Delete the Application directory at reboot if empty.
523 ScheduleFileSystemEntityForDeletion(target_path.value().c_str());
524
525 // If we need a reboot to continue, schedule the parent directories for
526 // deletion unconditionally. If they are not empty, the session manager
527 // will not delete them on reboot.
528 ScheduleParentAndGrandparentForDeletion(target_path);
529 } else {
530 result = DeleteApplicationProductAndVendorDirectories(target_path);
531 }
532 return result; 609 return result;
533 } 610 }
534 611
535 // This method checks if Chrome is currently running or if the user has 612 // This method checks if Chrome is currently running or if the user has
536 // cancelled the uninstall operation by clicking Cancel on the confirmation 613 // cancelled the uninstall operation by clicking Cancel on the confirmation
537 // box that Chrome pops up. 614 // box that Chrome pops up.
538 InstallStatus IsChromeActiveOrUserCancelled( 615 InstallStatus IsChromeActiveOrUserCancelled(
539 const InstallerState& installer_state, 616 const InstallerState& installer_state,
540 const Product& product) { 617 const Product& product) {
541 int32 exit_code = content::RESULT_CODE_NORMAL_EXIT; 618 int32 exit_code = content::RESULT_CODE_NORMAL_EXIT;
(...skipping 674 matching lines...) Expand 10 before | Expand all | Expand 10 after
1216 product); 1293 product);
1217 ret = installer::UNINSTALL_SUCCESSFUL; 1294 ret = installer::UNINSTALL_SUCCESSFUL;
1218 1295
1219 // When deleting files, we must make sure that we're either a "single" 1296 // When deleting files, we must make sure that we're either a "single"
1220 // (aka non-multi) installation or we are the Chrome Binaries. 1297 // (aka non-multi) installation or we are the Chrome Binaries.
1221 1298
1222 std::vector<FilePath> local_state_folders; 1299 std::vector<FilePath> local_state_folders;
1223 GetLocalStateFolders(product, &local_state_folders); 1300 GetLocalStateFolders(product, &local_state_folders);
1224 FilePath backup_state_file(BackupLocalStateFile(local_state_folders)); 1301 FilePath backup_state_file(BackupLocalStateFile(local_state_folders));
1225 1302
1226 DeleteResult delete_result = DELETE_SUCCEEDED;
1227
1228 if (product.is_chrome_app_host()) { 1303 if (product.is_chrome_app_host()) {
1229 DeleteAppHostFilesAndFolders(installer_state, product_state->version()); 1304 DeleteAppHostFilesAndFolders(installer_state, product_state->version());
1230 } else if (!installer_state.is_multi_install() || 1305 } else if (!installer_state.is_multi_install() ||
1231 product.is_chrome_binaries()) { 1306 product.is_chrome_binaries()) {
1232 1307 DeleteResult delete_result = DeleteChromeFilesAndFolders(
1233 // In order to be able to remove the folder in which we're running, we 1308 installer_state, cmd_line.GetProgram());
1234 // need to move setup.exe out of the install folder. 1309 if (delete_result == DELETE_FAILED) {
1235 // TODO(tommi): What if the temp folder is on a different volume? 1310 ret = installer::UNINSTALL_FAILED;
1236 MoveSetupOutOfInstallFolder(installer_state, setup_path, 1311 } else if (delete_result == DELETE_REQUIRES_REBOOT) {
1237 product_state->version()); 1312 ret = installer::UNINSTALL_REQUIRES_REBOOT;
1238 delete_result = DeleteChromeFilesAndFolders(installer_state, 1313 }
1239 product_state->version());
1240 } 1314 }
1241 1315
1242 if (delete_profile) 1316 if (delete_profile)
1243 DeleteLocalState(local_state_folders, product.is_chrome_frame()); 1317 DeleteLocalState(local_state_folders, product.is_chrome_frame());
1244 1318
1245 if (delete_result == DELETE_FAILED) {
1246 ret = installer::UNINSTALL_FAILED;
1247 } else if (delete_result == DELETE_REQUIRES_REBOOT) {
1248 ret = installer::UNINSTALL_REQUIRES_REBOOT;
1249 }
1250
1251 if (!force_uninstall) { 1319 if (!force_uninstall) {
1252 VLOG(1) << "Uninstallation complete. Launching post-uninstall operations."; 1320 VLOG(1) << "Uninstallation complete. Launching post-uninstall operations.";
1253 browser_dist->DoPostUninstallOperations(product_state->version(), 1321 browser_dist->DoPostUninstallOperations(product_state->version(),
1254 backup_state_file, distribution_data); 1322 backup_state_file, distribution_data);
1255 } 1323 }
1256 1324
1257 // Try and delete the preserved local state once the post-install 1325 // Try and delete the preserved local state once the post-install
1258 // operations are complete. 1326 // operations are complete.
1259 if (!backup_state_file.empty()) 1327 if (!backup_state_file.empty())
1260 file_util::Delete(backup_state_file, false); 1328 file_util::Delete(backup_state_file, false);
1261 1329
1262 // If user-level Chrome is being uninstalled and system-level Chrome is 1330 // If user-level Chrome is being uninstalled and system-level Chrome is
1263 // present, launch the system-level Active Setup command to do post-install 1331 // present, launch the system-level Active Setup command to do post-install
1264 // tasks for this user (i.e., create shortcuts). 1332 // tasks for this user (i.e., create shortcuts).
1265 if (product.is_chrome() && !installer_state.system_install() && 1333 if (product.is_chrome() && !installer_state.system_install() &&
1266 original_state.GetProductState(true, browser_dist->GetType())) { 1334 original_state.GetProductState(true, browser_dist->GetType())) {
1267 InstallUtil::TriggerActiveSetupCommand(); 1335 InstallUtil::TriggerActiveSetupCommand();
1268 } 1336 }
1269 1337
1270 return ret; 1338 return ret;
1271 } 1339 }
1272 1340
1341 void CleanUpInstallationDirectoryAfterUninstall(
1342 const InstallationState& original_state,
1343 const InstallerState& installer_state,
1344 const CommandLine& cmd_line,
1345 installer::InstallStatus* uninstall_status) {
1346 if (*uninstall_status != installer::UNINSTALL_SUCCESSFUL &&
1347 *uninstall_status != installer::UNINSTALL_REQUIRES_REBOOT) {
1348 return;
1349 }
1350 const FilePath target_path(installer_state.target_path());
1351 if (target_path.empty()) {
1352 LOG(ERROR) << "No installation destination path.";
1353 *uninstall_status = installer::UNINSTALL_FAILED;
1354 return;
1355 }
1356 FilePath setup_exe(cmd_line.GetProgram());
1357 file_util::AbsolutePath(&setup_exe);
1358 if (!target_path.IsParent(setup_exe)) {
1359 LOG(INFO) << "setup.exe is not in target path. Skipping installer cleanup.";
1360 return;
1361 }
1362 FilePath install_directory(setup_exe.DirName());
1363
1364 bool remove_setup = true;
1365 bool remove_archive = true;
1366 CheckShouldRemoveSetupAndArchive(original_state, installer_state,
1367 &remove_setup, &remove_archive);
1368 if (!remove_archive)
1369 return;
1370
1371 if (remove_setup) {
1372 // In order to be able to remove the folder in which we're running, we
1373 // need to move setup.exe out of the install folder.
1374 // TODO(tommi): What if the temp folder is on a different volume?
1375 MoveSetupOutOfInstallFolder(installer_state, setup_exe);
1376 }
1377
1378 // Remove files from "...\<product>\Application\<version>\Installer"
1379 if (!RemoveInstallerFiles(install_directory, remove_setup)) {
1380 *uninstall_status = installer::UNINSTALL_FAILED;
1381 return;
1382 }
1383
1384 if (!remove_setup)
1385 return;
1386
1387 // Try to remove the empty directory hierarchy.
1388
1389 // Delete "...\<product>\Application\<version>\Installer"
1390 if (DeleteEmptyDir(install_directory) != DELETE_SUCCEEDED) {
1391 *uninstall_status = installer::UNINSTALL_FAILED;
1392 return;
1393 }
1394
1395 // Delete "...\<product>\Application\<version>"
1396 DeleteResult delete_result = DeleteEmptyDir(install_directory.DirName());
1397 if (delete_result == DELETE_FAILED ||
1398 (delete_result == DELETE_NOT_EMPTY &&
1399 *uninstall_status != installer::UNINSTALL_REQUIRES_REBOOT)) {
1400 *uninstall_status = installer::UNINSTALL_FAILED;
1401 return;
1402 }
1403
1404 if (*uninstall_status == installer::UNINSTALL_REQUIRES_REBOOT) {
1405 // Delete the Application directory at reboot if empty.
1406 ScheduleFileSystemEntityForDeletion(target_path.value().c_str());
1407
1408 // If we need a reboot to continue, schedule the parent directories for
1409 // deletion unconditionally. If they are not empty, the session manager
1410 // will not delete them on reboot.
1411 ScheduleParentAndGrandparentForDeletion(target_path);
1412 } else if (DeleteApplicationProductAndVendorDirectories(target_path) ==
1413 installer::DELETE_FAILED) {
1414 *uninstall_status = installer::UNINSTALL_FAILED;
1415 }
1416 }
1417
1273 } // namespace installer 1418 } // namespace installer
OLDNEW
« no previous file with comments | « chrome/installer/setup/uninstall.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698