blob: da091d1b6dd5554905e90fa424f8ab20e976d0f5 [file] [log] [blame] [edit]
// Copyright 2024 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "modemfwd/suspend_checker.h"
#include <utility>
#include <base/files/file_util.h>
#include "modemfwd/logging.h"
namespace {
constexpr char kSuspendAnnouncedFile[] =
"/run/power_manager/power/suspend_announced";
} // namespace
namespace modemfwd {
SuspendChecker::SuspendChecker() = default;
// static
std::unique_ptr<SuspendChecker> SuspendChecker::Create() {
std::unique_ptr<SuspendChecker> checker =
std::unique_ptr<SuspendChecker>(new SuspendChecker);
if (!checker->SetUpWatch()) {
LOG(ERROR) << "Could not set up suspend announce file watch";
return nullptr;
}
return checker;
}
SuspendChecker::~SuspendChecker() = default;
bool SuspendChecker::IsSuspendAnnounced() const {
return base::PathExists(base::FilePath(kSuspendAnnouncedFile));
}
void SuspendChecker::RunWhenNotSuspending(base::OnceClosure cb) {
callbacks_.push_back(std::move(cb));
// Run callbacks inline if suspend has not been announced.
RunCallbacksIfSuspendNotAnnounced();
}
bool SuspendChecker::SetUpWatch() {
suspend_announced_watcher_.reset(new base::FilePathWatcher);
return suspend_announced_watcher_->Watch(
base::FilePath(kSuspendAnnouncedFile),
base::FilePathWatcher::Type::kNonRecursive,
base::BindRepeating(&SuspendChecker::OnWatcherEvent,
weak_ptr_factory_.GetWeakPtr()));
}
void SuspendChecker::OnWatcherEvent(const base::FilePath& /* path */,
bool error) {
if (error) {
LOG(WARNING) << "Suspend announcement watch returned an error. "
<< "Attempting to reset watch";
if (!SetUpWatch()) {
LOG(ERROR) << "Could not reset suspend announcement watch";
}
}
// We might be notified for file creation, etc. so we have to check for
// the existence of the file anyway. The documentation for FilePathWatcher
// says we can get more information by using ChangeInfo, but this is stated
// to only be a "strong hint", so there are no guarantees we can always use
// that to immediately know the file has been deleted.
RunCallbacksIfSuspendNotAnnounced();
}
void SuspendChecker::RunCallbacksIfSuspendNotAnnounced() {
if (IsSuspendAnnounced()) {
ELOG(INFO) << "Suspend has been announced, deferring tasks";
return;
}
EVLOG(1) << "Not currently suspending, running tasks";
for (auto& callback : callbacks_) {
std::move(callback).Run();
}
callbacks_.clear();
}
} // namespace modemfwd