blob: 0c22c86e08fddf9b097bfa7d6b7a8138f7b0c519 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/chrome_cleaner/engines/controllers/engine_cleaner.h"
#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "chrome/chrome_cleaner/engines/broker/logging_conversion.h"
#include "chrome/chrome_cleaner/engines/common/engine_result_codes.h"
#include "chrome/chrome_cleaner/logging/logging_service_api.h"
#include "chrome/chrome_cleaner/logging/proto/removal_status.pb.h"
#include "chrome/chrome_cleaner/os/file_removal_status_updater.h"
#include "chrome/chrome_cleaner/pup_data/pup_data.h"
namespace chrome_cleaner {
namespace {
void UpdateStatusOfMissingMatchedFiles(const std::vector<UwSId>& pup_ids) {
for (const auto& pup_id : pup_ids) {
PUPData::PUP* pup = PUPData::GetPUP(pup_id);
for (const base::FilePath& file_path :
pup->expanded_disk_footprints.file_paths()) {
// If the file was explicitly and successfully removed before, its status
// won't change. If the file was temporary and has disappeared on its own,
// update its status to REMOVAL_STATUS_NOT_FOUND.
if (!base::PathExists(file_path)) {
FileRemovalStatusUpdater::GetInstance()->UpdateRemovalStatus(
file_path, REMOVAL_STATUS_NOT_FOUND);
}
}
}
}
} // namespace
EngineCleaner::EngineCleaner(EngineClient* engine_client)
: engine_client_(engine_client),
task_runner_(base::SequencedTaskRunnerHandle::Get()) {
DCHECK(engine_client);
}
EngineCleaner::~EngineCleaner() = default;
void EngineCleaner::Start(const std::vector<UwSId>& pup_ids,
DoneCallback done_callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(done_callback);
DCHECK(!is_cleaning_);
CHECK(CanClean(pup_ids)) << "Attempt to remove UwS not enabled for cleaning";
done_callback_ = std::move(done_callback);
is_cleaning_ = true;
pups_to_clean_ = pup_ids;
// base::Unretained is safe because this object is owned by EngineFacade,
// which lives until program exit.
uint32_t result = engine_client_->StartCleanup(
pup_ids,
base::BindOnce(&EngineCleaner::OnCleanupDone, base::Unretained(this)));
if (result != EngineResultCode::kSuccess)
OnCleanupDone(result);
}
void EngineCleaner::StartPostReboot(const std::vector<UwSId>& pup_ids,
DoneCallback done_callback) {
Start(pup_ids, std::move(done_callback));
}
void EngineCleaner::Stop() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (IsCompletelyDone())
return;
// Don't actually try to cancel the engine. It will simply be killed as
// we exit.
HandleCleanupDone(EngineResultCode::kCancelled);
}
bool EngineCleaner::IsCompletelyDone() const {
return !is_cleaning_;
}
bool EngineCleaner::CanClean(const std::vector<UwSId>& pup_ids) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return PUPData::HasFlaggedPUP(pup_ids, &PUPData::HasRemovalFlag);
}
void EngineCleaner::HandleCleanupDone(uint32_t result) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// TODO(joenotcharles): This used to be called twice if the user cancelled
// after a HandleCleanupDone task had already been posted. Check if this is
// still possible and remove the test if not.
if (is_cleaning_) {
is_cleaning_ = false;
ResultCode engine_result =
CleaningResultCode(result, engine_client_->needs_reboot());
// Check if all files that were detected during the scanning were
// successfully removed. This is a best-effort check, as the logging service
// is not guaranteed to have information about all files.
UpdateStatusOfMissingMatchedFiles(pups_to_clean_);
if (!LoggingServiceAPI::GetInstance()->AllExpectedRemovalsConfirmed()) {
LOG(ERROR) << "Engine failed to delete some of the detected files";
// Override only successful result codes.
// If the engine requested reboot (RESULT_CODE_PENDING_REBOOT), go for it
// even if not all detected files were deleted, as we want the user to
// delete scheduled for post-reboot removal files ASAP.
if (engine_result == RESULT_CODE_SUCCESS)
engine_result = RESULT_CODE_FAILED;
}
std::move(done_callback_).Run(engine_result);
}
}
void EngineCleaner::OnCleanupDone(uint32_t result) {
DCHECK_NE(result, EngineResultCode::kCancelled); // Deprecated.
engine_client_->MaybeLogResultCode(EngineClient::Operation::ScanDoneCallback,
result);
// base::Unretained is safe because this object is owned by EngineFacade,
// which lives until program exit.
task_runner_->PostTask(FROM_HERE,
base::BindOnce(&EngineCleaner::HandleCleanupDone,
base::Unretained(this), result));
}
} // namespace chrome_cleaner