blob: 617ee0eae3f4ff780386185cb4038c5df818bd48 [file] [log] [blame]
// Copyright 2018 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 "power_manager/powerd/system/wakeup_device.h"
#include <string>
#include <utility>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <base/strings/string_number_conversions.h>
#include "power_manager/common/power_constants.h"
#include "power_manager/powerd/system/udev.h"
namespace power_manager {
namespace system {
const char WakeupDevice::kPowerWakeupCount[] = "power/wakeup_count";
WakeupDevice::WakeupDevice(const base::FilePath& path, UdevInterface* udev)
: path_(path), udev_(udev) {}
WakeupDevice::~WakeupDevice() {}
void WakeupDevice::PrepareForSuspend() {
// This can happen when the device is no more a wake source (if power/wakeup
// is disabled).
was_pre_suspend_read_successful_ =
ReadWakeupCount(&wakeup_count_before_suspend_);
}
void WakeupDevice::HandleResume() {
caused_last_wake_ = false;
if (!was_pre_suspend_read_successful_) {
return;
}
uint64_t wakeup_count_after_resume = 0;
// This can happen when the device is no more a wake source (if power/wakeup
// is disabled).
if (!ReadWakeupCount(&wakeup_count_after_resume))
return;
if (wakeup_count_after_resume != wakeup_count_before_suspend_) {
LOG(INFO) << "Device " << path_.value() << " had wakeup count "
<< wakeup_count_before_suspend_ << " before suspend and "
<< wakeup_count_after_resume << " after resume";
caused_last_wake_ = true;
}
}
bool WakeupDevice::CausedLastWake() const {
return caused_last_wake_;
}
bool WakeupDevice::ReadWakeupCount(uint64_t* wakeup_count_out) {
DCHECK(wakeup_count_out);
std::string wakeup_count_str;
if (!udev_->GetSysattr(path_.value(), kPowerWakeupCount, &wakeup_count_str)) {
VLOG(1) << "Failed to read " << kPowerWakeupCount
<< " sysattr available for " << path_.value();
return false;
}
// Some drivers leave the wakeup_count empty initially.
if (wakeup_count_str.empty()) {
*wakeup_count_out = 0;
return true;
}
if (base::StringToUint64(wakeup_count_str, wakeup_count_out)) {
return true;
}
LOG(ERROR) << "Could not parse wakeup_count sysattr for " << path_.value();
return false;
}
WakeupDeviceFactory::WakeupDeviceFactory(UdevInterface* udev) : udev_(udev) {}
WakeupDeviceFactory::~WakeupDeviceFactory() {}
std::unique_ptr<WakeupDeviceInterface> WakeupDeviceFactory::CreateWakeupDevice(
const base::FilePath& path) {
const base::FilePath wakeup_path = path.Append(kPowerWakeup);
if (!base::PathExists(wakeup_path)) {
// This can happen when the device is not wake capable.
return nullptr;
}
return std::make_unique<WakeupDevice>(path, udev_);
}
} // namespace system
} // namespace power_manager