1 /*
2 * Copyright 2018 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 "SystemSuspend.h"
18
19 #include <android-base/file.h>
20 #include <android-base/logging.h>
21 #include <android-base/strings.h>
22 #include <fcntl.h>
23 #include <hidl/Status.h>
24 #include <hwbinder/IPCThreadState.h>
25 #include <sys/stat.h>
26 #include <sys/types.h>
27
28 #include <string>
29 #include <thread>
30
31 using ::android::base::Error;
32 using ::android::base::ReadFdToString;
33 using ::android::base::WriteStringToFd;
34 using ::android::hardware::Void;
35 using ::std::string;
36
37 namespace android {
38 namespace system {
39 namespace suspend {
40 namespace V1_0 {
41
42 static const char kSleepState[] = "mem";
43 // TODO(b/128923994): we only need /sys/power/wake_[un]lock to export debugging info via
44 // /sys/kernel/debug/wakeup_sources.
45 static constexpr char kSysPowerWakeLock[] = "/sys/power/wake_lock";
46 static constexpr char kSysPowerWakeUnlock[] = "/sys/power/wake_unlock";
47
48 // This function assumes that data in fd is small enough that it can be read in one go.
49 // We use this function instead of the ones available in libbase because it doesn't block
50 // indefinitely when reading from socket streams which are used for testing.
readFd(int fd)51 string readFd(int fd) {
52 char buf[BUFSIZ];
53 ssize_t n = TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)));
54 if (n < 0) return "";
55 return string{buf, static_cast<size_t>(n)};
56 }
57
getCallingPid()58 static inline int getCallingPid() {
59 return ::android::hardware::IPCThreadState::self()->getCallingPid();
60 }
61
WakeLock(SystemSuspend * systemSuspend,const string & name,int pid)62 WakeLock::WakeLock(SystemSuspend* systemSuspend, const string& name, int pid)
63 : mReleased(), mSystemSuspend(systemSuspend), mName(name), mPid(pid) {
64 mSystemSuspend->incSuspendCounter(mName);
65 }
66
~WakeLock()67 WakeLock::~WakeLock() {
68 releaseOnce();
69 }
70
release()71 Return<void> WakeLock::release() {
72 releaseOnce();
73 return Void();
74 }
75
releaseOnce()76 void WakeLock::releaseOnce() {
77 std::call_once(mReleased, [this]() {
78 mSystemSuspend->decSuspendCounter(mName);
79 mSystemSuspend->updateWakeLockStatOnRelease(mName, mPid, getTimeNow());
80 });
81 }
82
SystemSuspend(unique_fd wakeupCountFd,unique_fd stateFd,unique_fd suspendStatsFd,size_t maxNativeStatsEntries,unique_fd kernelWakelockStatsFd,std::chrono::milliseconds baseSleepTime,const sp<SuspendControlService> & controlService,bool useSuspendCounter)83 SystemSuspend::SystemSuspend(unique_fd wakeupCountFd, unique_fd stateFd, unique_fd suspendStatsFd,
84 size_t maxNativeStatsEntries, unique_fd kernelWakelockStatsFd,
85 std::chrono::milliseconds baseSleepTime,
86 const sp<SuspendControlService>& controlService,
87 bool useSuspendCounter)
88 : mSuspendCounter(0),
89 mWakeupCountFd(std::move(wakeupCountFd)),
90 mStateFd(std::move(stateFd)),
91 mSuspendStatsFd(std::move(suspendStatsFd)),
92 mBaseSleepTime(baseSleepTime),
93 mSleepTime(baseSleepTime),
94 mControlService(controlService),
95 mStatsList(maxNativeStatsEntries, std::move(kernelWakelockStatsFd)),
96 mUseSuspendCounter(useSuspendCounter),
97 mWakeLockFd(-1),
98 mWakeUnlockFd(-1) {
99 mControlService->setSuspendService(this);
100
101 if (!mUseSuspendCounter) {
102 mWakeLockFd.reset(TEMP_FAILURE_RETRY(open(kSysPowerWakeLock, O_CLOEXEC | O_RDWR)));
103 if (mWakeLockFd < 0) {
104 PLOG(ERROR) << "error opening " << kSysPowerWakeLock;
105 }
106 mWakeUnlockFd.reset(TEMP_FAILURE_RETRY(open(kSysPowerWakeUnlock, O_CLOEXEC | O_RDWR)));
107 if (mWakeUnlockFd < 0) {
108 PLOG(ERROR) << "error opening " << kSysPowerWakeUnlock;
109 }
110 }
111 }
112
enableAutosuspend()113 bool SystemSuspend::enableAutosuspend() {
114 static bool initialized = false;
115 if (initialized) {
116 LOG(ERROR) << "Autosuspend already started.";
117 return false;
118 }
119
120 initAutosuspend();
121 initialized = true;
122 return true;
123 }
124
forceSuspend()125 bool SystemSuspend::forceSuspend() {
126 // We are forcing the system to suspend. This particular call ignores all
127 // existing wakelocks (full or partial). It does not cancel the wakelocks
128 // or reset mSuspendCounter, it just ignores them. When the system
129 // returns from suspend, the wakelocks and SuspendCounter will not have
130 // changed.
131 auto counterLock = std::unique_lock(mCounterLock);
132 bool success = WriteStringToFd(kSleepState, mStateFd);
133 counterLock.unlock();
134
135 if (!success) {
136 PLOG(VERBOSE) << "error writing to /sys/power/state for forceSuspend";
137 }
138 return success;
139 }
140
acquireWakeLock(WakeLockType,const hidl_string & name)141 Return<sp<IWakeLock>> SystemSuspend::acquireWakeLock(WakeLockType /* type */,
142 const hidl_string& name) {
143 auto pid = getCallingPid();
144 auto timeNow = getTimeNow();
145 IWakeLock* wl = new WakeLock{this, name, pid};
146 mStatsList.updateOnAcquire(name, pid, timeNow);
147 return wl;
148 }
149
incSuspendCounter(const string & name)150 void SystemSuspend::incSuspendCounter(const string& name) {
151 auto l = std::lock_guard(mCounterLock);
152 if (mUseSuspendCounter) {
153 mSuspendCounter++;
154 } else {
155 if (!WriteStringToFd(name, mWakeLockFd)) {
156 PLOG(ERROR) << "error writing " << name << " to " << kSysPowerWakeLock;
157 }
158 }
159 }
160
decSuspendCounter(const string & name)161 void SystemSuspend::decSuspendCounter(const string& name) {
162 auto l = std::lock_guard(mCounterLock);
163 if (mUseSuspendCounter) {
164 if (--mSuspendCounter == 0) {
165 mCounterCondVar.notify_one();
166 }
167 } else {
168 if (!WriteStringToFd(name, mWakeUnlockFd)) {
169 PLOG(ERROR) << "error writing " << name << " to " << kSysPowerWakeUnlock;
170 }
171 }
172 }
173
initAutosuspend()174 void SystemSuspend::initAutosuspend() {
175 std::thread autosuspendThread([this] {
176 while (true) {
177 std::this_thread::sleep_for(mSleepTime);
178 lseek(mWakeupCountFd, 0, SEEK_SET);
179 const string wakeupCount = readFd(mWakeupCountFd);
180 if (wakeupCount.empty()) {
181 PLOG(ERROR) << "error reading from /sys/power/wakeup_count";
182 continue;
183 }
184
185 auto counterLock = std::unique_lock(mCounterLock);
186 mCounterCondVar.wait(counterLock, [this] { return mSuspendCounter == 0; });
187 // The mutex is locked and *MUST* remain locked until we write to /sys/power/state.
188 // Otherwise, a WakeLock might be acquired after we check mSuspendCounter and before we
189 // write to /sys/power/state.
190
191 if (!WriteStringToFd(wakeupCount, mWakeupCountFd)) {
192 PLOG(VERBOSE) << "error writing from /sys/power/wakeup_count";
193 continue;
194 }
195 bool success = WriteStringToFd(kSleepState, mStateFd);
196 counterLock.unlock();
197
198 if (!success) {
199 PLOG(VERBOSE) << "error writing to /sys/power/state";
200 }
201
202 mControlService->notifyWakeup(success);
203
204 updateSleepTime(success);
205 }
206 });
207 autosuspendThread.detach();
208 LOG(INFO) << "automatic system suspend enabled";
209 }
210
updateSleepTime(bool success)211 void SystemSuspend::updateSleepTime(bool success) {
212 static constexpr std::chrono::milliseconds kMaxSleepTime = 1min;
213 if (success) {
214 mSleepTime = mBaseSleepTime;
215 return;
216 }
217 // Double sleep time after each failure up to one minute.
218 mSleepTime = std::min(mSleepTime * 2, kMaxSleepTime);
219 }
220
updateWakeLockStatOnRelease(const std::string & name,int pid,TimestampType timeNow)221 void SystemSuspend::updateWakeLockStatOnRelease(const std::string& name, int pid,
222 TimestampType timeNow) {
223 mStatsList.updateOnRelease(name, pid, timeNow);
224 }
225
getStatsList() const226 const WakeLockEntryList& SystemSuspend::getStatsList() const {
227 return mStatsList;
228 }
229
updateStatsNow()230 void SystemSuspend::updateStatsNow() {
231 mStatsList.updateNow();
232 }
233
234 /**
235 * Returns suspend stats.
236 */
getSuspendStats()237 Result<SuspendStats> SystemSuspend::getSuspendStats() {
238 SuspendStats stats;
239 std::unique_ptr<DIR, decltype(&closedir)> dp(fdopendir(dup(mSuspendStatsFd.get())), &closedir);
240 if (!dp) {
241 return stats;
242 }
243
244 // rewinddir, else subsequent calls will not get any suspend_stats
245 rewinddir(dp.get());
246
247 struct dirent* de;
248
249 // Grab a wakelock before reading suspend stats,
250 // to ensure a consistent snapshot.
251 sp<IWakeLock> suspendStatsLock = acquireWakeLock(WakeLockType::PARTIAL, "suspend_stats_lock");
252
253 while ((de = readdir(dp.get()))) {
254 std::string statName(de->d_name);
255 if ((statName == ".") || (statName == "..")) {
256 continue;
257 }
258
259 unique_fd statFd{TEMP_FAILURE_RETRY(
260 openat(mSuspendStatsFd.get(), statName.c_str(), O_CLOEXEC | O_RDONLY))};
261 if (statFd < 0) {
262 return Error() << "Failed to open " << statName;
263 }
264
265 std::string valStr;
266 if (!ReadFdToString(statFd.get(), &valStr)) {
267 return Error() << "Failed to read " << statName;
268 }
269
270 // Trim newline
271 valStr.erase(std::remove(valStr.begin(), valStr.end(), '\n'), valStr.end());
272
273 if (statName == "last_failed_dev") {
274 stats.lastFailedDev = valStr;
275 } else if (statName == "last_failed_step") {
276 stats.lastFailedStep = valStr;
277 } else {
278 int statVal = std::stoi(valStr);
279 if (statName == "success") {
280 stats.success = statVal;
281 } else if (statName == "fail") {
282 stats.fail = statVal;
283 } else if (statName == "failed_freeze") {
284 stats.failedFreeze = statVal;
285 } else if (statName == "failed_prepare") {
286 stats.failedPrepare = statVal;
287 } else if (statName == "failed_suspend") {
288 stats.failedSuspend = statVal;
289 } else if (statName == "failed_suspend_late") {
290 stats.failedSuspendLate = statVal;
291 } else if (statName == "failed_suspend_noirq") {
292 stats.failedSuspendNoirq = statVal;
293 } else if (statName == "failed_resume") {
294 stats.failedResume = statVal;
295 } else if (statName == "failed_resume_early") {
296 stats.failedResumeEarly = statVal;
297 } else if (statName == "failed_resume_noirq") {
298 stats.failedResumeNoirq = statVal;
299 } else if (statName == "last_failed_errno") {
300 stats.lastFailedErrno = statVal;
301 }
302 }
303 }
304
305 return stats;
306 }
307
308 } // namespace V1_0
309 } // namespace suspend
310 } // namespace system
311 } // namespace android
312