Home | History | Annotate | Download | only in shill
      1 //
      2 // Copyright (C) 2012 The Android Open Source Project
      3 //
      4 // Licensed under the Apache License, Version 2.0 (the "License");
      5 // you may not use this file except in compliance with the License.
      6 // You may obtain a copy of the License at
      7 //
      8 //      http://www.apache.org/licenses/LICENSE-2.0
      9 //
     10 // Unless required by applicable law or agreed to in writing, software
     11 // distributed under the License is distributed on an "AS IS" BASIS,
     12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 // See the License for the specific language governing permissions and
     14 // limitations under the License.
     15 //
     16 
     17 #include "shill/power_manager.h"
     18 
     19 #include <map>
     20 #include <string>
     21 
     22 #include <base/bind.h>
     23 #include <base/stl_util.h>
     24 #if defined(__ANDROID__)
     25 #include <dbus/service_constants.h>
     26 #else
     27 #include <chromeos/dbus/service_constants.h>
     28 #endif  // __ANDROID__
     29 
     30 #include "shill/control_interface.h"
     31 #include "shill/event_dispatcher.h"
     32 #include "shill/logging.h"
     33 #include "shill/power_manager_proxy_interface.h"
     34 
     35 using base::Bind;
     36 using base::TimeDelta;
     37 using base::Unretained;
     38 using std::map;
     39 using std::string;
     40 
     41 namespace shill {
     42 
     43 // static
     44 const int PowerManager::kInvalidSuspendId = -1;
     45 const char PowerManager::kSuspendDelayDescription[] = "shill";
     46 const char PowerManager::kDarkSuspendDelayDescription[] = "shill";
     47 const int PowerManager::kSuspendTimeoutMilliseconds = 15 * 1000;
     48 
     49 PowerManager::PowerManager(EventDispatcher* dispatcher,
     50                            ControlInterface* control_interface)
     51     : dispatcher_(dispatcher),
     52       control_interface_(control_interface),
     53       suspend_delay_registered_(false),
     54       suspend_delay_id_(0),
     55       dark_suspend_delay_registered_(false),
     56       dark_suspend_delay_id_(0),
     57       suspending_(false),
     58       in_dark_resume_(false),
     59       current_suspend_id_(0),
     60       current_dark_suspend_id_(0) {}
     61 
     62 PowerManager::~PowerManager() {}
     63 
     64 void PowerManager::Start(
     65     TimeDelta suspend_delay,
     66     const SuspendImminentCallback& suspend_imminent_callback,
     67     const SuspendDoneCallback& suspend_done_callback,
     68     const DarkSuspendImminentCallback& dark_suspend_imminent_callback) {
     69   power_manager_proxy_.reset(
     70       control_interface_->CreatePowerManagerProxy(
     71           this,
     72           Bind(&PowerManager::OnPowerManagerAppeared, Unretained(this)),
     73           Bind(&PowerManager::OnPowerManagerVanished, Unretained(this))));
     74   suspend_delay_ = suspend_delay;
     75   suspend_imminent_callback_ = suspend_imminent_callback;
     76   suspend_done_callback_ = suspend_done_callback;
     77   dark_suspend_imminent_callback_ = dark_suspend_imminent_callback;
     78 }
     79 
     80 void PowerManager::Stop() {
     81   LOG(INFO) << __func__;
     82   // We may attempt to unregister with a stale |suspend_delay_id_| if powerd
     83   // reappeared behind our back. It is safe to do so.
     84   if (suspend_delay_registered_)
     85     power_manager_proxy_->UnregisterSuspendDelay(suspend_delay_id_);
     86   if (dark_suspend_delay_registered_)
     87     power_manager_proxy_->UnregisterDarkSuspendDelay(dark_suspend_delay_id_);
     88 
     89   suspend_delay_registered_ = false;
     90   dark_suspend_delay_registered_ = false;
     91   power_manager_proxy_.reset();
     92 }
     93 
     94 bool PowerManager::ReportSuspendReadiness() {
     95   if (!suspending_) {
     96     LOG(INFO) << __func__ << ": Suspend attempt ("
     97               << current_suspend_id_ << ") not active. Ignoring signal.";
     98     return false;
     99   }
    100   return power_manager_proxy_->ReportSuspendReadiness(suspend_delay_id_,
    101                                                       current_suspend_id_);
    102 }
    103 
    104 bool PowerManager::ReportDarkSuspendReadiness() {
    105   return power_manager_proxy_->ReportDarkSuspendReadiness(
    106       dark_suspend_delay_id_,
    107       current_dark_suspend_id_);
    108 }
    109 
    110 bool PowerManager::RecordDarkResumeWakeReason(const string& wake_reason) {
    111   return power_manager_proxy_->RecordDarkResumeWakeReason(wake_reason);
    112 }
    113 
    114 void PowerManager::OnSuspendImminent(int suspend_id) {
    115   LOG(INFO) << __func__ << "(" << suspend_id << ")";
    116   current_suspend_id_ = suspend_id;
    117 
    118   // If we're already suspending, don't call the |suspend_imminent_callback_|
    119   // again.
    120   if (!suspending_) {
    121     // Change the power state to suspending as soon as this signal is received
    122     // so that the manager can suppress auto-connect, for example.
    123     // Also, we must set this before running the callback below, because the
    124     // callback may synchronously report suspend readiness.
    125     suspending_ = true;
    126     suspend_imminent_callback_.Run();
    127   }
    128 }
    129 
    130 void PowerManager::OnSuspendDone(int suspend_id) {
    131   // NB: |suspend_id| could be -1. See OnPowerManagerVanished.
    132   LOG(INFO) << __func__ << "(" << suspend_id << ")";
    133   if (!suspending_) {
    134     LOG(WARNING) << "Recieved unexpected SuspendDone ("
    135                  << suspend_id << "). Ignoring.";
    136     return;
    137   }
    138 
    139   suspending_ = false;
    140   in_dark_resume_ = false;
    141   suspend_done_callback_.Run();
    142 }
    143 
    144 void PowerManager::OnDarkSuspendImminent(int suspend_id) {
    145   LOG(INFO) << __func__ << "(" << suspend_id << ")";
    146   if (!dark_suspend_delay_registered_) {
    147     LOG(WARNING) << "Ignoring DarkSuspendImminent signal from powerd. shill "
    148                  << "does not have a dark suspend delay registered. This "
    149                  << "means that shill is not guaranteed any time before a "
    150                  << "resuspend.";
    151     return;
    152   }
    153   in_dark_resume_ = true;
    154   current_dark_suspend_id_ = suspend_id;
    155   dark_suspend_imminent_callback_.Run();
    156 }
    157 
    158 void PowerManager::OnPowerManagerAppeared() {
    159   LOG(INFO) << __func__;
    160   CHECK(!suspend_delay_registered_);
    161   if (power_manager_proxy_->RegisterSuspendDelay(suspend_delay_,
    162                                                  kSuspendDelayDescription,
    163                                                  &suspend_delay_id_))
    164     suspend_delay_registered_ = true;
    165 
    166   if (power_manager_proxy_->RegisterDarkSuspendDelay(
    167       suspend_delay_,
    168       kDarkSuspendDelayDescription,
    169       &dark_suspend_delay_id_))
    170     dark_suspend_delay_registered_ = true;
    171 }
    172 
    173 void PowerManager::OnPowerManagerVanished() {
    174   LOG(INFO) << __func__;
    175   // If powerd vanished during a suspend, we need to wake ourselves up.
    176   if (suspending_)
    177     OnSuspendDone(kInvalidSuspendId);
    178   suspend_delay_registered_ = false;
    179   dark_suspend_delay_registered_ = false;
    180 }
    181 
    182 }  // namespace shill
    183