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