chromium/chrome/browser/ash/policy/server_backed_state/server_backed_state_keys_broker.cc

// Copyright 2014 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/browser/ash/policy/server_backed_state/server_backed_state_keys_broker.h"

#include "base/containers/contains.h"
#include "base/functional/bind.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/task/single_thread_task_runner.h"
#include "base/time/time.h"
#include "chromeos/ash/components/dbus/session_manager/session_manager_client.h"

namespace policy {

namespace {

// Refresh interval for state keys. There's a quantized time component in
// state key generation, so they rotate over time. The quantum size is pretty
// coarse though (currently 2^23 seconds), so simply polling for a new state
// keys once a day is good enough.
constexpr base::TimeDelta kPollInterval = base::Days(1);

// In case state key fetching failed, we need to try again, sooner than
// |kPollInterval|.
constexpr base::TimeDelta kRetryInterval = base::Minutes(1);

}  // namespace

ServerBackedStateKeysBroker::ServerBackedStateKeysBroker(
    ash::SessionManagerClient* session_manager_client)
    : session_manager_client_(session_manager_client), requested_(false) {}

ServerBackedStateKeysBroker::~ServerBackedStateKeysBroker() {}

base::CallbackListSubscription
ServerBackedStateKeysBroker::RegisterUpdateCallback(
    const UpdateCallback& callback) {
  if (!available()) {
    LOG(WARNING) << "Fetching state keys.";
    FetchStateKeys();
  }
  return update_callbacks_.Add(callback);
}

void ServerBackedStateKeysBroker::RequestStateKeys(StateKeysCallback callback) {
  if (!available()) {
    request_callbacks_.AddUnsafe(std::move(callback));
    FetchStateKeys();
    return;
  }

  if (!callback.is_null())
    std::move(callback).Run(state_keys_);
}

// static
base::TimeDelta ServerBackedStateKeysBroker::GetPollIntervalForTesting() {
  return kPollInterval;
}

base::TimeDelta ServerBackedStateKeysBroker::GetRetryIntervalForTesting() {
  return kRetryInterval;
}

void ServerBackedStateKeysBroker::FetchStateKeys() {
  if (!requested_) {
    requested_ = true;
    session_manager_client_->GetServerBackedStateKeys(
        base::BindOnce(&ServerBackedStateKeysBroker::StoreStateKeys,
                       weak_factory_.GetWeakPtr()));
  }
}

void ServerBackedStateKeysBroker::StoreStateKeys(
    const base::expected<std::vector<std::string>, ErrorType>& state_keys) {
  bool send_notification = !available();

  requested_ = false;
  auto wait_interval = kPollInterval;
  if (!state_keys.has_value()) {
    LOG(WARNING) << "Failed to obtain server-backed state keys. Error: "
                 << static_cast<int>(state_keys.error());
    wait_interval = kRetryInterval;
  } else {
    send_notification |= state_keys_ != state_keys.value();
  }
  state_keys_ = state_keys.value_or(std::vector<std::string>());
  error_type_ = state_keys.error_or(ErrorType::kNoError);

  if (send_notification)
    update_callbacks_.Notify();

  request_callbacks_.Notify(state_keys_);

  base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
      FROM_HERE,
      base::BindOnce(&ServerBackedStateKeysBroker::FetchStateKeys,
                     weak_factory_.GetWeakPtr()),
      wait_interval);
}

ServerBackedStateKeysBroker::ErrorType ServerBackedStateKeysBroker::error_type()
    const {
  return error_type_;
}

}  // namespace policy