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 
PowerManager(EventDispatcher * dispatcher,ControlInterface * control_interface)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 
~PowerManager()62 PowerManager::~PowerManager() {}
63 
Start(TimeDelta suspend_delay,const SuspendImminentCallback & suspend_imminent_callback,const SuspendDoneCallback & suspend_done_callback,const DarkSuspendImminentCallback & dark_suspend_imminent_callback)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 
Stop()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 
ReportSuspendReadiness()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 
ReportDarkSuspendReadiness()104 bool PowerManager::ReportDarkSuspendReadiness() {
105   return power_manager_proxy_->ReportDarkSuspendReadiness(
106       dark_suspend_delay_id_,
107       current_dark_suspend_id_);
108 }
109 
RecordDarkResumeWakeReason(const string & wake_reason)110 bool PowerManager::RecordDarkResumeWakeReason(const string& wake_reason) {
111   return power_manager_proxy_->RecordDarkResumeWakeReason(wake_reason);
112 }
113 
OnSuspendImminent(int suspend_id)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 
OnSuspendDone(int suspend_id)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 
OnDarkSuspendImminent(int suspend_id)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 
OnPowerManagerAppeared()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 
OnPowerManagerVanished()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