1// Copyright 2014 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 "chrome/browser/chromeos/policy/server_backed_state_keys_broker.h"
6
7#include <algorithm>
8
9#include "base/bind.h"
10#include "base/location.h"
11#include "base/task_runner.h"
12#include "chromeos/dbus/session_manager_client.h"
13
14namespace policy {
15
16namespace {
17
18// Refresh interval for state keys. There's a quantized time component in
19// state key generation, so they rotate over time. The quantum size is pretty
20// coarse though (currently 2^23 seconds), so simply polling for a new state
21// keys once a day is good enough.
22const int kPollIntervalSeconds = 60 * 60 * 24;
23
24}  // namespace
25
26ServerBackedStateKeysBroker::ServerBackedStateKeysBroker(
27    chromeos::SessionManagerClient* session_manager_client,
28    scoped_refptr<base::TaskRunner> delayed_task_runner)
29    : session_manager_client_(session_manager_client),
30      delayed_task_runner_(delayed_task_runner),
31      first_boot_(false),
32      requested_(false),
33      initial_retrieval_completed_(false),
34      weak_factory_(this) {
35}
36
37ServerBackedStateKeysBroker::~ServerBackedStateKeysBroker() {
38}
39
40ServerBackedStateKeysBroker::Subscription
41ServerBackedStateKeysBroker::RegisterUpdateCallback(
42    const base::Closure& callback) {
43  if (!available())
44    FetchStateKeys();
45  return update_callbacks_.Add(callback);
46}
47
48void ServerBackedStateKeysBroker::RequestStateKeys(
49    const StateKeysCallback& callback) {
50  if (pending()) {
51    request_callbacks_.push_back(callback);
52    FetchStateKeys();
53    return;
54  }
55
56  if (!callback.is_null())
57    callback.Run(state_keys_, first_boot_);
58  return;
59}
60
61void ServerBackedStateKeysBroker::FetchStateKeys() {
62  if (!requested_) {
63    requested_ = true;
64    session_manager_client_->GetServerBackedStateKeys(
65        base::Bind(&ServerBackedStateKeysBroker::StoreStateKeys,
66                   weak_factory_.GetWeakPtr()));
67  }
68}
69
70void ServerBackedStateKeysBroker::StoreStateKeys(
71    const std::vector<std::string>& state_keys, bool first_boot) {
72  bool send_notification = !initial_retrieval_completed_;
73
74  requested_ = false;
75  initial_retrieval_completed_ = true;
76  if (state_keys.empty()) {
77    LOG(WARNING) << "Failed to obtain server-backed state keys.";
78  } else if (state_keys.end() !=
79             std::find(state_keys.begin(), state_keys.end(), std::string())) {
80    LOG(WARNING) << "Bad state keys.";
81  } else {
82    send_notification |= state_keys_ != state_keys;
83    state_keys_ = state_keys;
84    first_boot_ = first_boot;
85  }
86
87  if (send_notification)
88    update_callbacks_.Notify();
89
90  std::vector<StateKeysCallback> callbacks;
91  request_callbacks_.swap(callbacks);
92  for (std::vector<StateKeysCallback>::const_iterator callback(
93           callbacks.begin());
94       callback != callbacks.end();
95       ++callback) {
96    if (!callback->is_null())
97      callback->Run(state_keys_, first_boot_);
98  }
99
100  delayed_task_runner_->PostDelayedTask(
101      FROM_HERE,
102      base::Bind(&ServerBackedStateKeysBroker::FetchStateKeys,
103                 weak_factory_.GetWeakPtr()),
104      base::TimeDelta::FromSeconds(kPollIntervalSeconds));
105}
106
107}  // namespace policy
108