blob: ed5b3fd7c3db3bde2e248bc0a467b3dcf4e7f30f [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 <windows.h>
#include <restartmanager.h>
#include <map>
#include <memory>
#include <vector>
#include "base/callback_forward.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/sequence_checker.h"
#include "base/strings/string16.h"
#include "base/synchronization/lock.h"
#include "base/threading/watchdog.h"
#include "chrome/chrome_cleaner/cleaner/cleaner.h"
#include "chrome/chrome_cleaner/components/component_api.h"
#include "chrome/chrome_cleaner/components/component_manager.h"
#include "chrome/chrome_cleaner/constants/uws_id.h"
#include "chrome/chrome_cleaner/engines/controllers/engine_facade_interface.h"
#include "chrome/chrome_cleaner/ipc/chrome_prompt_ipc.h"
#include "chrome/chrome_cleaner/ipc/sandbox.h"
#include "chrome/chrome_cleaner/scanner/scanner.h"
#include "chrome/chrome_cleaner/settings/settings_types.h"
#include "chrome/chrome_cleaner/ui/main_dialog_api.h"
#include "components/chrome_cleaner/public/constants/result_codes.h"
namespace chrome_cleaner {
class ComponentAPI;
class RebooterAPI;
class RegistryLogger;
enum class TimedOutStage {
// The class used by the main entry point to connect the dots between the UI,
// the scanner, cleaner and other components. It works as a state machine in the
// following manner:
// - Starts with either a ScanAndClean() or a ValidateCleanup()
// - ScanAndClean()
// - Set the "main dialog" to scan mode. (Actually a legacy name, this
// class now delegates UI actions to Chrome.)
// - Call the Component Manager's PreScan method.
// - Called back when PreScan is done for all components.
// - Start the scanner and run the main message loop.
// - Called back when scanning is done.
// - Call the Component Manager's PostScan method.
// - Called back when PostScan is done for all components.
// - If no PUPs are found let the user know about it, wait for OnClose
// to be called, and return proper exit code.
// - If PUPs are found, get the cleanup requirements.
// - If the requirements failed, do as if No PUPs was found.
// - Once requirements are confirmed, the user is asked for confirm
// the cleanup, wait for answer callback.
// - If user refuses, exit with proper exit code.
// - If user accepts, the pre-cleanup custom actions are executed.
// - If one of the actions fails, exit with proper exit code.
// - Call the Component Manager's PreCleanup method.
// - Called back when PreCleanup is done for all components.
// - Set the main dialog to cleanup mode.
// - Start Cleaner, and wait for done call back.
// - Once cleanup completes, call the Component Manager's
// PostCleanup method.
// - Called back when PostCleanup is done for all components.
// - Show the final UI to user, and wait for OnClose to be
// called.
// - Call the Component Manager's CloseAllComponents method.
// - Return proper exit code.
// - ValidateCleanup()
// - Start the scanner and run the main message loop.
// - Called back when scanning is done.
// - If nothing was found, exit with proper exit code.
// - If something was found, make a last attempt at removing files that
// would have been left over before rebooting.
// TODO(joenotcharles): Clean this chain of callbacks up a lot. This looks like
// a great case for futures!
class MainController : public ComponentManagerDelegate,
public MainDialogDelegate {
// Provide conditional object at construction time for easier mocking and to
// do the reporter / cleaner duality resolution outside the controller.
// Ownership of |signature_matcher| and |registry_logger| are NOT transferred
// to this class so the passed instances MUST outlive this MainController
// instance. RegistryLogger has internal state, so cannot be const-reference,
// cannot be null and must outlive the MainController.
MainController(RebooterAPI* rebooter,
RegistryLogger* registry_logger,
ChromePromptIPC* chrome_prompt_ipc);
~MainController() override;
// Add a new component to be called before the scan and after the cleanup. The
// MainController takes ownership of the component.
void AddComponent(std::unique_ptr<ComponentAPI> component);
// Sets the engine that will be used for scanning and cleaning.
void SetEngineFacade(EngineFacadeInterface* engine_facade);
// Start a new scan.
ResultCode ScanAndClean();
// Start a post-reboot validation scan.
ResultCode ValidateCleanup();
// Returns a callback that should be called with the sandbox type when an IPC
// connection to a sandbox closes and will terminate the process.
SandboxConnectionErrorCallback GetSandboxConnectionErrorCallback();
virtual MainDialogAPI* main_dialog();
// Allow tests to override watchdog timeouts.
base::TimeDelta scanning_watchdog_timeout_;
base::TimeDelta user_response_watchdog_timeout_;
base::TimeDelta cleaning_watchdog_timeout_;
class ChromePromptConnectionErrorHandler;
friend class ChromePromptConnectionErrorHandler;
static void CallSandboxConnectionClosed(
scoped_refptr<base::SequencedTaskRunner> task_runner,
base::WeakPtr<MainController> main_controller,
SandboxType sandbox_type);
void FoundUwSCallback(UwSId pup_id);
// The callback for a regular/new scan. |found_pups| contains the
// IDs of the found PUPs.
void DoneScanning(ResultCode status, const std::vector<UwSId>& found_pups);
// The callback when running a post-reboot validating scan.
void DoneValidating(ResultCode status, const std::vector<UwSId>& found_pups);
// The callback when running last-attempt cleaning after validating scan.
void DoneCleanupValidation(ResultCode validation_code);
// Interrupts scan on broken connection error. This will be posted by
// ConnectionErrorHandler::OnConnectionClosed() on the thread used by main
// controller.
void OnChromePromptConnectionClosed();
void OnSandboxConnectionClosed(SandboxType sandbox_type);
// The callback for regular cleanup.
void CleanupDone(ResultCode clean_result);
// ComponentManagerDelegate.
void PreScanDone() override;
void PostScanDone() override;
void PreCleanupDone() override;
void PostCleanupDone() override;
// MainDialogDelegate implementation.
void AcceptedCleanup(bool confirmed) override;
void OnClose() override;
// Closes the main dialog.
void Quit();
// Uploads logs to SafeBrowsing. |tag| must be unique (UploadLogs cannot be
// called with the same |tag| multiple times). If the raw logs are being
// dumped to disk, |tag| will be appended to the filename. If |quit_when_done|
// is true, then the current UI message loop will be told to QuitWhenIdle
// after all the log uploads have completed.
void UploadLogs(const base::string16& tag, bool quit_when_done);
// Handles the completion of a logs upload.
void LogsUploadComplete(const base::string16& tag, bool success);
// Logs |exit_code| and any other metrics that should be saved on an early
// exit, such as a watchdog timeout or sandbox error.
void WriteEarlyExitMetrics(ResultCode exit_code);
// Callback for the Watchdog timeout.
int WatchdogTimeoutCallback(TimedOutStage timeout_stage);
Scanner* scanner();
Cleaner* cleaner();
// The API to force a reboot.
RebooterAPI* rebooter_;
// The manager of components to be called before / after the scan / cleanup.
ComponentManager component_manager_;
// The objects that needed to be connected together by the controller.
std::unique_ptr<MainDialogAPI> main_dialog_;
EngineFacadeInterface* engine_facade_ = nullptr;
// The PUPs that were found by the Scanner.
std::vector<chrome_cleaner::UwSId> found_pups_;
// The result to be returned to our caller.
ResultCode result_code_;
// Tracks the progress of multiple logs uploads.
std::map<base::string16, bool> logs_upload_complete_;
// Whether we should quit after all the logs uploads are done or not.
bool quit_when_logs_upload_complete_ = false;
// Pointer to the RegistryLogger used by this class to log upload results.
RegistryLogger* registry_logger_;
// Start times of the scanning and cleaning phases.
base::Time scan_start_time_;
base::Time clean_start_time_;
// Indicate whether or not we have finished the scanning and cleaning phases.
bool finished_scanning_ = false;
bool finished_cleaning_ = false;
// Indicate whether removable UwS were found.
bool removable_uws_found_ = false;
// Watchdog for terminating if scanning or cleaning takes too long.
std::unique_ptr<base::Watchdog> watchdog_;
// Quit closure to indicate the current scan & cleanup or validation is done.
base::OnceClosure quit_closure_;
// The connection error handlers gets a weak pointer for the main controller,
// so that it doesn't try to access the object once it's destroyed.
base::WeakPtrFactory<MainController> weak_factory_{this};
} // namespace chrome_cleaner