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

Unified Diff: chrome/browser/safe_browsing/srt_fetcher_win.cc

Issue 2226133005: Add support for the ExperimentalSwReporterEngine field trial. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Set flags explicitly in srt_fetcher browsertest Created 4 years, 3 months 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/safe_browsing/srt_fetcher_win.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/safe_browsing/srt_fetcher_win.cc
diff --git a/chrome/browser/safe_browsing/srt_fetcher_win.cc b/chrome/browser/safe_browsing/srt_fetcher_win.cc
index c8733099af9c188aaf64d3e1d6d02524c369acfd..01fb75c9e6905cfc81c28124da94a55e3c9fb9ff 100644
--- a/chrome/browser/safe_browsing/srt_fetcher_win.cc
+++ b/chrome/browser/safe_browsing/srt_fetcher_win.cc
@@ -15,6 +15,7 @@
#include "base/bind_helpers.h"
#include "base/callback_helpers.h"
#include "base/command_line.h"
+#include "base/debug/leak_annotations.h"
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/metrics/field_trial.h"
@@ -129,7 +130,9 @@ const char kMemoryUsedMetricName[] = "SoftwareReporter.MemoryUsed";
// Reports metrics about the software reporter via UMA (and sometimes Rappor).
class UMAHistogramReporter {
public:
- explicit UMAHistogramReporter(const std::string& suffix = std::string())
+ UMAHistogramReporter() : UMAHistogramReporter(std::string()) {}
+
+ explicit UMAHistogramReporter(const std::string& suffix)
: suffix_(suffix),
registry_key_(suffix.empty() ? kSoftwareRemovalToolRegistryKey
: base::StringPrintf(
@@ -225,6 +228,8 @@ class UMAHistogramReporter {
RecordLongTimesHistogram("SoftwareReporter.RunningTimeAccordingToChrome",
reporter_running_time);
+ // TODO(b/641081): This should only have KEY_QUERY_VALUE and KEY_SET_VALUE,
+ // and use Open to avoid creating the key if it doesn't already exist.
base::win::RegKey reporter_key(HKEY_CURRENT_USER, registry_key_.c_str(),
KEY_ALL_ACCESS);
if (!reporter_key.Valid()) {
@@ -282,6 +287,8 @@ class UMAHistogramReporter {
void ReportScanTimes() const {
base::string16 scan_times_key_path = base::StringPrintf(
L"%ls\\%ls", registry_key_.c_str(), kScanTimesSubKey);
+ // TODO(b/641081): This should only have KEY_QUERY_VALUE and KEY_SET_VALUE,
+ // and use Open to avoid creating the key if it doesn't already exist.
base::win::RegKey scan_times_key(
HKEY_CURRENT_USER, scan_times_key_path.c_str(), KEY_ALL_ACCESS);
if (!scan_times_key.Valid())
@@ -608,26 +615,32 @@ void MaybeFetchSRT(Browser* browser, const base::Version& reporter_version) {
new SRTFetcher(profile);
}
-// This class tries to run the reporter and reacts to its exit code. It
-// schedules subsequent runs as needed, or retries as soon as a browser is
-// available when none is on first try.
+// This class tries to run a queue of reporters and react to their exit codes.
+// It schedules subsequent runs of the queue as needed, or retries as soon as a
+// browser is available when none is on first try.
class ReporterRunner : public chrome::BrowserListObserver {
public:
- // Starts the sequence of attempts to run the reporter.
- static void Run(const SwReporterInvocation& invocation,
- const base::Version& version,
- scoped_refptr<base::TaskRunner> main_thread_task_runner,
- scoped_refptr<base::TaskRunner> blocking_task_runner) {
- if (!instance_)
+ // Registers |invocations| to run next time |TryToRun| is scheduled. (And if
+ // it's not already scheduled, call it now.)
+ static void ScheduleInvocations(
+ const SwReporterQueue& invocations,
+ const base::Version& version,
+ scoped_refptr<base::TaskRunner> main_thread_task_runner,
+ scoped_refptr<base::TaskRunner> blocking_task_runner) {
+ if (!instance_) {
instance_ = new ReporterRunner;
+ ANNOTATE_LEAKING_OBJECT_PTR(instance_);
+ }
DCHECK_CURRENTLY_ON(BrowserThread::UI);
- // There's nothing to do if the path and version of the reporter has not
- // changed, we just keep running the tasks that are running now.
- if (instance_->invocation_ == invocation && instance_->version_.IsValid() &&
- instance_->version_ == version)
+
+ // There's nothing to do if the invocation parameters and version of the
+ // reporter have not changed, we just keep running the tasks that are
+ // running now.
+ if (instance_->pending_invocations_ == invocations &&
+ instance_->version_.IsValid() && instance_->version_ == version)
return;
- instance_->invocation_ = invocation;
+ instance_->pending_invocations_ = invocations;
instance_->version_ = version;
instance_->main_thread_task_runner_ = std::move(main_thread_task_runner);
instance_->blocking_task_runner_ = std::move(blocking_task_runner);
@@ -652,9 +665,48 @@ class ReporterRunner : public chrome::BrowserListObserver {
BrowserList::RemoveObserver(this);
}
- // This method is called on the UI thread when the reporter run has completed.
- // This is run as a task posted from an interruptible worker thread so should
- // be resilient to unexpected shutdown.
+ // Launches the command line at the head of the queue.
+ void ScheduleNextInvocation() {
+ DCHECK(!current_invocations_.empty());
+ auto next_invocation = current_invocations_.front();
+ current_invocations_.pop();
+
+ if (g_testing_delegate_)
+ g_testing_delegate_->NotifyLaunchReady();
+
+ // Add switches for users who opted into extended Safe Browsing reporting.
+ // The invocation object is changed locally right before the actual process
+ // is launched because user status can change between this and the next run
+ // for this ReporterRunner object. For example, the ReporterDone() callback
+ // schedules the next run for a few days later, and the user might have
+ // changed settings in the meantime.
+ PrefService* local_state = g_browser_process->local_state();
+ if (next_invocation.flags & SwReporterInvocation::FLAG_SEND_REPORTER_LOGS &&
+ local_state && ShouldSendReporterLogs(*local_state)) {
+ AddSwitchesForExtendedReporterUser(&next_invocation);
+ // Set the local state value before the first attempt to run the
+ // reporter, because we only want to upload logs once in the window
+ // defined by |kDaysBetweenReporterLogsSent|. If we set with other local
+ // state values after the reporter runs, we could send logs again too
+ // quickly (for example, if Chrome stops before the reporter finishes).
+ local_state->SetInt64(prefs::kSwReporterLastTimeSentReport,
+ base::Time::Now().ToInternalValue());
+ }
+
+ // It's OK to simply |PostTaskAndReplyWithResult| so that
+ // |LaunchAndWaitForExit| doesn't need to access |main_thread_task_runner_|
+ // since the callback is not delayed and the test task runner won't need to
+ // force it.
+ base::PostTaskAndReplyWithResult(
+ blocking_task_runner_.get(), FROM_HERE,
+ base::Bind(&LaunchAndWaitForExit, next_invocation),
+ base::Bind(&ReporterRunner::ReporterDone, base::Unretained(this),
+ base::Time::Now(), version_, next_invocation));
+ }
+
+ // This method is called on the UI thread when an invocation of the reporter
+ // has completed. This is run as a task posted from an interruptible worker
+ // thread so should be resilient to unexpected shutdown.
void ReporterDone(const base::Time& reporter_start_time,
const base::Version& version,
const SwReporterInvocation& finished_invocation,
@@ -666,25 +718,41 @@ class ReporterRunner : public chrome::BrowserListObserver {
base::TimeDelta reporter_running_time =
base::Time::Now() - reporter_start_time;
- // Don't continue when the reporter process failed to launch, but still try
- // again after the regular delay. It's not worth retrying earlier, risking
- // running too often if it always fails, since not many users fail here.
- main_thread_task_runner_->PostDelayedTask(
- FROM_HERE,
- base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)),
- base::TimeDelta::FromDays(days_between_reporter_runs_));
+
+ // Don't continue the current queue of reporters if one failed to launch.
+ if (exit_code == kReporterFailureExitCode)
+ current_invocations_ = SwReporterQueue();
+
+ // As soon as we're not running this queue, schedule the next overall queue
+ // run after the regular delay. (If there was a failure it's not worth
+ // retrying earlier, risking running too often if it always fails, since
+ // not many users fail here.)
+ if (current_invocations_.empty()) {
+ main_thread_task_runner_->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)),
+ base::TimeDelta::FromDays(days_between_reporter_runs_));
+ } else {
+ ScheduleNextInvocation();
+ }
+
+ // If the reporter failed to launch, do not process the results. (The exit
+ // code itself doesn't need to be logged in this case because
+ // SW_REPORTER_FAILED_TO_START is logged in |LaunchAndWaitForExit|.)
if (exit_code == kReporterFailureExitCode)
return;
UMAHistogramReporter uma(finished_invocation.suffix);
uma.ReportVersion(version);
uma.ReportExitCode(exit_code);
- uma.ReportFoundUwS(!finished_invocation.is_experimental /*use_rappor*/);
+ uma.ReportFoundUwS(finished_invocation.flags &
+ SwReporterInvocation::FLAG_LOG_TO_RAPPOR);
- // Only save results from the canonical version of the software.
PrefService* local_state = g_browser_process->local_state();
- if (local_state && !finished_invocation.is_experimental) {
- local_state->SetInteger(prefs::kSwReporterLastExitCode, exit_code);
+ if (local_state) {
+ if (finished_invocation.flags &
+ SwReporterInvocation::FLAG_LOG_EXIT_CODE_TO_PREFS)
+ local_state->SetInteger(prefs::kSwReporterLastExitCode, exit_code);
local_state->SetInt64(prefs::kSwReporterLastTimeTriggered,
base::Time::Now().ToInternalValue());
}
@@ -692,8 +760,8 @@ class ReporterRunner : public chrome::BrowserListObserver {
uma.ReportScanTimes();
uma.ReportMemoryUsage();
- // Only continue to launch the prompt for the canonical version.
- if (finished_invocation.is_experimental)
+ if (!(finished_invocation.flags &
+ SwReporterInvocation::FLAG_TRIGGER_PROMPT))
return;
if (!IsInSRTPromptFieldTrialGroups()) {
@@ -727,12 +795,17 @@ class ReporterRunner : public chrome::BrowserListObserver {
void TryToRun() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
PrefService* local_state = g_browser_process->local_state();
+
if (!version_.IsValid() || !local_state) {
+ // TODO(b/641081): This doesn't look right. Even on first run, |version_|
+ // should be valid (and this is already checked in RunSwReporters). We
+ // should abort if local_state is missing, but this has nothing to do
+ // with |first_run_|.
DCHECK(first_run_);
return;
}
- // Run the reporter if it hasn't been triggered in the last
+ // Run a queue of reporters if none have been triggered in the last
// |days_between_reporter_runs_| days, which depends if there is a pending
// prompt to be added to Chrome's menu.
if (local_state->GetBoolean(prefs::kSwReporterPendingPrompt)) {
@@ -741,51 +814,25 @@ class ReporterRunner : public chrome::BrowserListObserver {
} else {
days_between_reporter_runs_ = kDaysBetweenSuccessfulSwReporterRuns;
}
+ const base::Time now = base::Time::Now();
const base::Time last_time_triggered = base::Time::FromInternalValue(
local_state->GetInt64(prefs::kSwReporterLastTimeTriggered));
- base::TimeDelta next_trigger_delay(
+ const base::Time next_trigger(
last_time_triggered +
- base::TimeDelta::FromDays(days_between_reporter_runs_) -
- base::Time::Now());
- if (next_trigger_delay.ToInternalValue() <= 0 ||
- // Also make sure the kSwReporterLastTimeTriggered value is not set in
- // the future.
- last_time_triggered > base::Time::Now()) {
- if (g_testing_delegate_)
- g_testing_delegate_->NotifyLaunchReady();
-
- // Creating a new invocation to add switches for users who opted into
- // extended Safe Browsing reporting. The invocation object is changed
- // locally right before the actual process is launched because user status
- // can change between this and the next run for this ReporterRunner
- // object. For example, the ReporterDone() callback schedules the next run
- // for a few days later, and the user might have changed settings in the
- // meantime.
- SwReporterInvocation actual_invocation(invocation_);
- if (ShouldSendReporterLogs(*local_state)) {
- AddSwitchesForExtendedReporterUser(&actual_invocation);
- // Set the local state value before the first attempt to run the
- // reporter, because we only want to upload logs once in the window
- // defined by |kDaysBetweenReporterLogsSent|. If we set with other local
- // state values after the reporter runs, we could send logs again too
- // quickly (for example, if Chrome stops before the reporter finishes).
- local_state->SetInt64(prefs::kSwReporterLastTimeSentReport,
- base::Time::Now().ToInternalValue());
- }
- // It's OK to simply |PostTaskAndReplyWithResult| so that
- // |LaunchAndWaitForExit| doesn't need to access
- // |main_thread_task_runner_| since the callback is not delayed and the
- // test task runner won't need to force it.
- base::PostTaskAndReplyWithResult(
- blocking_task_runner_.get(), FROM_HERE,
- base::Bind(&LaunchAndWaitForExit, actual_invocation),
- base::Bind(&ReporterRunner::ReporterDone, base::Unretained(this),
- base::Time::Now(), version_, invocation_));
+ base::TimeDelta::FromDays(days_between_reporter_runs_));
+ if (!pending_invocations_.empty() &&
+ (next_trigger <= now ||
+ // Also make sure the kSwReporterLastTimeTriggered value is not set in
+ // the future.
+ last_time_triggered > now)) {
+ DCHECK(current_invocations_.empty());
+ current_invocations_ = pending_invocations_;
+ ScheduleNextInvocation();
} else {
main_thread_task_runner_->PostDelayedTask(
FROM_HERE,
base::Bind(&ReporterRunner::TryToRun, base::Unretained(this)),
- next_trigger_delay);
+ next_trigger - now);
}
}
@@ -821,15 +868,21 @@ class ReporterRunner : public chrome::BrowserListObserver {
}
bool first_run_ = true;
- SwReporterInvocation invocation_;
+
+ // The queue of invocations that are currently running.
+ SwReporterQueue current_invocations_;
+
+ // The invocations to run next time the SwReporter is run.
+ SwReporterQueue pending_invocations_;
+
base::Version version_;
scoped_refptr<base::TaskRunner> main_thread_task_runner_;
scoped_refptr<base::TaskRunner> blocking_task_runner_;
// This value is used to identify how long to wait before starting a new run
- // of the reporter. It's initialized with the default value and may be changed
- // to a different value when a prompt is pending and the reporter should be
- // run before adding the global error to the Chrome menu.
+ // of the reporter queue. It's initialized with the default value and may be
+ // changed to a different value when a prompt is pending and the reporter
+ // should be run before adding the global error to the Chrome menu.
int days_between_reporter_runs_ = kDaysBetweenSuccessfulSwReporterRuns;
// A single leaky instance.
@@ -845,11 +898,6 @@ ReporterRunner* ReporterRunner::instance_ = nullptr;
SwReporterInvocation::SwReporterInvocation()
: command_line(base::CommandLine::NO_PROGRAM) {}
-SwReporterInvocation::SwReporterInvocation(const SwReporterInvocation& other)
- : command_line(other.command_line),
- suffix(other.suffix),
- is_experimental(other.is_experimental) {}
-
SwReporterInvocation SwReporterInvocation::FromFilePath(
const base::FilePath& exe_path) {
SwReporterInvocation invocation;
@@ -866,15 +914,18 @@ SwReporterInvocation SwReporterInvocation::FromCommandLine(
bool SwReporterInvocation::operator==(const SwReporterInvocation& other) const {
return command_line.argv() == other.command_line.argv() &&
- suffix == other.suffix && is_experimental == other.is_experimental;
+ suffix == other.suffix && flags == other.flags;
}
-void RunSwReporter(const SwReporterInvocation& invocation,
- const base::Version& version,
- scoped_refptr<base::TaskRunner> main_thread_task_runner,
- scoped_refptr<base::TaskRunner> blocking_task_runner) {
- ReporterRunner::Run(invocation, version, std::move(main_thread_task_runner),
- std::move(blocking_task_runner));
+void RunSwReporters(const SwReporterQueue& invocations,
+ const base::Version& version,
+ scoped_refptr<base::TaskRunner> main_thread_task_runner,
+ scoped_refptr<base::TaskRunner> blocking_task_runner) {
+ DCHECK(!invocations.empty());
+ DCHECK(version.IsValid());
+ ReporterRunner::ScheduleInvocations(invocations, version,
+ std::move(main_thread_task_runner),
+ std::move(blocking_task_runner));
}
bool ReporterFoundUws() {
« no previous file with comments | « chrome/browser/safe_browsing/srt_fetcher_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698