blob: ba6cad3915e4783974aa11e9291a8ddb5880decf [file] [log] [blame]
// Copyright 2019 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/policy/shutdown_from_suspend.h"
#include <base/bind.h>
#include <base/strings/stringprintf.h>
#include "power_manager/common/power_constants.h"
#include "power_manager/common/prefs.h"
#include "power_manager/common/util.h"
#include "power_manager/powerd/system/power_supply.h"
namespace power_manager {
namespace policy {
ShutdownFromSuspend::ShutdownFromSuspend()
: ShutdownFromSuspend(timers::SimpleAlarmTimer::Create()) {}
ShutdownFromSuspend::ShutdownFromSuspend(
std::unique_ptr<timers::SimpleAlarmTimer> alarm_timer)
: alarm_timer_(std::move(alarm_timer)) {}
ShutdownFromSuspend::~ShutdownFromSuspend() = default;
void ShutdownFromSuspend::Init(PrefsInterface* prefs,
system::PowerSupplyInterface* power_supply) {
DCHECK(prefs);
DCHECK(power_supply);
power_supply_ = power_supply;
// Shutdown after X can only work if dark resume is enabled.
bool dark_resume_disable =
prefs->GetBool(kDisableDarkResumePref, &dark_resume_disable) &&
dark_resume_disable;
int64_t shutdown_after_sec = 0;
enabled_ =
!dark_resume_disable &&
prefs->GetInt64(kShutdownFromSuspendSecPref, &shutdown_after_sec) &&
shutdown_after_sec > 0;
if (enabled_) {
shutdown_delay_ = base::TimeDelta::FromSeconds(shutdown_after_sec);
prefs->GetDouble(kLowBatteryShutdownPercentPref,
&low_battery_shutdown_percent_);
LOG(INFO) << "Shutdown from suspend is configured to "
<< util::TimeDeltaToString(shutdown_delay_)
<< ". low_battery_shutdown_percent is "
<< low_battery_shutdown_percent_;
} else {
LOG(INFO) << "Shutdown from suspend is disabled";
}
}
bool ShutdownFromSuspend::ShouldShutdown() {
if (timer_fired_) {
LOG(INFO) << "Timer expired. Device should shut down.";
return true;
}
if (power_supply_->RefreshImmediately()) {
const double percent = power_supply_->GetPowerStatus().battery_percentage;
if (0 <= percent && percent <= low_battery_shutdown_percent_) {
LOG(INFO) << "Battery percentage " << base::StringPrintf("%0.2f", percent)
<< "% <= low_battery_shutdown_percent ("
<< base::StringPrintf("%0.2f", low_battery_shutdown_percent_)
<< "%). Device should shut down.";
return true;
}
} else {
LOG(ERROR) << "Failed to refresh battery status";
}
return false;
}
ShutdownFromSuspend::Action ShutdownFromSuspend::PrepareForSuspendAttempt() {
if (!enabled_)
return ShutdownFromSuspend::Action::SUSPEND;
// TODO(crbug.com/964510): If the timer is gonna expire in next few minutes,
// shutdown.
if (in_dark_resume_ && ShutdownFromSuspend::ShouldShutdown()) {
if (!power_supply_->GetPowerStatus().line_power_on) {
LOG(INFO) << "Shutting down.";
return ShutdownFromSuspend::Action::SHUT_DOWN;
}
LOG(INFO) << "Not shutting down from resume as line power is connected.";
}
if (!alarm_timer_) {
LOG(WARNING) << "System doesn't support CLOCK_REALTIME_ALARM";
return ShutdownFromSuspend::Action::SUSPEND;
}
if (!alarm_timer_->IsRunning()) {
alarm_timer_->Start(
FROM_HERE, shutdown_delay_,
base::Bind(&ShutdownFromSuspend::OnTimerWake, base::Unretained(this)));
}
return ShutdownFromSuspend::Action::SUSPEND;
}
void ShutdownFromSuspend::HandleDarkResume() {
in_dark_resume_ = true;
}
void ShutdownFromSuspend::HandleFullResume() {
in_dark_resume_ = false;
if (alarm_timer_)
alarm_timer_->Stop();
else
LOG(WARNING) << "System doesn't support CLOCK_REALTIME_ALARM.";
timer_fired_ = false;
}
void ShutdownFromSuspend::OnTimerWake() {
timer_fired_ = true;
}
} // namespace policy
} // namespace power_manager