blob: d6b5910594b0da08c465ff3aee848f3b997b89ad [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/autofill/next_idle_time_ticks.h"
#include <memory>
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/metrics/histogram_functions.h"
#include "base/task/current_thread.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "components/autofill/core/common/autofill_features.h"
#include "content/public/browser/browser_thread.h"
namespace autofill {
struct NextIdleTimeTicks::Data {
// Sets `value` to the current time ticks.
void SetValueToCurrentTimeTicks();
// Starts a timer for a measurement attempt of the next idle time ticks.
void StartTimerForMeasurementAttempt(base::TimeDelta delay);
// Registers a callback with the UI thread in the browser process to measure
// the time ticks the next time the UI thread becomes idle. Offset is passed
// on to `SetValueToCurrentTimeTicksWithOffset`.
void AttemptMeasurement();
base::TimeTicks value;
// The delay after which the first measurement attempt is made.
base::TimeDelta measurement_start_delay;
// The callback subscription for when the UI thread becomes idle the next
// time.
base::CallbackListSubscription on_idle_callback_subscription;
// The `TimeTicks` when the measurement attempt was started - used for metrics
// reporting only.
base::TimeTicks start_time_measurement_attempt;
// A timer that controls the next next measurement attempt.
base::OneShotTimer measurement_delay_timer;
};
void NextIdleTimeTicks::Data::SetValueToCurrentTimeTicks() {
value = base::TimeTicks::Now();
if (base::FeatureList::IsEnabled(
features::kAutofillPopupImprovedTimingChecks) ||
base::FeatureList::IsEnabled(
features::kAutofillPopupImprovedTimingChecksV2)) {
CHECK(!start_time_measurement_attempt.is_null());
base::UmaHistogramTimes(
"Autofill.Popup.NextIdleTimeTicksDelay",
base::TimeTicks::Now() - start_time_measurement_attempt);
}
}
void NextIdleTimeTicks::Data::StartTimerForMeasurementAttempt(
base::TimeDelta delay) {
measurement_start_delay = delay;
measurement_delay_timer.Start(FROM_HERE, delay, this,
&NextIdleTimeTicks::Data::AttemptMeasurement);
}
void NextIdleTimeTicks::Data::AttemptMeasurement() {
start_time_measurement_attempt = base::TimeTicks::Now();
on_idle_callback_subscription =
base::CurrentUIThread::Get()->RegisterOnNextIdleCallback(
{},
base::BindOnce(&NextIdleTimeTicks::Data::SetValueToCurrentTimeTicks,
base::Unretained(this)));
}
NextIdleTimeTicks::NextIdleTimeTicks() = default;
NextIdleTimeTicks::NextIdleTimeTicks(NextIdleTimeTicks&&) = default;
NextIdleTimeTicks& NextIdleTimeTicks::operator=(NextIdleTimeTicks&&) = default;
NextIdleTimeTicks::~NextIdleTimeTicks() = default;
// static
NextIdleTimeTicks NextIdleTimeTicks::CaptureNextIdleTimeTicks() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
NextIdleTimeTicks result;
result.data_ = std::make_unique<Data>();
if (base::FeatureList::IsEnabled(
autofill::features::kAutofillPopupImprovedTimingChecks)) {
result.data_->AttemptMeasurement();
} else {
result.data_->SetValueToCurrentTimeTicks();
}
return result;
}
// static
NextIdleTimeTicks NextIdleTimeTicks::CaptureNextIdleTimeTicksWithDelay(
base::TimeDelta delay) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
NextIdleTimeTicks result;
result.data_ = std::make_unique<Data>();
result.data_->StartTimerForMeasurementAttempt(delay);
return result;
}
base::TimeTicks NextIdleTimeTicks::value() const {
return data_ && !data_->value.is_null()
? data_->measurement_start_delay + data_->value
: base::TimeTicks();
}
} // namespace autofill