| // Copyright 2018 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/settings/settings.h" |
| |
| #include "base/command_line.h" |
| #include "base/guid.h" |
| #include "base/logging.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_split.h" |
| #include "chrome/chrome_cleaner/constants/chrome_cleaner_switches.h" |
| #include "chrome/chrome_cleaner/engines/engine_resources.h" |
| #include "chrome/chrome_cleaner/settings/settings_definitions.h" |
| #include "mojo/public/cpp/platform/named_platform_channel.h" |
| |
| namespace chrome_cleaner { |
| |
| namespace { |
| |
| // Returns the value associated with flag --session-id when it's present or |
| // empty string when it's not found. |
| base::string16 GetSessionId(const base::CommandLine& command_line) { |
| return command_line.GetSwitchValueNative(kSessionIdSwitch); |
| } |
| |
| // Returns the engine being used. |
| Engine::Name GetEngine(const base::CommandLine& command_line) { |
| if (command_line.HasSwitch(kEngineSwitch)) { |
| std::string value = command_line.GetSwitchValueASCII(kEngineSwitch); |
| int numeric_value = Engine::URZA; |
| if (base::StringToInt(value, &numeric_value) && |
| Engine_Name_IsValid(numeric_value) && |
| numeric_value != Engine::UNKNOWN) { |
| return static_cast<Engine::Name>(numeric_value); |
| } |
| |
| LOG(WARNING) << "Invalid engine (" << value << "), using default engine"; |
| } |
| |
| return Engine::URZA; |
| } |
| |
| ExecutionMode GetExecutionMode(const base::CommandLine& command_line) { |
| int val = -1; |
| // WARNING: this switch is used by internal test systems, be careful when |
| // making changes. |
| if (base::StringToInt(command_line.GetSwitchValueASCII(kExecutionModeSwitch), |
| &val) && |
| val > static_cast<int>(ExecutionMode::kNone) && |
| val < static_cast<int>(ExecutionMode::kNumValues)) { |
| return static_cast<ExecutionMode>(val); |
| } |
| return ExecutionMode::kNone; |
| } |
| |
| bool GetLogsCollectionEnabled(const base::CommandLine& command_line, |
| TargetBinary target_binary, |
| ExecutionMode execution_mode) { |
| switch (target_binary) { |
| case TargetBinary::kReporter: |
| // For the reporter, if logging collection is enabled, then we will save |
| // UwS matching to a proto that can be saved to disk or sent to Google if |
| // logs upload is allowed. WARNING: this switch is used by internal test |
| // systems, be careful when making changes. |
| return command_line.HasSwitch(kExtendedSafeBrowsingEnabledSwitch); |
| case TargetBinary::kCleaner: |
| // Logs collection is only enabled if the user did not opt out, which |
| // causes the scanner process to launch the elevated cleaner with the |
| // |kWithCleanupModeLogsSwitch| flag. |
| return (execution_mode == ExecutionMode::kCleanup && |
| command_line.HasSwitch(kWithCleanupModeLogsSwitch)) || |
| (execution_mode == ExecutionMode::kScanning && |
| command_line.HasSwitch(kWithScanningModeLogsSwitch)); |
| default: |
| return false; |
| } |
| } |
| |
| bool GetLogsUploadAllowed(const base::CommandLine& command_line, |
| TargetBinary target_binary, |
| ExecutionMode execution_mode) { |
| // WARNING: this switch is used by internal test systems, be careful when |
| // making changes. |
| if (command_line.HasSwitch(kNoReportUploadSwitch)) |
| return false; |
| |
| return GetLogsCollectionEnabled(command_line, target_binary, execution_mode); |
| } |
| |
| bool GetAllowCrashReportUpload(const base::CommandLine& command_line) { |
| if (command_line.HasSwitch(kNoCrashUploadSwitch)) |
| return false; |
| |
| // WARNING: this switch is used by internal test systems, be careful when |
| // making changes. |
| return command_line.HasSwitch(kEnableCrashReportingSwitch); |
| } |
| |
| // If switch --cleanup-id is present and not empty, returns the value |
| // associated with it. The most common case is when the current cleaner |
| // process is running post-reboot and was scheduled by a pre-reboot process |
| // with that cleanup id. Otherwise, generate a new random string that should be |
| // immutable for this process and propagated to other processes corresponding |
| // to the same cleanup. |
| std::string GetCleanerRunId(const base::CommandLine& command_line) { |
| std::string cleanup_id = command_line.GetSwitchValueASCII(kCleanupIdSwitch); |
| if (cleanup_id.empty()) { |
| cleanup_id = base::GenerateGUID(); |
| DCHECK(!cleanup_id.empty()); |
| } |
| return cleanup_id; |
| } |
| |
| // Populates |result| with locations that should be scanned. Returns true if no |
| // invalid location values were provided on the command line. |
| bool GetLocationsToScan(const base::CommandLine& command_line, |
| std::vector<UwS::TraceLocation>* result) { |
| std::vector<UwS::TraceLocation> valid_locations = GetValidTraceLocations(); |
| if (!command_line.HasSwitch(kScanLocationsSwitch)) { |
| result->swap(valid_locations); |
| return true; |
| } |
| |
| std::string locations_list_str = |
| command_line.GetSwitchValueASCII(kScanLocationsSwitch); |
| std::vector<base::StringPiece> location_strs = |
| base::SplitStringPiece(locations_list_str, ",", base::TRIM_WHITESPACE, |
| base::SPLIT_WANT_NONEMPTY); |
| const std::set<UwS::TraceLocation> valid_locations_set( |
| valid_locations.begin(), valid_locations.end()); |
| bool all_values_valid = true; |
| result->clear(); |
| for (const auto& location_str : location_strs) { |
| int location_num; |
| if (base::StringToInt(location_str, &location_num)) { |
| UwS::TraceLocation location = |
| static_cast<UwS::TraceLocation>(location_num); |
| if (valid_locations_set.find(location) != valid_locations_set.end()) |
| result->push_back(location); |
| else |
| all_values_valid = false; |
| } else { |
| all_values_valid = false; |
| } |
| } |
| |
| if (result->empty()) { |
| result->swap(valid_locations); |
| all_values_valid = false; |
| } |
| |
| return all_values_valid; |
| } |
| |
| } // namespace |
| |
| bool GetTimeoutOverride(const base::CommandLine& command_line, |
| const char* switch_name, |
| base::TimeDelta* timeout) { |
| if (!command_line.HasSwitch(switch_name)) |
| return false; |
| |
| int timeout_minutes = 0; |
| if (!base::StringToInt(command_line.GetSwitchValueNative(switch_name), |
| &timeout_minutes)) { |
| return false; |
| } |
| |
| // Negative timeout is invalid. |
| if (timeout_minutes < 0) |
| return false; |
| |
| DCHECK(timeout); |
| *timeout = base::TimeDelta::FromMinutes(timeout_minutes); |
| return true; |
| } |
| |
| std::vector<UwS::TraceLocation> GetValidTraceLocations() { |
| std::vector<UwS::TraceLocation> result; |
| for (int location = UwS::TraceLocation_MIN; |
| location <= UwS::TraceLocation_MAX; ++location) { |
| if (UwS::TraceLocation_IsValid(location)) { |
| result.push_back(static_cast<UwS::TraceLocation>(location)); |
| } |
| } |
| return result; |
| } |
| |
| // static |
| Settings* Settings::instance_for_testing_ = nullptr; |
| |
| // static |
| Settings* Settings::GetInstance() { |
| if (instance_for_testing_) |
| return instance_for_testing_; |
| return base::Singleton<Settings>::get(); |
| } |
| |
| // static |
| void Settings::SetInstanceForTesting(Settings* instance_for_testing) { |
| instance_for_testing_ = instance_for_testing; |
| } |
| |
| bool Settings::allow_crash_report_upload() const { |
| return allow_crash_report_upload_; |
| } |
| |
| base::string16 Settings::session_id() const { |
| return session_id_; |
| } |
| |
| std::string Settings::cleanup_id() const { |
| return cleanup_id_; |
| } |
| |
| Engine::Name Settings::engine() const { |
| return engine_; |
| } |
| |
| std::string Settings::engine_version() const { |
| return GetEngineVersion(engine()); |
| } |
| |
| bool Settings::logs_upload_allowed() const { |
| return logs_upload_allowed_; |
| } |
| |
| bool Settings::logs_collection_enabled() const { |
| return logs_collection_enabled_; |
| } |
| |
| bool Settings::logs_allowed_in_cleanup_mode() const { |
| DCHECK_EQ(ExecutionMode::kScanning, execution_mode_); |
| return logs_allowed_in_cleanup_mode_; |
| } |
| |
| void Settings::set_logs_allowed_in_cleanup_mode(bool new_value) { |
| // TODO Make the global settings object immutable. |
| DCHECK_EQ(ExecutionMode::kScanning, execution_mode_); |
| logs_allowed_in_cleanup_mode_ = new_value; |
| } |
| |
| bool Settings::metrics_enabled() const { |
| return metrics_enabled_; |
| } |
| |
| bool Settings::sber_enabled() const { |
| return sber_enabled_; |
| } |
| |
| const std::string& Settings::chrome_mojo_pipe_token() const { |
| return chrome_mojo_pipe_token_; |
| } |
| |
| bool Settings::has_parent_pipe_handle() const { |
| return has_parent_pipe_handle_; |
| } |
| |
| ExecutionMode Settings::execution_mode() const { |
| return execution_mode_; |
| } |
| |
| bool Settings::remove_report_only_uws() const { |
| return remove_report_only_uws_; |
| } |
| |
| bool Settings::cleaning_timeout_overridden() const { |
| return cleaning_timeout_overridden_; |
| } |
| |
| base::TimeDelta Settings::cleaning_timeout() const { |
| return cleaning_timeout_; |
| } |
| |
| bool Settings::scanning_timeout_overridden() const { |
| return scanning_timeout_overridden_; |
| } |
| |
| base::TimeDelta Settings::scanning_timeout() const { |
| return scanning_timeout_; |
| } |
| |
| bool Settings::user_response_timeout_overridden() const { |
| return user_response_timeout_overridden_; |
| } |
| |
| base::TimeDelta Settings::user_response_timeout() const { |
| return user_response_timeout_; |
| } |
| |
| const std::vector<UwS::TraceLocation>& Settings::locations_to_scan() const { |
| return locations_to_scan_; |
| } |
| |
| bool Settings::scan_switches_correct() const { |
| return scan_switches_correct_; |
| } |
| |
| Settings::Settings() { |
| Initialize(*base::CommandLine::ForCurrentProcess(), GetTargetBinary()); |
| } |
| |
| Settings::~Settings() = default; |
| |
| void Settings::Initialize(const base::CommandLine& command_line, |
| TargetBinary target_binary) { |
| allow_crash_report_upload_ = GetAllowCrashReportUpload(command_line); |
| session_id_ = GetSessionId(command_line); |
| cleanup_id_ = GetCleanerRunId(command_line); |
| engine_ = GetEngine(command_line); |
| |
| metrics_enabled_ = command_line.HasSwitch(kUmaUserSwitch); |
| // WARNING: this switch is used by internal test systems, be careful when |
| // making changes. |
| sber_enabled_ = command_line.HasSwitch(kExtendedSafeBrowsingEnabledSwitch); |
| execution_mode_ = GetExecutionMode(command_line); |
| logs_upload_allowed_ = |
| GetLogsUploadAllowed(command_line, target_binary, execution_mode_); |
| logs_collection_enabled_ = |
| GetLogsCollectionEnabled(command_line, target_binary, execution_mode_); |
| chrome_mojo_pipe_token_ = command_line.GetSwitchValueASCII( |
| chrome_cleaner::kChromeMojoPipeTokenSwitch); |
| has_parent_pipe_handle_ = |
| command_line.HasSwitch(mojo::NamedPlatformChannel::kNamedHandleSwitch); |
| #if !defined(CHROME_CLEANER_OFFICIAL_BUILD) |
| remove_report_only_uws_ = command_line.HasSwitch(kRemoveScanOnlyUwS); |
| #endif |
| |
| cleaning_timeout_overridden_ = GetTimeoutOverride( |
| command_line, kCleaningTimeoutMinutesSwitch, &cleaning_timeout_); |
| scanning_timeout_overridden_ = GetTimeoutOverride( |
| command_line, kScanningTimeoutMinutesSwitch, &scanning_timeout_); |
| user_response_timeout_overridden_ = GetTimeoutOverride( |
| command_line, kUserResponseTimeoutMinutesSwitch, &user_response_timeout_); |
| scan_switches_correct_ = |
| GetLocationsToScan(command_line, &locations_to_scan_); |
| } |
| |
| } // namespace chrome_cleaner |