File: task_manager.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (199 lines) | stat: -rw-r--r-- 6,650 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
// Copyright 2020 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/credential_provider/extension/task_manager.h"

#include <windows.h>

#include <memory>

#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/single_thread_task_runner.h"
#include "base/time/time.h"
#include "chrome/credential_provider/extension/extension_utils.h"
#include "chrome/credential_provider/extension/user_context_enumerator.h"
#include "chrome/credential_provider/gaiacp/logging.h"
#include "chrome/credential_provider/gaiacp/reg_utils.h"

namespace credential_provider {
namespace extension {

namespace {

// Backoff policy for errors returned by performing task operation.
const net::BackoffEntry::Policy kRetryLaterPolicy = {
    // Number of initial errors to ignore before starting to back off.
    0,

    // Initial delay in ms: 1 minute.
    1000 * 60,

    // Factor by which the waiting time is multiplied.
    2,

    // Fuzzing percentage; this spreads delays randomly between 80% and 100%
    // of the calculated time.
    0.20,

    // Maximum delay in ms: 3 hours. However this field of back off policy is
    // overridden by individual task's execution period when actually backing
    // off.
    1000 * 60 * 60 * 3,

    // When to discard an entry: never.
    -1,

    // |always_use_initial_delay|; false means that the initial delay is
    // applied after the first error, and starts backing off from there.
    true,
};

// Returns the elapsed time delta since the last time the periodic sync were
// successfully performed for the given task registry.
base::TimeDelta GetTimeDeltaSinceLastPeriodicSync(
    const std::wstring& task_reg_name) {
  wchar_t last_sync_millis[512];
  ULONG last_sync_size = std::size(last_sync_millis);
  HRESULT hr = GetGlobalFlag(task_reg_name, last_sync_millis, &last_sync_size);

  if (FAILED(hr)) {
    // The periodic sync has never happened before.
    return base::TimeDelta::Max();
  }

  int64_t last_sync_millis_int64;
  base::StringToInt64(last_sync_millis, &last_sync_millis_int64);
  const auto last_sync = base::Time::FromDeltaSinceWindowsEpoch(
      base::Milliseconds(last_sync_millis_int64));
  return base::Time::Now() - last_sync;
}

}  // namespace

// static
TaskManager** TaskManager::GetInstanceStorage() {
  static TaskManager* instance = new TaskManager();

  return &instance;
}

// static
TaskManager* TaskManager::Get() {
  return *GetInstanceStorage();
}

TaskManager::TaskManager() = default;

TaskManager::~TaskManager() = default;

void TaskManager::ExecuteTask(
    scoped_refptr<base::SingleThreadTaskRunner> task_runner,
    const std::string& task_name) {
  LOGFN(VERBOSE);

  // Get an instance of the task and execute it.
  std::unique_ptr<Task> task((task_list_[task_name]).Run());
  if (task == nullptr) {
    LOGFN(ERROR) << task_name << " task is null";
    return;
  }

  HRESULT hr =
      UserContextEnumerator::Get()->PerformTask(task_name, *task.get());

  // Calculate next time the task should be executed.
  base::TimeDelta next_run;

  if (FAILED(hr)) {
    LOGFN(ERROR) << task_name << " failed hr=" << putHR(hr);

    // Check whether a backoff entry exists for the task. If so, consider the
    // backoff period when calculating next run.
    if (task_execution_backoffs_.find(task_name) ==
        task_execution_backoffs_.end()) {
      // First set the template backoff policy for the task.
      task_execution_policies_[task_name] =
          std::make_unique<net::BackoffEntry::Policy>();
      *task_execution_policies_[task_name] = kRetryLaterPolicy;

      // Max backoff time shouldn't be more than task execution period.
      task_execution_policies_[task_name]->maximum_backoff_ms =
          task->GetConfig().execution_period.InMilliseconds();

      const net::BackoffEntry::Policy* policy =
          task_execution_policies_.find(task_name)->second.get();

      // Create backoff entry as this is the first failure after a success.
      task_execution_backoffs_[task_name] =
          std::make_unique<net::BackoffEntry>(policy);
    }

    task_execution_backoffs_[task_name]->InformOfRequest(false);

    // Get backoff time for the next request.
    next_run = task_execution_backoffs_[task_name]->GetTimeUntilRelease();

  } else {
    // Clear the back off entry as the task succeeded. An alternative was to
    // keep it and report success.
    task_execution_backoffs_.erase(task_name);
    next_run = task->GetConfig().execution_period;

    LOGFN(INFO) << task_name << " was executed successfully!";
    const base::Time sync_time = base::Time::Now();
    const std::wstring sync_time_millis = base::NumberToWString(
        sync_time.ToDeltaSinceWindowsEpoch().InMilliseconds());

    SetGlobalFlag(GetLastSyncRegNameForTask(base::UTF8ToWide(task_name)),
                  sync_time_millis);
  }

  // Schedule next task execution.
  task_runner->PostDelayedTask(
      FROM_HERE,
      base::BindOnce(&TaskManager::ExecuteTask, base::Unretained(this),
                     task_runner, task_name),
      next_run);
}

void TaskManager::RunTasks(
    scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
  // Enumerate registered tasks and kick-off the periodic execution.
  for (auto it = task_list_.begin(); it != task_list_.end(); ++it) {
    // Get an instance of registered Task.
    std::unique_ptr<Task> task((it->second).Run());
    if (task == nullptr) {
      LOGFN(ERROR) << it->first << " task is null";
      continue;
    }

    // Calculate the next run so that periodic polling  happens within
    // proper time intervals. When the tasks are scheduled, we don't want to
    // immediately start executing to allow some warm-up.
    base::TimeDelta next_run = base::Seconds(10);
    const base::TimeDelta time_since_last_run =
        GetTimeDeltaSinceLastPeriodicSync(
            GetLastSyncRegNameForTask(base::UTF8ToWide(it->first)));

    if (time_since_last_run < task->GetConfig().execution_period)
      next_run = task->GetConfig().execution_period - time_since_last_run;

    task_runner->PostDelayedTask(
        FROM_HERE,
        base::BindOnce(&TaskManager::ExecuteTask, base::Unretained(this),
                       task_runner, it->first),
        next_run);
  }
}

void TaskManager::RegisterTask(const std::string& task_name,
                               TaskCreator task_creator) {
  LOGFN(VERBOSE);

  task_list_.emplace(task_name, std::move(task_creator));
}

}  // namespace extension
}  // namespace credential_provider