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
35using base::Bind;
36using base::TimeDelta;
37using base::Unretained;
38using std::map;
39using std::string;
40
41namespace shill {
42
43// static
44const int PowerManager::kInvalidSuspendId = -1;
45const char PowerManager::kSuspendDelayDescription[] = "shill";
46const char PowerManager::kDarkSuspendDelayDescription[] = "shill";
47const int PowerManager::kSuspendTimeoutMilliseconds = 15 * 1000;
48
49PowerManager::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
62PowerManager::~PowerManager() {}
63
64void 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
80void 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
94bool 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
104bool PowerManager::ReportDarkSuspendReadiness() {
105  return power_manager_proxy_->ReportDarkSuspendReadiness(
106      dark_suspend_delay_id_,
107      current_dark_suspend_id_);
108}
109
110bool PowerManager::RecordDarkResumeWakeReason(const string& wake_reason) {
111  return power_manager_proxy_->RecordDarkResumeWakeReason(wake_reason);
112}
113
114void 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
130void 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
144void 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
158void 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
173void 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