1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/policy/core/common/policy_scheduler.h"
6 
7 #include "base/threading/thread_task_runner_handle.h"
8 
9 namespace policy {
10 
PolicyScheduler(Task task,SchedulerCallback callback,base::TimeDelta interval)11 PolicyScheduler::PolicyScheduler(Task task,
12                                  SchedulerCallback callback,
13                                  base::TimeDelta interval)
14     : task_(task), callback_(callback), interval_(interval) {
15   ScheduleTaskNow();
16 }
17 
~PolicyScheduler()18 PolicyScheduler::~PolicyScheduler() {
19   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
20 }
21 
ScheduleTaskNow()22 void PolicyScheduler::ScheduleTaskNow() {
23   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
24   ScheduleDelayedTask(base::TimeDelta());
25 }
26 
ScheduleDelayedTask(base::TimeDelta delay)27 void PolicyScheduler::ScheduleDelayedTask(base::TimeDelta delay) {
28   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
29 
30   if (job_) {
31     job_->Cancel();
32   }
33   job_ = std::make_unique<base::CancelableClosure>(base::Bind(
34       &PolicyScheduler::RunScheduledTask, weak_ptr_factory_.GetWeakPtr()));
35   base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(FROM_HERE,
36                                                        job_->callback(), delay);
37 }
38 
ScheduleNextTask()39 void PolicyScheduler::ScheduleNextTask() {
40   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
41 
42   base::TimeDelta interval = overlap_ ? base::TimeDelta() : interval_;
43   const base::TimeTicks now(base::TimeTicks::Now());
44   // Time uses saturated arithmetics thus no under/overflow possible.
45   const base::TimeDelta delay = last_task_ + interval - now;
46   // Clamping delay to non-negative values just to be on the safe side.
47   ScheduleDelayedTask(std::max(base::TimeDelta(), delay));
48 }
49 
RunScheduledTask()50 void PolicyScheduler::RunScheduledTask() {
51   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
52 
53   if (task_in_progress_) {
54     overlap_ = true;
55     return;
56   }
57 
58   overlap_ = false;
59   task_in_progress_ = true;
60   task_.Run(base::BindOnce(&PolicyScheduler::OnTaskDone,
61                            weak_ptr_factory_.GetWeakPtr()));
62 }
63 
OnTaskDone(bool success)64 void PolicyScheduler::OnTaskDone(bool success) {
65   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
66 
67   task_in_progress_ = false;
68   last_task_ = base::TimeTicks::Now();
69   callback_.Run(success);
70   ScheduleNextTask();
71 }
72 
73 }  // namespace policy
74