|  | // 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 "content/browser/btm/persistent_repeating_timer.h" | 
|  |  | 
|  | #include "base/functional/bind.h" | 
|  | #include "base/functional/callback.h" | 
|  | #include "base/memory/raw_ptr.h" | 
|  | #include "base/time/time.h" | 
|  |  | 
|  | namespace content { | 
|  |  | 
|  | PersistentRepeatingTimer::Storage::~Storage() = default; | 
|  |  | 
|  | PersistentRepeatingTimer::PersistentRepeatingTimer( | 
|  | std::unique_ptr<Storage> time_storage, | 
|  | base::TimeDelta delay, | 
|  | base::RepeatingClosure task) | 
|  | : storage_(std::move(time_storage)), delay_(delay), user_task_(task) {} | 
|  |  | 
|  | PersistentRepeatingTimer::~PersistentRepeatingTimer() = default; | 
|  |  | 
|  | void PersistentRepeatingTimer::Start() { | 
|  | if (timer_.IsRunning()) { | 
|  | return;  // Already started. | 
|  | } | 
|  |  | 
|  | storage_->GetLastFired( | 
|  | base::BindOnce(&PersistentRepeatingTimer::StartWithLastFired, | 
|  | weak_factory_.GetWeakPtr())); | 
|  | } | 
|  |  | 
|  | void PersistentRepeatingTimer::StartWithLastFired( | 
|  | std::optional<base::Time> last_fired) { | 
|  | if (timer_.IsRunning()) { | 
|  | return;  // Already started. | 
|  | } | 
|  |  | 
|  | const base::TimeDelta time_since_update = | 
|  | base::Time::Now() - last_fired.value_or(base::Time()); | 
|  | if (time_since_update >= delay_) { | 
|  | OnTimerFired(); | 
|  | } else { | 
|  | timer_.Start(FROM_HERE, delay_ - time_since_update, | 
|  | base::BindRepeating(&PersistentRepeatingTimer::OnTimerFired, | 
|  | base::Unretained(this))); | 
|  | } | 
|  | DCHECK(timer_.IsRunning()); | 
|  | } | 
|  |  | 
|  | void PersistentRepeatingTimer::OnTimerFired() { | 
|  | DCHECK(!timer_.IsRunning()); | 
|  | const base::Time now = base::Time::Now(); | 
|  | storage_->SetLastFired(now); | 
|  | user_task_.Run(); | 
|  | StartWithLastFired(now); | 
|  | } | 
|  |  | 
|  | }  // namespace content |