blob: 4b819fc9de01c3ce9abd961745cf87ee7f2d4df4 [file] [log] [blame]
// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cryptohome/cleanup/low_disk_space_handler.h"
#include <type_traits>
#include <base/check.h>
#include <base/logging.h>
#include "cryptohome/cleanup/disk_cleanup.h"
#include "cryptohome/cleanup/user_oldest_activity_timestamp_manager.h"
#include "cryptohome/platform.h"
#include "cryptohome/storage/homedirs.h"
namespace cryptohome {
namespace {
bool IsDiskSpaceLow(DiskCleanup::FreeSpaceState state) {
switch (state) {
case DiskCleanup::FreeSpaceState::kNeedNormalCleanup:
case DiskCleanup::FreeSpaceState::kNeedAggressiveCleanup:
case DiskCleanup::FreeSpaceState::kNeedCriticalCleanup:
return true;
case DiskCleanup::FreeSpaceState::kError:
case DiskCleanup::FreeSpaceState::kAboveTarget:
case DiskCleanup::FreeSpaceState::kAboveThreshold:
return false;
}
}
} // namespace
LowDiskSpaceHandler::LowDiskSpaceHandler(
HomeDirs* homedirs,
Platform* platform,
UserOldestActivityTimestampManager* timestamp_manager)
: platform_(platform),
default_cleanup_(new DiskCleanup(platform, homedirs, timestamp_manager)),
cleanup_(default_cleanup_.get()),
low_disk_notification_period_(kLowDiskNotificationPeriod),
update_user_activity_timestamp_period_(kUpdateUserActivityPeriod) {}
LowDiskSpaceHandler::~LowDiskSpaceHandler() {
DCHECK(stopped_);
}
void LowDiskSpaceHandler::Stop() {
stopped_ = true;
}
bool LowDiskSpaceHandler::Init(
base::RepeatingCallback<bool(const base::Location&,
base::OnceClosure,
const base::TimeDelta&)> post_delayed_task) {
post_delayed_task_ = post_delayed_task;
last_update_user_activity_timestamp_time_ = platform_->GetCurrentTime();
// We need to mark "stopped_" as false BEFORE calling any of the following
// methods, for the callbacks to work correctly; i.e. especially since the
// default "base::TimeDelta()" is zero and the "post_delayed_task" could
// call the callbacks from a different thread.
stopped_ = false;
if (!post_delayed_task_.Run(
FROM_HERE,
base::BindOnce(&LowDiskSpaceHandler::FreeDiskSpace,
base::Unretained(this)),
base::TimeDelta()))
return false;
if (!post_delayed_task_.Run(
FROM_HERE,
base::BindOnce(&LowDiskSpaceHandler::LowDiskSpaceCheck,
base::Unretained(this)),
base::TimeDelta()))
return false;
return true;
}
void LowDiskSpaceHandler::FreeDiskSpace() {
if (stopped_)
return;
if (!cleanup_->FreeDiskSpace()) {
LOG(ERROR) << "FreeDiskSpace encontered an error";
}
last_auto_cleanup_time_ = platform_->GetCurrentTime();
}
void LowDiskSpaceHandler::LowDiskSpaceCheck() {
if (stopped_)
return;
bool low_disk_space_signal_emitted = false;
auto free_disk_space = cleanup_->AmountOfFreeDiskSpace();
auto free_space_state = cleanup_->GetFreeDiskSpaceState(free_disk_space);
if (free_space_state == DiskCleanup::FreeSpaceState::kError) {
LOG(ERROR) << "Error getting free disk space";
} else {
VLOG(1) << "Available free disk space " << *free_disk_space
<< "; FreeSpaceState="
<< static_cast<std::underlying_type_t<DiskCleanup::FreeSpaceState>>(
free_space_state);
if (IsDiskSpaceLow(free_space_state)) {
LOG(INFO) << "Available disk space: |" << free_disk_space.value()
<< "| bytes. Emitting low disk space signal.";
low_disk_space_callback_.Run(free_disk_space.value());
low_disk_space_signal_emitted = true;
}
}
const base::Time current_time = platform_->GetCurrentTime();
const bool time_for_auto_cleanup =
current_time - last_auto_cleanup_time_ > kAutoCleanupPeriod;
// We shouldn't repeat cleanups on every minute if the disk space
// stays below the threshold. Trigger it only if there was no notification
// previously or if enterprise owned and free space can be reclaimed.
const bool early_cleanup_needed = low_disk_space_signal_emitted &&
(!low_disk_space_signal_was_emitted_ ||
cleanup_->IsFreeableDiskSpaceAvailable());
if (time_for_auto_cleanup || early_cleanup_needed)
FreeDiskSpace();
const bool time_for_update_user_activity_timestamp =
current_time - last_update_user_activity_timestamp_time_ >
update_user_activity_timestamp_period_;
if (time_for_update_user_activity_timestamp) {
last_update_user_activity_timestamp_time_ = current_time;
update_user_activity_timestamp_callback_.Run();
}
low_disk_space_signal_was_emitted_ = low_disk_space_signal_emitted;
post_delayed_task_.Run(FROM_HERE,
base::BindOnce(&LowDiskSpaceHandler::LowDiskSpaceCheck,
base::Unretained(this)),
low_disk_notification_period_);
}
} // namespace cryptohome