blob: a8ddecc3ea28d14ebf16607743a6a3d0d187a491 [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/scanner_impl.h"
#include <utility>
#include <vector>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/check_op.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "chrome/chrome_cleaner/constants/uws_id.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/settings/settings.h"
#include "components/chrome_cleaner/public/constants/result_codes.h"
namespace chrome_cleaner {
ScannerImpl::ScannerImpl(EngineClient* engine_client)
: engine_client_(engine_client),
task_runner_(base::SequencedTaskRunnerHandle::Get()) {
DCHECK(engine_client_);
}
ScannerImpl::~ScannerImpl() {
CHECK(!is_scanning_);
}
bool ScannerImpl::Start(const FoundUwSCallback& found_uws_callback,
DoneCallback done_callback) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!is_scanning_);
is_scanning_ = true;
DCHECK(found_uws_callback);
DCHECK(done_callback);
found_uws_callback_ = found_uws_callback;
done_callback_ = std::move(done_callback);
DCHECK(Settings::GetInstance()->scan_switches_correct());
std::vector<UwS::TraceLocation> enabled_locations =
Settings::GetInstance()->locations_to_scan();
LoggingServiceAPI::GetInstance()->SetScannedLocations(enabled_locations);
// base::Unretained is safe because this object is owned by EngineFacade,
// which lives until program exit.
uint32_t result = engine_client_->StartScan(
engine_client_->GetEnabledUwS(), enabled_locations,
/*include_details=*/true,
base::BindRepeating(&ScannerImpl::OnFoundUwS, base::Unretained(this)),
base::BindOnce(&ScannerImpl::OnScanDone, base::Unretained(this)));
if (result != EngineResultCode::kSuccess) {
OnScanDone(result);
return false;
}
return true;
}
void ScannerImpl::Stop() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (IsCompletelyDone())
return;
// Don't actually try to cancel the sandboxed engine. It will simply be killed
// as we exit.
HandleScanDone(EngineResultCode::kCancelled);
}
bool ScannerImpl::IsCompletelyDone() const {
return !is_scanning_;
}
void ScannerImpl::HandleFoundUwS(UwSId pup_id, const PUPData::PUP& pup) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(is_scanning_);
if (found_uws_.find(pup_id) == found_uws_.end()) {
// Note this calls |found_uws_callback_| even for UwS that will be
// discarded during HandleScanDone (eg. if it has no files or the ID is
// unsupported.) This is necessary because |found_uws_callback_| updates
// state for the watchdog timeout, so if we wait until HandleScanDone it
// might be too late.
found_uws_callback_.Run(pup_id);
}
found_uws_.insert(pup_id);
// HandleScanDone will handle invalid UwS case when invoked. Postpone the
// decision for the moment.
if (!PUPData::IsKnownPUP(pup_id))
return;
PUPData::GetPUP(pup_id)->MergeFrom(pup);
}
void ScannerImpl::HandleScanDone(uint32_t result) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!is_scanning_) {
// 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.
return;
}
// Log details of all UwS found during the scan. This must be done at the
// end of the scan because the sandboxed engine updates files found for each
// UwS in parallel.
std::vector<UwSId> supported_uws;
bool found_unsupported_uws = false;
for (UwSId pup_id : found_uws_) {
switch (UwSLoggingDecision(pup_id)) {
case LoggingDecision::kUnsupported:
found_unsupported_uws = true;
break;
case LoggingDecision::kNotLogged:
// Do nothing.
break;
case LoggingDecision::kLogged:
LoggingServiceAPI::GetInstance()->AddDetectedUwS(
PUPData::GetPUP(pup_id), kUwSDetectedFlagsNone);
supported_uws.push_back(pup_id);
break;
}
}
is_scanning_ = false;
ResultCode result_code = found_unsupported_uws
? RESULT_CODE_ENGINE_REPORTED_UNSUPPORTED_UWS
: ScanningResultCode(result);
std::move(done_callback_).Run(result_code, supported_uws);
}
void ScannerImpl::OnFoundUwS(UwSId pup_id, const PUPData::PUP& pup) {
// base::Unretained is safe because this object is owned by EngineFacade,
// which lives until program exit.
task_runner_->PostTask(FROM_HERE,
base::BindOnce(&ScannerImpl::HandleFoundUwS,
base::Unretained(this), pup_id, pup));
}
void ScannerImpl::OnScanDone(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(&ScannerImpl::HandleScanDone,
base::Unretained(this), result));
}
} // namespace chrome_cleaner