| // |
| // Copyright (C) 2012 The Android Open Source Project |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| |
| #include "shill/power_manager.h" |
| |
| #include <map> |
| #include <string> |
| |
| #include <base/bind.h> |
| #include <base/stl_util.h> |
| #if defined(__ANDROID__) |
| #include <dbus/service_constants.h> |
| #else |
| #include <chromeos/dbus/service_constants.h> |
| #endif // __ANDROID__ |
| |
| #include "shill/control_interface.h" |
| #include "shill/event_dispatcher.h" |
| #include "shill/logging.h" |
| #include "shill/power_manager_proxy_interface.h" |
| |
| using base::Bind; |
| using base::TimeDelta; |
| using base::Unretained; |
| using std::map; |
| using std::string; |
| |
| namespace shill { |
| |
| // static |
| const int PowerManager::kInvalidSuspendId = -1; |
| const char PowerManager::kSuspendDelayDescription[] = "shill"; |
| const char PowerManager::kDarkSuspendDelayDescription[] = "shill"; |
| const int PowerManager::kSuspendTimeoutMilliseconds = 15 * 1000; |
| |
| PowerManager::PowerManager(EventDispatcher* dispatcher, |
| ControlInterface* control_interface) |
| : dispatcher_(dispatcher), |
| control_interface_(control_interface), |
| suspend_delay_registered_(false), |
| suspend_delay_id_(0), |
| dark_suspend_delay_registered_(false), |
| dark_suspend_delay_id_(0), |
| suspending_(false), |
| in_dark_resume_(false), |
| current_suspend_id_(0), |
| current_dark_suspend_id_(0) {} |
| |
| PowerManager::~PowerManager() {} |
| |
| void PowerManager::Start( |
| TimeDelta suspend_delay, |
| const SuspendImminentCallback& suspend_imminent_callback, |
| const SuspendDoneCallback& suspend_done_callback, |
| const DarkSuspendImminentCallback& dark_suspend_imminent_callback) { |
| power_manager_proxy_.reset( |
| control_interface_->CreatePowerManagerProxy( |
| this, |
| Bind(&PowerManager::OnPowerManagerAppeared, Unretained(this)), |
| Bind(&PowerManager::OnPowerManagerVanished, Unretained(this)))); |
| suspend_delay_ = suspend_delay; |
| suspend_imminent_callback_ = suspend_imminent_callback; |
| suspend_done_callback_ = suspend_done_callback; |
| dark_suspend_imminent_callback_ = dark_suspend_imminent_callback; |
| } |
| |
| void PowerManager::Stop() { |
| LOG(INFO) << __func__; |
| // We may attempt to unregister with a stale |suspend_delay_id_| if powerd |
| // reappeared behind our back. It is safe to do so. |
| if (suspend_delay_registered_) |
| power_manager_proxy_->UnregisterSuspendDelay(suspend_delay_id_); |
| if (dark_suspend_delay_registered_) |
| power_manager_proxy_->UnregisterDarkSuspendDelay(dark_suspend_delay_id_); |
| |
| suspend_delay_registered_ = false; |
| dark_suspend_delay_registered_ = false; |
| power_manager_proxy_.reset(); |
| } |
| |
| bool PowerManager::ReportSuspendReadiness() { |
| if (!suspending_) { |
| LOG(INFO) << __func__ << ": Suspend attempt (" |
| << current_suspend_id_ << ") not active. Ignoring signal."; |
| return false; |
| } |
| return power_manager_proxy_->ReportSuspendReadiness(suspend_delay_id_, |
| current_suspend_id_); |
| } |
| |
| bool PowerManager::ReportDarkSuspendReadiness() { |
| return power_manager_proxy_->ReportDarkSuspendReadiness( |
| dark_suspend_delay_id_, |
| current_dark_suspend_id_); |
| } |
| |
| bool PowerManager::RecordDarkResumeWakeReason(const string& wake_reason) { |
| return power_manager_proxy_->RecordDarkResumeWakeReason(wake_reason); |
| } |
| |
| void PowerManager::OnSuspendImminent(int suspend_id) { |
| LOG(INFO) << __func__ << "(" << suspend_id << ")"; |
| current_suspend_id_ = suspend_id; |
| |
| // If we're already suspending, don't call the |suspend_imminent_callback_| |
| // again. |
| if (!suspending_) { |
| // Change the power state to suspending as soon as this signal is received |
| // so that the manager can suppress auto-connect, for example. |
| // Also, we must set this before running the callback below, because the |
| // callback may synchronously report suspend readiness. |
| suspending_ = true; |
| suspend_imminent_callback_.Run(); |
| } |
| } |
| |
| void PowerManager::OnSuspendDone(int suspend_id) { |
| // NB: |suspend_id| could be -1. See OnPowerManagerVanished. |
| LOG(INFO) << __func__ << "(" << suspend_id << ")"; |
| if (!suspending_) { |
| LOG(WARNING) << "Recieved unexpected SuspendDone (" |
| << suspend_id << "). Ignoring."; |
| return; |
| } |
| |
| suspending_ = false; |
| in_dark_resume_ = false; |
| suspend_done_callback_.Run(); |
| } |
| |
| void PowerManager::OnDarkSuspendImminent(int suspend_id) { |
| LOG(INFO) << __func__ << "(" << suspend_id << ")"; |
| if (!dark_suspend_delay_registered_) { |
| LOG(WARNING) << "Ignoring DarkSuspendImminent signal from powerd. shill " |
| << "does not have a dark suspend delay registered. This " |
| << "means that shill is not guaranteed any time before a " |
| << "resuspend."; |
| return; |
| } |
| in_dark_resume_ = true; |
| current_dark_suspend_id_ = suspend_id; |
| dark_suspend_imminent_callback_.Run(); |
| } |
| |
| void PowerManager::OnPowerManagerAppeared() { |
| LOG(INFO) << __func__; |
| CHECK(!suspend_delay_registered_); |
| if (power_manager_proxy_->RegisterSuspendDelay(suspend_delay_, |
| kSuspendDelayDescription, |
| &suspend_delay_id_)) |
| suspend_delay_registered_ = true; |
| |
| if (power_manager_proxy_->RegisterDarkSuspendDelay( |
| suspend_delay_, |
| kDarkSuspendDelayDescription, |
| &dark_suspend_delay_id_)) |
| dark_suspend_delay_registered_ = true; |
| } |
| |
| void PowerManager::OnPowerManagerVanished() { |
| LOG(INFO) << __func__; |
| // If powerd vanished during a suspend, we need to wake ourselves up. |
| if (suspending_) |
| OnSuspendDone(kInvalidSuspendId); |
| suspend_delay_registered_ = false; |
| dark_suspend_delay_registered_ = false; |
| } |
| |
| } // namespace shill |