blob: cae3e4111a20b58140d7c8cf08c694d339c7543b [file] [log] [blame]
// Copyright (c) 2012 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 "shill/power_manager.h"
#include <map>
#include <string>
#include <base/stl_util.h>
#include "shill/event_dispatcher.h"
#include "shill/logging.h"
#include "shill/power_manager_proxy_interface.h"
#include "shill/proxy_factory.h"
using std::map;
using std::string;
namespace shill {
const int PowerManager::kSuspendTimeoutMilliseconds = 15 * 1000;
PowerManager::PowerManager(EventDispatcher *dispatcher,
ProxyFactory *proxy_factory)
: dispatcher_(dispatcher),
power_manager_proxy_(proxy_factory->CreatePowerManagerProxy(this)),
suspending_(false) {}
PowerManager::~PowerManager() {
}
bool PowerManager::AddSuspendDelay(
const std::string &key,
const std::string &description,
base::TimeDelta timeout,
const SuspendImminentCallback &imminent_callback,
const SuspendDoneCallback &done_callback) {
CHECK(!imminent_callback.is_null());
CHECK(!done_callback.is_null());
if (ContainsKey(suspend_delays_, key)) {
LOG(ERROR) << "Ignoring request to insert duplicate key " << key;
return false;
}
int delay_id = 0;
if (!power_manager_proxy_->RegisterSuspendDelay(
timeout, description, &delay_id)) {
return false;
}
SuspendDelay delay;
delay.imminent_callback = imminent_callback;
delay.done_callback = done_callback;
delay.delay_id = delay_id;
suspend_delays_[key] = delay;
return true;
}
bool PowerManager::RemoveSuspendDelay(const std::string &key) {
SuspendDelayMap::const_iterator it = suspend_delays_.find(key);
if (it == suspend_delays_.end()) {
LOG(ERROR) << "Ignoring unregistered key " << key;
return false;
}
if (!power_manager_proxy_->UnregisterSuspendDelay(it->second.delay_id)) {
return false;
}
suspend_delays_.erase(it);
return true;
}
bool PowerManager::ReportSuspendReadiness(const std::string &key,
int suspend_id) {
SuspendDelayMap::const_iterator it = suspend_delays_.find(key);
if (it == suspend_delays_.end()) {
LOG(ERROR) << "Ignoring unregistered key " << key;
return false;
}
return power_manager_proxy_->ReportSuspendReadiness(
it->second.delay_id, suspend_id);
}
void PowerManager::OnSuspendImminent(int suspend_id) {
LOG(INFO) << __func__ << "(" << suspend_id << ")";
// Change the power state to suspending as soon as this signal is received so
// that the manager can suppress auto-connect, for example. Schedules a
// suspend timeout in case the suspend attempt failed or got interrupted, and
// there's no proper notification from the power manager.
suspending_ = true;
suspend_timeout_.Reset(
base::Bind(&PowerManager::OnSuspendTimeout, base::Unretained(this),
suspend_id));
dispatcher_->PostDelayedTask(suspend_timeout_.callback(),
kSuspendTimeoutMilliseconds);
for (SuspendDelayMap::const_iterator it = suspend_delays_.begin();
it != suspend_delays_.end(); ++it) {
SuspendImminentCallback callback = it->second.imminent_callback;
CHECK(!callback.is_null());
callback.Run(suspend_id);
}
}
void PowerManager::OnSuspendDone(int suspend_id) {
LOG(INFO) << __func__ << "(" << suspend_id << ")";
suspend_timeout_.Cancel();
suspending_ = false;
for (SuspendDelayMap::const_iterator it = suspend_delays_.begin();
it != suspend_delays_.end(); ++it) {
SuspendDoneCallback callback = it->second.done_callback;
CHECK(!callback.is_null());
callback.Run(suspend_id);
}
}
void PowerManager::OnSuspendTimeout(int suspend_id) {
LOG(ERROR) << "Suspend timed out -- assuming power-on state.";
OnSuspendDone(suspend_id);
}
} // namespace shill