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

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: Remove unused method. Created 8 years 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 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) {
203 BrowserDistribution::Type dist_type =
204 static_cast<BrowserDistribution::Type>(i);
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 "
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 // Removes all files from the installer directory, leaving setup.exe iff
228 // |remove_setup| is false.
229 // Returns false in case of an error.
230 bool RemoveInstallerFiles(const FilePath& install_directory,
231 bool remove_setup) {
232 using file_util::FileEnumerator;
233 FileEnumerator file_enumerator(
234 install_directory,
235 false,
236 FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
237 bool success = true;
238
239 while (true) {
240 FilePath to_delete(file_enumerator.Next());
241 if (to_delete.empty())
242 break;
243 if (!remove_setup && to_delete.BaseName() == FilePath(installer::kSetupExe))
grt (UTC plus 2) 2012/11/23 21:00:55 nit: create this FilePath instance out of the loop
erikwright (departed) 2012/11/29 07:40:36 Done.
244 continue;
245
246 VLOG(1) << "Deleting install path " << to_delete.value();
247 if (!file_util::Delete(to_delete, true)) {
248 LOG(ERROR) << "Failed to delete path: " << to_delete.value();
249 success = false;
250 }
251 }
252
253 return success;
254 }
255
184 } // namespace 256 } // namespace
185 257
186 namespace installer { 258 namespace installer {
187 259
188 // This functions checks for any Chrome instances that are 260 // This functions checks for any Chrome instances that are
189 // running and first asks them to close politely by sending a Windows message. 261 // 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 262 // 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 263 // procesess active after the message has been sent, this function will try
192 // to kill them. 264 // to kill them.
193 void CloseAllChromeProcesses() { 265 void CloseAllChromeProcesses() {
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after
403 const FilePath product_dir(user_data_dir.DirName()); 475 const FilePath product_dir(user_data_dir.DirName());
404 if (!product_dir.empty()) 476 if (!product_dir.empty())
405 DeleteEmptyDir(product_dir); 477 DeleteEmptyDir(product_dir);
406 } 478 }
407 } 479 }
408 480
409 return result; 481 return result;
410 } 482 }
411 483
412 bool MoveSetupOutOfInstallFolder(const InstallerState& installer_state, 484 bool MoveSetupOutOfInstallFolder(const InstallerState& installer_state,
413 const FilePath& setup_path, 485 const FilePath& setup_exe) {
414 const Version& installed_version) {
415 bool ret = false; 486 bool ret = false;
416 FilePath setup_exe(installer_state.GetInstallerDirectory(installed_version)
417 .Append(setup_path.BaseName()));
418 FilePath temp_file; 487 FilePath temp_file;
419 if (!file_util::CreateTemporaryFile(&temp_file)) { 488 if (!file_util::CreateTemporaryFile(&temp_file)) {
420 LOG(ERROR) << "Failed to create temporary file for setup.exe."; 489 LOG(ERROR) << "Failed to create temporary file for setup.exe.";
421 } else { 490 } else {
422 VLOG(1) << "Attempting to move setup to: " << temp_file.value(); 491 VLOG(1) << "Attempting to move setup to: " << temp_file.value();
423 ret = file_util::Move(setup_exe, temp_file); 492 ret = file_util::Move(setup_exe, temp_file);
424 PLOG_IF(ERROR, !ret) << "Failed to move setup to " << temp_file.value(); 493 PLOG_IF(ERROR, !ret) << "Failed to move setup to " << temp_file.value();
425 494
426 // We cannot delete the file right away, but try to delete it some other 495 // We cannot delete the file right away, but try to delete it some other
427 // way. Either with the help of a different process or the system. 496 // way. Either with the help of a different process or the system.
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
464 } 533 }
465 534
466 DeleteInstallTempDir(target_path); 535 DeleteInstallTempDir(target_path);
467 536
468 DeleteResult result = DELETE_SUCCEEDED; 537 DeleteResult result = DELETE_SUCCEEDED;
469 538
470 FilePath app_host_exe(target_path.Append(installer::kChromeAppHostExe)); 539 FilePath app_host_exe(target_path.Append(installer::kChromeAppHostExe));
471 if (!file_util::Delete(app_host_exe, false)) { 540 if (!file_util::Delete(app_host_exe, false)) {
472 result = DELETE_FAILED; 541 result = DELETE_FAILED;
473 LOG(ERROR) << "Failed to delete path: " << app_host_exe.value(); 542 LOG(ERROR) << "Failed to delete path: " << app_host_exe.value();
474 } else {
475 result = DeleteApplicationProductAndVendorDirectories(target_path);
476 } 543 }
477 544
478 return result; 545 return result;
479 } 546 }
480 547
481 DeleteResult DeleteChromeFilesAndFolders(const InstallerState& installer_state, 548 DeleteResult DeleteChromeFilesAndFolders(const InstallerState& installer_state,
482 const Version& installed_version) { 549 const FilePath& installer_path) {
483 const FilePath& target_path = installer_state.target_path(); 550 const FilePath& target_path = installer_state.target_path();
484 if (target_path.empty()) { 551 if (target_path.empty()) {
485 LOG(ERROR) << "DeleteChromeFilesAndFolders: no installation destination " 552 LOG(ERROR) << "DeleteChromeFilesAndFolders: no installation destination "
486 << "path."; 553 << "path.";
487 return DELETE_FAILED; // Nothing else we can do to uninstall, so we return. 554 return DELETE_FAILED; // Nothing else we can do to uninstall, so we return.
488 } 555 }
489 556
490 DeleteInstallTempDir(target_path); 557 DeleteInstallTempDir(target_path);
491 558
492 DeleteResult result = DELETE_SUCCEEDED; 559 DeleteResult result = DELETE_SUCCEEDED;
493 560
561 FilePath installer_directory;
562 if (target_path.IsParent(installer_path))
563 installer_directory = installer_path.DirName();
564
565 // Enumerate all the files in target_path recursively (breadth-first).
566 // We delete a file or folder unless it is a parent/child of the installer
567 // directory. For parents of the installer directory, we will later recurse
568 // and delete all the children (that are not also parents/children of the
569 // installer directory).
494 using file_util::FileEnumerator; 570 using file_util::FileEnumerator;
495 FileEnumerator file_enumerator(target_path, false, 571 FileEnumerator file_enumerator(
496 FileEnumerator::FILES | FileEnumerator::DIRECTORIES); 572 target_path, true, FileEnumerator::FILES | FileEnumerator::DIRECTORIES);
497 while (true) { 573 while (true) {
498 FilePath to_delete(file_enumerator.Next()); 574 FilePath to_delete(file_enumerator.Next());
499 if (to_delete.empty()) 575 if (to_delete.empty())
500 break; 576 break;
501 if (to_delete.BaseName().value() == installer::kChromeAppHostExe) 577 if (to_delete.BaseName().value() == installer::kChromeAppHostExe)
502 continue; 578 continue;
579 if (!installer_directory.empty() &&
580 (to_delete == installer_directory ||
581 installer_directory.IsParent(to_delete) ||
582 to_delete.IsParent(installer_directory))) {
583 continue;
584 }
503 585
504 VLOG(1) << "Deleting install path " << to_delete.value(); 586 VLOG(1) << "Deleting install path " << to_delete.value();
505 if (!file_util::Delete(to_delete, true)) { 587 if (!file_util::Delete(to_delete, true)) {
506 LOG(ERROR) << "Failed to delete path (1st try): " << to_delete.value(); 588 LOG(ERROR) << "Failed to delete path (1st try): " << to_delete.value();
507 if (installer_state.FindProduct(BrowserDistribution::CHROME_FRAME)) { 589 if (installer_state.FindProduct(BrowserDistribution::CHROME_FRAME)) {
508 // We don't try killing Chrome processes for Chrome Frame builds since 590 // We don't try killing Chrome processes for Chrome Frame builds since
509 // that is unlikely to help. Instead, schedule files for deletion and 591 // that is unlikely to help. Instead, schedule files for deletion and
510 // return a value that will trigger a reboot prompt. 592 // return a value that will trigger a reboot prompt.
511 FileEnumerator::FindInfo find_info; 593 FileEnumerator::FindInfo find_info;
512 file_enumerator.GetFindInfo(&find_info); 594 file_enumerator.GetFindInfo(&find_info);
513 if (FileEnumerator::IsDirectory(find_info)) 595 if (FileEnumerator::IsDirectory(find_info))
514 ScheduleDirectoryForDeletion(to_delete.value().c_str()); 596 ScheduleDirectoryForDeletion(to_delete.value().c_str());
515 else 597 else
516 ScheduleFileSystemEntityForDeletion(to_delete.value().c_str()); 598 ScheduleFileSystemEntityForDeletion(to_delete.value().c_str());
517 result = DELETE_REQUIRES_REBOOT; 599 result = DELETE_REQUIRES_REBOOT;
518 } else { 600 } else {
519 // Try closing any running Chrome processes and deleting files once 601 // Try closing any running Chrome processes and deleting files once
520 // again. 602 // again.
521 CloseAllChromeProcesses(); 603 CloseAllChromeProcesses();
522 if (!file_util::Delete(to_delete, true)) { 604 if (!file_util::Delete(to_delete, true)) {
523 LOG(ERROR) << "Failed to delete path (2nd try): " 605 LOG(ERROR) << "Failed to delete path (2nd try): "
524 << to_delete.value(); 606 << to_delete.value();
525 result = DELETE_FAILED; 607 result = DELETE_FAILED;
526 break; 608 break;
527 } 609 }
528 } 610 }
529 } 611 }
530 } 612 }
531 613
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; 614 return result;
544 } 615 }
545 616
546 // This method checks if Chrome is currently running or if the user has 617 // This method checks if Chrome is currently running or if the user has
547 // cancelled the uninstall operation by clicking Cancel on the confirmation 618 // cancelled the uninstall operation by clicking Cancel on the confirmation
548 // box that Chrome pops up. 619 // box that Chrome pops up.
549 InstallStatus IsChromeActiveOrUserCancelled( 620 InstallStatus IsChromeActiveOrUserCancelled(
550 const InstallerState& installer_state, 621 const InstallerState& installer_state,
551 const Product& product) { 622 const Product& product) {
552 int32 exit_code = content::RESULT_CODE_NORMAL_EXIT; 623 int32 exit_code = content::RESULT_CODE_NORMAL_EXIT;
(...skipping 674 matching lines...) Expand 10 before | Expand all | Expand 10 after
1227 product); 1298 product);
1228 ret = installer::UNINSTALL_SUCCESSFUL; 1299 ret = installer::UNINSTALL_SUCCESSFUL;
1229 1300
1230 // When deleting files, we must make sure that we're either a "single" 1301 // When deleting files, we must make sure that we're either a "single"
1231 // (aka non-multi) installation or we are the Chrome Binaries. 1302 // (aka non-multi) installation or we are the Chrome Binaries.
1232 1303
1233 std::vector<FilePath> local_state_folders; 1304 std::vector<FilePath> local_state_folders;
1234 GetLocalStateFolders(product, &local_state_folders); 1305 GetLocalStateFolders(product, &local_state_folders);
1235 FilePath backup_state_file(BackupLocalStateFile(local_state_folders)); 1306 FilePath backup_state_file(BackupLocalStateFile(local_state_folders));
1236 1307
1237 DeleteResult delete_result = DELETE_SUCCEEDED;
1238
1239 if (product.is_chrome_app_host()) { 1308 if (product.is_chrome_app_host()) {
1240 DeleteAppHostFilesAndFolders(installer_state, product_state->version()); 1309 DeleteAppHostFilesAndFolders(installer_state, product_state->version());
1241 } else if (!installer_state.is_multi_install() || 1310 } else if (!installer_state.is_multi_install() ||
1242 product.is_chrome_binaries()) { 1311 product.is_chrome_binaries()) {
1243 1312 DeleteResult delete_result = DeleteChromeFilesAndFolders(
1244 // In order to be able to remove the folder in which we're running, we 1313 installer_state, cmd_line.GetProgram());
1245 // need to move setup.exe out of the install folder. 1314 if (delete_result == DELETE_FAILED) {
1246 // TODO(tommi): What if the temp folder is on a different volume? 1315 ret = installer::UNINSTALL_FAILED;
1247 MoveSetupOutOfInstallFolder(installer_state, setup_path, 1316 } else if (delete_result == DELETE_REQUIRES_REBOOT) {
1248 product_state->version()); 1317 ret = installer::UNINSTALL_REQUIRES_REBOOT;
1249 delete_result = DeleteChromeFilesAndFolders(installer_state, 1318 }
1250 product_state->version());
1251 } 1319 }
1252 1320
1253 if (delete_profile) 1321 if (delete_profile)
1254 DeleteLocalState(local_state_folders, product.is_chrome_frame()); 1322 DeleteLocalState(local_state_folders, product.is_chrome_frame());
1255 1323
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) { 1324 if (!force_uninstall) {
1263 VLOG(1) << "Uninstallation complete. Launching post-uninstall operations."; 1325 VLOG(1) << "Uninstallation complete. Launching post-uninstall operations.";
1264 browser_dist->DoPostUninstallOperations(product_state->version(), 1326 browser_dist->DoPostUninstallOperations(product_state->version(),
1265 backup_state_file, distribution_data); 1327 backup_state_file, distribution_data);
1266 } 1328 }
1267 1329
1268 // Try and delete the preserved local state once the post-install 1330 // Try and delete the preserved local state once the post-install
1269 // operations are complete. 1331 // operations are complete.
1270 if (!backup_state_file.empty()) 1332 if (!backup_state_file.empty())
1271 file_util::Delete(backup_state_file, false); 1333 file_util::Delete(backup_state_file, false);
1272 1334
1273 return ret; 1335 return ret;
1274 } 1336 }
1275 1337
1338 void CleanUpInstallationDirectoryAfterUninstall(
1339 const InstallationState& original_state,
1340 const InstallerState& installer_state,
1341 const CommandLine& cmd_line,
1342 installer::InstallStatus* uninstall_status) {
1343 if (*uninstall_status != installer::UNINSTALL_SUCCESSFUL &&
1344 *uninstall_status != installer::UNINSTALL_REQUIRES_REBOOT) {
1345 return;
1346 }
1347 const FilePath target_path(installer_state.target_path());
1348 if (target_path.empty()) {
1349 LOG(ERROR) << "No installation destination path.";
1350 *uninstall_status = installer::UNINSTALL_FAILED;
1351 return;
1352 }
1353 const FilePath setup_exe = cmd_line.GetProgram();
grt (UTC plus 2) 2012/11/23 21:00:55 wdyt about using file_util::AbsolutePath here in c
erikwright (departed) 2012/11/29 07:40:36 From my reading of GetCommandLine (which is what C
grt (UTC plus 2) 2012/11/30 13:40:30 I believe gab@ has run into cases where it isn't f
gab 2012/11/30 15:19:45 Right, I think it's the path setup.exe was invoked
1354 if (!target_path.IsParent(setup_exe)) {
1355 LOG(INFO) << "setup.exe is not in target path. Skipping installer cleanup.";
1356 return;
1357 }
1358 FilePath install_directory(setup_exe.DirName());
1359
1360 bool remove_setup = true;
1361 bool remove_archive = true;
1362 CheckShouldRemoveSetupAndArchive(original_state, installer_state,
1363 &remove_setup, &remove_archive);
1364 if (!remove_archive)
1365 return;
1366
1367 if (remove_setup) {
1368 // In order to be able to remove the folder in which we're running, we
1369 // need to move setup.exe out of the install folder.
1370 // TODO(tommi): What if the temp folder is on a different volume?
1371 MoveSetupOutOfInstallFolder(installer_state, setup_exe);
1372 }
1373
grt (UTC plus 2) 2012/11/23 21:00:55 // Remove files from "...\<product>\Application\<v
erikwright (departed) 2012/11/29 07:40:36 Done.
1374 if (!RemoveInstallerFiles(install_directory, remove_setup)) {
1375 *uninstall_status = installer::UNINSTALL_FAILED;
1376 return;
1377 }
1378
1379 if (!remove_setup)
1380 return;
1381
1382 // Try to remove the empty directory hierarchy.
1383
grt (UTC plus 2) 2012/11/23 21:00:55 // Delete "...\<product>\Application\<version>\Ins
erikwright (departed) 2012/11/29 07:40:36 Done.
1384 if (DeleteEmptyDir(install_directory) != DELETE_SUCCEEDED) {
1385 *uninstall_status = installer::UNINSTALL_FAILED;
1386 return;
1387 }
1388
grt (UTC plus 2) 2012/11/23 21:00:55 // Delete "...\<product>\Application\<version>"
erikwright (departed) 2012/11/29 07:40:36 Done.
1389 FilePath to_delete = install_directory.DirName();
1390 while (to_delete != target_path) {
grt (UTC plus 2) 2012/11/23 21:00:55 isn't the loop overkill? it looks like the versio
erikwright (departed) 2012/11/29 07:40:36 I guess I was trying not to code that dependency i
1391 DeleteResult delete_result = DeleteEmptyDir(to_delete);
1392 if (delete_result == DELETE_SUCCEEDED) {
1393 to_delete = to_delete.DirName();
1394 continue;
1395 }
1396 if (delete_result == DELETE_NOT_EMPTY &&
1397 *uninstall_status == installer::UNINSTALL_REQUIRES_REBOOT) {
1398 break;
1399 }
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
1276 } // 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