chromium/chrome/browser/ash/printing/history/print_job_history_cleaner.cc

// Copyright 2019 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/printing/history/print_job_history_cleaner.h"

#include "base/functional/bind.h"
#include "base/metrics/histogram_functions.h"
#include "base/task/sequenced_task_runner.h"
#include "base/time/clock.h"
#include "base/time/default_clock.h"
#include "base/time/time.h"
#include "chrome/browser/ash/printing/history/print_job_info.pb.h"
#include "chrome/common/pref_names.h"
#include "components/prefs/pref_service.h"

namespace ash {

namespace {

// This "PrintJobHistoryExpirationPeriod" policy value stands for storing the
// print job history indefinitely.
constexpr int kPrintJobHistoryIndefinite = -1;

// Returns true if |pref_service| has been initialized.
bool IsPrefServiceInitialized(PrefService* pref_service) {
  return pref_service->GetAllPrefStoresInitializationStatus() !=
         PrefService::INITIALIZATION_STATUS_WAITING;
}

bool IsCompletionTimeExpired(
    base::Time completion_time,
    base::Time now,
    base::TimeDelta print_job_history_expiration_period) {
  return completion_time + print_job_history_expiration_period < now;
}

}  // namespace

PrintJobHistoryCleaner::PrintJobHistoryCleaner(
    PrintJobDatabase* print_job_database,
    PrefService* pref_service)
    : print_job_database_(print_job_database),
      pref_service_(pref_service),
      clock_(base::DefaultClock::GetInstance()) {}

PrintJobHistoryCleaner::~PrintJobHistoryCleaner() = default;

void PrintJobHistoryCleaner::CleanUp(base::OnceClosure callback) {
  if (IsPrefServiceInitialized(pref_service_)) {
    OnPrefServiceInitialized(std::move(callback), true);
    return;
  }
  // Register for a callback that will be invoked when |pref_service_| is
  // initialized.
  pref_service_->AddPrefInitObserver(
      base::BindOnce(&PrintJobHistoryCleaner::OnPrefServiceInitialized,
                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}

void PrintJobHistoryCleaner::SetClockForTesting(const base::Clock* clock) {
  clock_ = clock;
}

void PrintJobHistoryCleaner::OnPrefServiceInitialized(
    base::OnceClosure callback,
    bool success) {
  int expiration_period =
      pref_service_->GetInteger(prefs::kPrintJobHistoryExpirationPeriod);

  // We don't want to run cleanup procedure if there are no expired print jobs.
  if (!success || !print_job_database_->IsInitialized() ||
      expiration_period == kPrintJobHistoryIndefinite ||
      !IsCompletionTimeExpired(oldest_print_job_completion_time_, clock_->Now(),
                               base::Days(expiration_period))) {
    base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
        FROM_HERE, std::move(callback));
    return;
  }
  print_job_database_->GetPrintJobs(
      base::BindOnce(&PrintJobHistoryCleaner::OnPrintJobsRetrieved,
                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}

void PrintJobHistoryCleaner::OnPrintJobsRetrieved(
    base::OnceClosure callback,
    bool success,
    std::vector<printing::proto::PrintJobInfo> print_job_infos) {
  if (!success) {
    base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
        FROM_HERE, std::move(callback));
    return;
  }
  std::vector<std::string> print_job_ids_to_remove;
  base::TimeDelta print_job_history_expiration_period = base::Days(
      pref_service_->GetInteger(prefs::kPrintJobHistoryExpirationPeriod));

  base::Time now = clock_->Now();
  oldest_print_job_completion_time_ = now;
  for (const auto& print_job_info : print_job_infos) {
    base::Time completion_time = base::Time::FromMillisecondsSinceUnixEpoch(
        print_job_info.completion_time());
    if (IsCompletionTimeExpired(completion_time, now,
                                print_job_history_expiration_period)) {
      print_job_ids_to_remove.push_back(print_job_info.id());
    } else if (completion_time < oldest_print_job_completion_time_) {
      oldest_print_job_completion_time_ = completion_time;
    }
  }
  print_job_database_->DeletePrintJobs(
      print_job_ids_to_remove,
      base::BindOnce(&PrintJobHistoryCleaner::OnPrintJobsDeleted,
                     weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}

void PrintJobHistoryCleaner::OnPrintJobsDeleted(base::OnceClosure callback,
                                                bool success) {
  base::SequencedTaskRunner::GetCurrentDefault()->PostTask(FROM_HERE,
                                                           std::move(callback));
}

}  // namespace ash