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 struct SuspendTime {
43 std::chrono::nanoseconds suspendOverhead;
44 std::chrono::nanoseconds suspendTime;
45 };
46
47 static const char kSleepState[] = "mem";
48 // TODO(b/128923994): we only need /sys/power/wake_[un]lock to export debugging info via
49 // /sys/kernel/debug/wakeup_sources.
50 static constexpr char kSysPowerWakeLock[] = "/sys/power/wake_lock";
51 static constexpr char kSysPowerWakeUnlock[] = "/sys/power/wake_unlock";
52 static constexpr char kUnknownWakeup[] = "unknown";
53
54 // This function assumes that data in fd is small enough that it can be read in one go.
55 // We use this function instead of the ones available in libbase because it doesn't block
56 // indefinitely when reading from socket streams which are used for testing.
readFd(int fd)57 string readFd(int fd) {
58 char buf[BUFSIZ];
59 ssize_t n = TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)));
60 if (n < 0) return "";
61 return string{buf, static_cast<size_t>(n)};
62 }
63
getCallingPid()64 static inline int getCallingPid() {
65 return ::android::hardware::IPCThreadState::self()->getCallingPid();
66 }
67
readWakeupReasons(int fd)68 static std::vector<std::string> readWakeupReasons(int fd) {
69 std::vector<std::string> wakeupReasons;
70 std::string reasonlines;
71
72 lseek(fd, 0, SEEK_SET);
73 if (!ReadFdToString(fd, &reasonlines)) {
74 LOG(ERROR) << "failed to read wakeup reasons";
75 // Return unknown wakeup reason if we fail to read
76 return {kUnknownWakeup};
77 }
78
79 std::stringstream ss(reasonlines);
80 for (std::string reasonline; std::getline(ss, reasonline);) {
81 reasonline = ::android::base::Trim(reasonline);
82
83 // Only include non-empty reason lines
84 if (!reasonline.empty()) {
85 wakeupReasons.push_back(reasonline);
86 }
87 }
88
89 // Empty wakeup reason found. Record as unknown wakeup
90 if (wakeupReasons.empty()) {
91 wakeupReasons.push_back(kUnknownWakeup);
92 }
93
94 return wakeupReasons;
95 }
96
97 // reads the suspend overhead and suspend time
98 // Returns 0s if reading the sysfs node fails (unlikely)
readSuspendTime(int fd)99 static struct SuspendTime readSuspendTime(int fd) {
100 std::string content;
101
102 lseek(fd, 0, SEEK_SET);
103 if (!ReadFdToString(fd, &content)) {
104 LOG(ERROR) << "failed to read suspend time";
105 return {0ns, 0ns};
106 }
107
108 double suspendOverhead, suspendTime;
109 std::stringstream ss(content);
110 if (!(ss >> suspendOverhead) || !(ss >> suspendTime)) {
111 LOG(ERROR) << "failed to parse suspend time " << content;
112 return {0ns, 0ns};
113 }
114
115 return {std::chrono::duration_cast<std::chrono::nanoseconds>(
116 std::chrono::duration<double>(suspendOverhead)),
117 std::chrono::duration_cast<std::chrono::nanoseconds>(
118 std::chrono::duration<double>(suspendTime))};
119 }
120
WakeLock(SystemSuspend * systemSuspend,const string & name,int pid)121 WakeLock::WakeLock(SystemSuspend* systemSuspend, const string& name, int pid)
122 : mReleased(), mSystemSuspend(systemSuspend), mName(name), mPid(pid) {
123 mSystemSuspend->incSuspendCounter(mName);
124 }
125
~WakeLock()126 WakeLock::~WakeLock() {
127 releaseOnce();
128 }
129
release()130 Return<void> WakeLock::release() {
131 releaseOnce();
132 return Void();
133 }
134
releaseOnce()135 void WakeLock::releaseOnce() {
136 std::call_once(mReleased, [this]() {
137 mSystemSuspend->decSuspendCounter(mName);
138 mSystemSuspend->updateWakeLockStatOnRelease(mName, mPid, getTimeNow());
139 });
140 }
141
SystemSuspend(unique_fd wakeupCountFd,unique_fd stateFd,unique_fd suspendStatsFd,size_t maxStatsEntries,unique_fd kernelWakelockStatsFd,unique_fd wakeupReasonsFd,unique_fd suspendTimeFd,const SleepTimeConfig & sleepTimeConfig,const sp<SuspendControlService> & controlService,const sp<SuspendControlServiceInternal> & controlServiceInternal,bool useSuspendCounter)142 SystemSuspend::SystemSuspend(unique_fd wakeupCountFd, unique_fd stateFd, unique_fd suspendStatsFd,
143 size_t maxStatsEntries, unique_fd kernelWakelockStatsFd,
144 unique_fd wakeupReasonsFd, unique_fd suspendTimeFd,
145 const SleepTimeConfig& sleepTimeConfig,
146 const sp<SuspendControlService>& controlService,
147 const sp<SuspendControlServiceInternal>& controlServiceInternal,
148 bool useSuspendCounter)
149 : mSuspendCounter(0),
150 mWakeupCountFd(std::move(wakeupCountFd)),
151 mStateFd(std::move(stateFd)),
152 mSuspendStatsFd(std::move(suspendStatsFd)),
153 mSuspendTimeFd(std::move(suspendTimeFd)),
154 kSleepTimeConfig(sleepTimeConfig),
155 mSleepTime(sleepTimeConfig.baseSleepTime),
156 mNumConsecutiveBadSuspends(0),
157 mControlService(controlService),
158 mControlServiceInternal(controlServiceInternal),
159 mStatsList(maxStatsEntries, std::move(kernelWakelockStatsFd)),
160 mWakeupList(maxStatsEntries),
161 mUseSuspendCounter(useSuspendCounter),
162 mWakeLockFd(-1),
163 mWakeUnlockFd(-1),
164 mWakeupReasonsFd(std::move(wakeupReasonsFd)) {
165 mControlServiceInternal->setSuspendService(this);
166
167 if (!mUseSuspendCounter) {
168 mWakeLockFd.reset(TEMP_FAILURE_RETRY(open(kSysPowerWakeLock, O_CLOEXEC | O_RDWR)));
169 if (mWakeLockFd < 0) {
170 PLOG(ERROR) << "error opening " << kSysPowerWakeLock;
171 }
172 mWakeUnlockFd.reset(TEMP_FAILURE_RETRY(open(kSysPowerWakeUnlock, O_CLOEXEC | O_RDWR)));
173 if (mWakeUnlockFd < 0) {
174 PLOG(ERROR) << "error opening " << kSysPowerWakeUnlock;
175 }
176 }
177 }
178
enableAutosuspend()179 bool SystemSuspend::enableAutosuspend() {
180 if (mAutosuspendEnabled.test_and_set()) {
181 LOG(ERROR) << "Autosuspend already started.";
182 return false;
183 }
184
185 initAutosuspend();
186 return true;
187 }
188
forceSuspend()189 bool SystemSuspend::forceSuspend() {
190 // We are forcing the system to suspend. This particular call ignores all
191 // existing wakelocks (full or partial). It does not cancel the wakelocks
192 // or reset mSuspendCounter, it just ignores them. When the system
193 // returns from suspend, the wakelocks and SuspendCounter will not have
194 // changed.
195 auto counterLock = std::unique_lock(mCounterLock);
196 bool success = WriteStringToFd(kSleepState, mStateFd);
197 counterLock.unlock();
198
199 if (!success) {
200 PLOG(VERBOSE) << "error writing to /sys/power/state for forceSuspend";
201 }
202 return success;
203 }
204
acquireWakeLock(WakeLockType,const hidl_string & name)205 Return<sp<IWakeLock>> SystemSuspend::acquireWakeLock(WakeLockType /* type */,
206 const hidl_string& name) {
207 auto pid = getCallingPid();
208 auto timeNow = getTimeNow();
209 IWakeLock* wl = new WakeLock{this, name, pid};
210 mControlService->notifyWakelock(name, true);
211 mStatsList.updateOnAcquire(name, pid, timeNow);
212 return wl;
213 }
214
incSuspendCounter(const string & name)215 void SystemSuspend::incSuspendCounter(const string& name) {
216 auto l = std::lock_guard(mCounterLock);
217 if (mUseSuspendCounter) {
218 mSuspendCounter++;
219 } else {
220 if (!WriteStringToFd(name, mWakeLockFd)) {
221 PLOG(ERROR) << "error writing " << name << " to " << kSysPowerWakeLock;
222 }
223 }
224 }
225
decSuspendCounter(const string & name)226 void SystemSuspend::decSuspendCounter(const string& name) {
227 auto l = std::lock_guard(mCounterLock);
228 if (mUseSuspendCounter) {
229 if (--mSuspendCounter == 0) {
230 mCounterCondVar.notify_one();
231 }
232 } else {
233 if (!WriteStringToFd(name, mWakeUnlockFd)) {
234 PLOG(ERROR) << "error writing " << name << " to " << kSysPowerWakeUnlock;
235 }
236 }
237 }
238
initAutosuspend()239 void SystemSuspend::initAutosuspend() {
240 std::thread autosuspendThread([this] {
241 while (true) {
242 std::this_thread::sleep_for(mSleepTime);
243 lseek(mWakeupCountFd, 0, SEEK_SET);
244 const string wakeupCount = readFd(mWakeupCountFd);
245 if (wakeupCount.empty()) {
246 PLOG(ERROR) << "error reading from /sys/power/wakeup_count";
247 continue;
248 }
249
250 auto counterLock = std::unique_lock(mCounterLock);
251 mCounterCondVar.wait(counterLock, [this] { return mSuspendCounter == 0; });
252 // The mutex is locked and *MUST* remain locked until we write to /sys/power/state.
253 // Otherwise, a WakeLock might be acquired after we check mSuspendCounter and before we
254 // write to /sys/power/state.
255
256 if (!WriteStringToFd(wakeupCount, mWakeupCountFd)) {
257 PLOG(VERBOSE) << "error writing from /sys/power/wakeup_count";
258 continue;
259 }
260 bool success = WriteStringToFd(kSleepState, mStateFd);
261 counterLock.unlock();
262
263 if (!success) {
264 PLOG(VERBOSE) << "error writing to /sys/power/state";
265 }
266
267 struct SuspendTime suspendTime = readSuspendTime(mSuspendTimeFd);
268 updateSleepTime(success, suspendTime);
269
270 std::vector<std::string> wakeupReasons = readWakeupReasons(mWakeupReasonsFd);
271 mWakeupList.update(wakeupReasons);
272
273 mControlService->notifyWakeup(success, wakeupReasons);
274 }
275 });
276 autosuspendThread.detach();
277 LOG(INFO) << "automatic system suspend enabled";
278 }
279
280 /**
281 * Updates sleep time depending on the result of suspend attempt.
282 * Time (in milliseconds) between suspend attempts is described the formula
283 * t[n] = { B, 0 < n <= N
284 * { min(B * (S**(n - N)), M), n > N
285 * where:
286 * n is the number of consecutive bad suspend attempts,
287 * B = kBaseSleepTime,
288 * N = kSuspendBackoffThreshold,
289 * S = kSleepTimeScaleFactor,
290 * M = kMaxSleepTime
291 *
292 * kFailedSuspendBackoffEnabled determines whether a failed suspend is counted as a bad suspend
293 *
294 * kShortSuspendBackoffEnabled determines whether a suspend whose duration
295 * t < kShortSuspendThreshold is counted as a bad suspend
296 */
updateSleepTime(bool success,const struct SuspendTime & suspendTime)297 void SystemSuspend::updateSleepTime(bool success, const struct SuspendTime& suspendTime) {
298 std::scoped_lock lock(mSuspendInfoLock);
299 mSuspendInfo.suspendAttemptCount++;
300 mSuspendInfo.sleepTimeMillis +=
301 std::chrono::round<std::chrono::milliseconds>(mSleepTime).count();
302
303 bool shortSuspend = success && (suspendTime.suspendTime > 0ns) &&
304 (suspendTime.suspendTime < kSleepTimeConfig.shortSuspendThreshold);
305
306 bool badSuspend = (kSleepTimeConfig.failedSuspendBackoffEnabled && !success) ||
307 (kSleepTimeConfig.shortSuspendBackoffEnabled && shortSuspend);
308
309 auto suspendTimeMillis =
310 std::chrono::round<std::chrono::milliseconds>(suspendTime.suspendTime).count();
311 auto suspendOverheadMillis =
312 std::chrono::round<std::chrono::milliseconds>(suspendTime.suspendOverhead).count();
313
314 if (success) {
315 mSuspendInfo.suspendOverheadTimeMillis += suspendOverheadMillis;
316 mSuspendInfo.suspendTimeMillis += suspendTimeMillis;
317 } else {
318 mSuspendInfo.failedSuspendCount++;
319 mSuspendInfo.failedSuspendOverheadTimeMillis += suspendOverheadMillis;
320 }
321
322 if (shortSuspend) {
323 mSuspendInfo.shortSuspendCount++;
324 mSuspendInfo.shortSuspendTimeMillis += suspendTimeMillis;
325 }
326
327 if (!badSuspend) {
328 mNumConsecutiveBadSuspends = 0;
329 mSleepTime = kSleepTimeConfig.baseSleepTime;
330 return;
331 }
332
333 // Suspend attempt was bad (failed or short suspend)
334 if (mNumConsecutiveBadSuspends >= kSleepTimeConfig.backoffThreshold) {
335 if (mNumConsecutiveBadSuspends == kSleepTimeConfig.backoffThreshold) {
336 mSuspendInfo.newBackoffCount++;
337 } else {
338 mSuspendInfo.backoffContinueCount++;
339 }
340
341 mSleepTime = std::min(std::chrono::round<std::chrono::milliseconds>(
342 mSleepTime * kSleepTimeConfig.sleepTimeScaleFactor),
343 kSleepTimeConfig.maxSleepTime);
344 }
345
346 mNumConsecutiveBadSuspends++;
347 }
348
updateWakeLockStatOnRelease(const std::string & name,int pid,TimestampType timeNow)349 void SystemSuspend::updateWakeLockStatOnRelease(const std::string& name, int pid,
350 TimestampType timeNow) {
351 mControlService->notifyWakelock(name, false);
352 mStatsList.updateOnRelease(name, pid, timeNow);
353 }
354
getStatsList() const355 const WakeLockEntryList& SystemSuspend::getStatsList() const {
356 return mStatsList;
357 }
358
updateStatsNow()359 void SystemSuspend::updateStatsNow() {
360 mStatsList.updateNow();
361 }
362
getSuspendInfo(SuspendInfo * info)363 void SystemSuspend::getSuspendInfo(SuspendInfo* info) {
364 std::scoped_lock lock(mSuspendInfoLock);
365
366 *info = mSuspendInfo;
367 }
368
getWakeupList() const369 const WakeupList& SystemSuspend::getWakeupList() const {
370 return mWakeupList;
371 }
372
373 /**
374 * Returns suspend stats.
375 */
getSuspendStats()376 Result<SuspendStats> SystemSuspend::getSuspendStats() {
377 SuspendStats stats;
378 std::unique_ptr<DIR, decltype(&closedir)> dp(fdopendir(dup(mSuspendStatsFd.get())), &closedir);
379 if (!dp) {
380 return stats;
381 }
382
383 // rewinddir, else subsequent calls will not get any suspend_stats
384 rewinddir(dp.get());
385
386 struct dirent* de;
387
388 // Grab a wakelock before reading suspend stats,
389 // to ensure a consistent snapshot.
390 sp<IWakeLock> suspendStatsLock = acquireWakeLock(WakeLockType::PARTIAL, "suspend_stats_lock");
391
392 while ((de = readdir(dp.get()))) {
393 std::string statName(de->d_name);
394 if ((statName == ".") || (statName == "..")) {
395 continue;
396 }
397
398 unique_fd statFd{TEMP_FAILURE_RETRY(
399 openat(mSuspendStatsFd.get(), statName.c_str(), O_CLOEXEC | O_RDONLY))};
400 if (statFd < 0) {
401 return Error() << "Failed to open " << statName;
402 }
403
404 std::string valStr;
405 if (!ReadFdToString(statFd.get(), &valStr)) {
406 return Error() << "Failed to read " << statName;
407 }
408
409 // Trim newline
410 valStr.erase(std::remove(valStr.begin(), valStr.end(), '\n'), valStr.end());
411
412 if (statName == "last_failed_dev") {
413 stats.lastFailedDev = valStr;
414 } else if (statName == "last_failed_step") {
415 stats.lastFailedStep = valStr;
416 } else {
417 int statVal = std::stoi(valStr);
418 if (statName == "success") {
419 stats.success = statVal;
420 } else if (statName == "fail") {
421 stats.fail = statVal;
422 } else if (statName == "failed_freeze") {
423 stats.failedFreeze = statVal;
424 } else if (statName == "failed_prepare") {
425 stats.failedPrepare = statVal;
426 } else if (statName == "failed_suspend") {
427 stats.failedSuspend = statVal;
428 } else if (statName == "failed_suspend_late") {
429 stats.failedSuspendLate = statVal;
430 } else if (statName == "failed_suspend_noirq") {
431 stats.failedSuspendNoirq = statVal;
432 } else if (statName == "failed_resume") {
433 stats.failedResume = statVal;
434 } else if (statName == "failed_resume_early") {
435 stats.failedResumeEarly = statVal;
436 } else if (statName == "failed_resume_noirq") {
437 stats.failedResumeNoirq = statVal;
438 } else if (statName == "last_failed_errno") {
439 stats.lastFailedErrno = statVal;
440 }
441 }
442 }
443
444 return stats;
445 }
446
getSleepTime() const447 std::chrono::milliseconds SystemSuspend::getSleepTime() const {
448 return mSleepTime;
449 }
450
451 } // namespace V1_0
452 } // namespace suspend
453 } // namespace system
454 } // namespace android
455