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 #define ATRACE_TAG ATRACE_TAG_POWER
18 #define ATRACE_TRACK_BACKOFF "suspend_backoff"
19
20 #include "SystemSuspend.h"
21
22 #include <aidl/android/system/suspend/ISystemSuspend.h>
23 #include <aidl/android/system/suspend/IWakeLock.h>
24 #include <android-base/file.h>
25 #include <android-base/logging.h>
26 #include <android-base/parseint.h>
27 #include <android-base/properties.h>
28 #include <android-base/stringprintf.h>
29 #include <android-base/strings.h>
30 #include <android/binder_manager.h>
31 #include <android/system/suspend/internal/ISuspendControlServiceInternal.h>
32 #include <fcntl.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35
36 #include <chrono>
37 #include <cstdlib>
38 #include <string>
39 #include <thread>
40 using namespace std::chrono_literals;
41
42 using ::aidl::android::system::suspend::ISystemSuspend;
43 using ::aidl::android::system::suspend::IWakeLock;
44 using ::aidl::android::system::suspend::WakeLockType;
45 using ::android::base::CachedProperty;
46 using ::android::base::Error;
47 using ::android::base::ParseInt;
48 using ::android::base::ParseUint;
49 using ::android::base::ReadFdToString;
50 using ::android::base::StringPrintf;
51 using ::android::base::WriteStringToFd;
52 using ::std::string;
53
54 using ISCSI = ::android::system::suspend::internal::ISuspendControlServiceInternal;
55
56 namespace android {
57 namespace system {
58 namespace suspend {
59 namespace V1_0 {
60
61 struct SuspendTime {
62 std::chrono::nanoseconds suspendOverhead;
63 std::chrono::nanoseconds suspendTime;
64 };
65
66 static const char kSleepState[] = "mem";
67 // TODO(b/128923994): we only need /sys/power/wake_[un]lock to export debugging info via
68 // /sys/kernel/debug/wakeup_sources.
69 static constexpr char kSysPowerWakeLock[] = "/sys/power/wake_lock";
70 static constexpr char kSysPowerWakeUnlock[] = "/sys/power/wake_unlock";
71 static constexpr char kUnknownWakeup[] = "unknown";
72 // This is used to disable autosuspend when zygote is restarted
73 // it allows the system to make progress before autosuspend is kicked
74 // NOTE: If the name of this wakelock is changed then also update the name
75 // in rootdir/init.zygote32.rc, rootdir/init.zygote64.rc, and
76 // rootdir/init.zygote64_32.rc
77 static constexpr char kZygoteKernelWakelock[] = "zygote_kwl";
78
79 // This function assumes that data in fd is small enough that it can be read in one go.
80 // We use this function instead of the ones available in libbase because it doesn't block
81 // indefinitely when reading from socket streams which are used for testing.
readFd(int fd)82 string readFd(int fd) {
83 char buf[BUFSIZ];
84 ssize_t n = TEMP_FAILURE_RETRY(read(fd, &buf[0], sizeof(buf)));
85 if (n < 0) return "";
86 return string{buf, static_cast<size_t>(n)};
87 }
88
readWakeupReasons(int fd)89 static std::vector<std::string> readWakeupReasons(int fd) {
90 std::vector<std::string> wakeupReasons;
91 std::string reasonlines;
92
93 lseek(fd, 0, SEEK_SET);
94
95 bool ret = ReadFdToString(fd, &reasonlines);
96 if (!ret)
97 PLOG(ERROR) << "failed to read wakeup reasons";
98
99 // Return unknown wakeup reason if reading wakeup reasons fails or is empty
100 if (!ret || reasonlines.empty())
101 return {kUnknownWakeup};
102
103 std::stringstream ss(reasonlines);
104 for (std::string reasonline; std::getline(ss, reasonline);) {
105 reasonline = ::android::base::Trim(reasonline);
106
107 // Only include non-empty reason lines
108 if (!reasonline.empty()) {
109 wakeupReasons.push_back(reasonline);
110 }
111 }
112
113 // Empty wakeup reason found. Record as unknown wakeup
114 if (wakeupReasons.empty()) {
115 wakeupReasons.push_back(kUnknownWakeup);
116 }
117
118 return wakeupReasons;
119 }
120
121 // reads the suspend overhead and suspend time
122 // Returns 0s if reading the sysfs node fails (unlikely)
readSuspendTime(int fd)123 static struct SuspendTime readSuspendTime(int fd) {
124 std::string content;
125
126 lseek(fd, 0, SEEK_SET);
127 if (!ReadFdToString(fd, &content)) {
128 LOG(ERROR) << "failed to read suspend time";
129 return {0ns, 0ns};
130 }
131
132 double suspendOverhead, suspendTime;
133 std::stringstream ss(content);
134 if (!(ss >> suspendOverhead) || !(ss >> suspendTime)) {
135 LOG(ERROR) << "failed to parse suspend time " << content;
136 return {0ns, 0ns};
137 }
138
139 return {std::chrono::duration_cast<std::chrono::nanoseconds>(
140 std::chrono::duration<double>(suspendOverhead)),
141 std::chrono::duration_cast<std::chrono::nanoseconds>(
142 std::chrono::duration<double>(suspendTime))};
143 }
144
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)145 SystemSuspend::SystemSuspend(unique_fd wakeupCountFd, unique_fd stateFd, unique_fd suspendStatsFd,
146 size_t maxStatsEntries, unique_fd kernelWakelockStatsFd,
147 unique_fd wakeupReasonsFd, unique_fd suspendTimeFd,
148 const SleepTimeConfig& sleepTimeConfig,
149 const sp<SuspendControlService>& controlService,
150 const sp<SuspendControlServiceInternal>& controlServiceInternal,
151 bool useSuspendCounter)
152 : mSuspendCounter(0),
153 mWakeupCountFd(std::move(wakeupCountFd)),
154 mStateFd(std::move(stateFd)),
155 mSuspendStatsFd(std::move(suspendStatsFd)),
156 mSuspendTimeFd(std::move(suspendTimeFd)),
157 kSleepTimeConfig(sleepTimeConfig),
158 mSleepTime(sleepTimeConfig.baseSleepTime),
159 mNumConsecutiveBadSuspends(0),
160 mControlService(controlService),
161 mControlServiceInternal(controlServiceInternal),
162 mStatsList(maxStatsEntries, std::move(kernelWakelockStatsFd)),
163 mWakeupList(maxStatsEntries),
164 mUseSuspendCounter(useSuspendCounter),
165 mWakeLockFd(-1),
166 mWakeUnlockFd(-1),
167 mWakeupReasonsFd(std::move(wakeupReasonsFd)) {
168 mControlServiceInternal->setSuspendService(this);
169
170 if (!mUseSuspendCounter) {
171 mWakeLockFd.reset(TEMP_FAILURE_RETRY(open(kSysPowerWakeLock, O_CLOEXEC | O_RDWR)));
172 if (mWakeLockFd < 0) {
173 PLOG(ERROR) << "error opening " << kSysPowerWakeLock;
174 }
175 }
176
177 mWakeUnlockFd.reset(TEMP_FAILURE_RETRY(open(kSysPowerWakeUnlock, O_CLOEXEC | O_RDWR)));
178 if (mWakeUnlockFd < 0) {
179 PLOG(ERROR) << "error opening " << kSysPowerWakeUnlock;
180 }
181 }
182
enableAutosuspend(const sp<IBinder> & token)183 bool SystemSuspend::enableAutosuspend(const sp<IBinder>& token) {
184 auto tokensLock = std::lock_guard(mAutosuspendClientTokensLock);
185 auto autosuspendLock = std::lock_guard(mAutosuspendLock);
186
187 // Disable zygote kernel wakelock, since explicitly attempting to
188 // enable autosuspend. This should be done even if autosuspend is
189 // already enabled, since it could be the case that the framework
190 // is restarting and connecting to the existing suspend service.
191 if (!WriteStringToFd(kZygoteKernelWakelock, mWakeUnlockFd)) {
192 PLOG(ERROR) << "error writing " << kZygoteKernelWakelock << " to " << kSysPowerWakeUnlock;
193 }
194
195 bool hasToken = std::find(mAutosuspendClientTokens.begin(), mAutosuspendClientTokens.end(),
196 token) != mAutosuspendClientTokens.end();
197
198 if (!hasToken) {
199 mAutosuspendClientTokens.push_back(token);
200 }
201
202 if (mAutosuspendEnabled) {
203 LOG(ERROR) << "Autosuspend already started.";
204 return false;
205 }
206
207 mAutosuspendEnabled = true;
208 initAutosuspendLocked();
209 return true;
210 }
211
disableAutosuspendLocked()212 void SystemSuspend::disableAutosuspendLocked() {
213 mAutosuspendClientTokens.clear();
214 if (mAutosuspendEnabled) {
215 mAutosuspendEnabled = false;
216 mAutosuspendCondVar.notify_all();
217 LOG(INFO) << "automatic system suspend disabled";
218 }
219 }
220
disableAutosuspend()221 void SystemSuspend::disableAutosuspend() {
222 auto tokensLock = std::lock_guard(mAutosuspendClientTokensLock);
223 auto autosuspendLock = std::lock_guard(mAutosuspendLock);
224 disableAutosuspendLocked();
225 }
226
checkAutosuspendClientsLivenessLocked()227 void SystemSuspend::checkAutosuspendClientsLivenessLocked() {
228 // Ping autosuspend client tokens, remove any dead tokens from the list.
229 // mAutosuspendLock must not be held when calling this, as that could lead to a deadlock
230 // if pingBinder() can't be processed by system_server because it's Binder thread pool is
231 // exhausted and blocked on acquire/release wakelock calls.
232 mAutosuspendClientTokens.erase(
233 std::remove_if(mAutosuspendClientTokens.begin(), mAutosuspendClientTokens.end(),
234 [](const sp<IBinder>& token) { return token->pingBinder() != OK; }),
235 mAutosuspendClientTokens.end());
236 }
237
hasAliveAutosuspendTokenLocked()238 bool SystemSuspend::hasAliveAutosuspendTokenLocked() {
239 return !mAutosuspendClientTokens.empty();
240 }
241
~SystemSuspend(void)242 SystemSuspend::~SystemSuspend(void) {
243 auto tokensLock = std::lock_guard(mAutosuspendClientTokensLock);
244 auto autosuspendLock = std::unique_lock(mAutosuspendLock);
245
246 // signal autosuspend thread to shut down
247 disableAutosuspendLocked();
248
249 // wait for autosuspend thread to exit
250 mAutosuspendCondVar.wait_for(autosuspendLock, 100ms, [this]() REQUIRES(mAutosuspendLock) {
251 return !mAutosuspendThreadCreated;
252 });
253 }
254
forceSuspend()255 bool SystemSuspend::forceSuspend() {
256 #ifndef FUZZ_MODE_SUSPEND_SERVICE
257 // We are forcing the system to suspend. This particular call ignores all
258 // existing wakelocks (full or partial). It does not cancel the wakelocks
259 // or reset mSuspendCounter, it just ignores them. When the system
260 // returns from suspend, the wakelocks and SuspendCounter will not have
261 // changed.
262 auto autosuspendLock = std::unique_lock(mAutosuspendLock);
263 bool success = WriteStringToFd(kSleepState, mStateFd);
264 autosuspendLock.unlock();
265
266 if (!success) {
267 PLOG(VERBOSE) << "error writing to /sys/power/state for forceSuspend";
268 }
269 return success;
270 #else
271 return false;
272 #endif // !FUZZ_MODE_SUSPEND_SERVICE
273 }
274
incSuspendCounter(const string & name)275 void SystemSuspend::incSuspendCounter(const string& name) {
276 auto l = std::lock_guard(mAutosuspendLock);
277 if (mUseSuspendCounter) {
278 mSuspendCounter++;
279 } else {
280 if (!WriteStringToFd(name, mWakeLockFd)) {
281 PLOG(ERROR) << "error writing " << name << " to " << kSysPowerWakeLock;
282 }
283 }
284 }
285
decSuspendCounter(const string & name)286 void SystemSuspend::decSuspendCounter(const string& name) {
287 auto l = std::lock_guard(mAutosuspendLock);
288 if (mUseSuspendCounter) {
289 if (--mSuspendCounter == 0) {
290 mAutosuspendCondVar.notify_one();
291 }
292 } else {
293 if (!WriteStringToFd(name, mWakeUnlockFd)) {
294 PLOG(ERROR) << "error writing " << name << " to " << kSysPowerWakeUnlock;
295 }
296 }
297 }
298
reopenFileUsingFd(const int fd,const int permission)299 unique_fd SystemSuspend::reopenFileUsingFd(const int fd, const int permission) {
300 string filePath = android::base::StringPrintf("/proc/self/fd/%d", fd);
301
302 unique_fd tempFd{TEMP_FAILURE_RETRY(open(filePath.c_str(), permission))};
303 if (tempFd < 0) {
304 PLOG(ERROR) << "SystemSuspend: Error opening file, using path: " << filePath;
305 return unique_fd(-1);
306 }
307 return tempFd;
308 }
309
initAutosuspendLocked()310 void SystemSuspend::initAutosuspendLocked() {
311 if (mAutosuspendThreadCreated) {
312 LOG(INFO) << "Autosuspend thread already started.";
313 return;
314 }
315
316 std::thread autosuspendThread([this] {
317 auto autosuspendLock = std::unique_lock(mAutosuspendLock);
318 bool shouldSleep = true;
319
320 while (true) {
321 {
322 base::ScopedLockAssertion autosuspendLocked(mAutosuspendLock);
323
324 if (!mAutosuspendEnabled) {
325 mAutosuspendThreadCreated = false;
326 return;
327 }
328 // If we got here by a failed write to /sys/power/wakeup_count; don't sleep
329 // since we didn't attempt to suspend on the last cycle of this loop.
330 if (shouldSleep) {
331 mAutosuspendCondVar.wait_for(
332 autosuspendLock, mSleepTime,
333 [this]() REQUIRES(mAutosuspendLock) { return !mAutosuspendEnabled; });
334 }
335
336 if (!mAutosuspendEnabled) continue;
337 autosuspendLock.unlock();
338 }
339
340 lseek(mWakeupCountFd, 0, SEEK_SET);
341 string wakeupCount = readFd(mWakeupCountFd);
342
343 {
344 autosuspendLock.lock();
345 base::ScopedLockAssertion autosuspendLocked(mAutosuspendLock);
346
347 if (wakeupCount.empty()) {
348 PLOG(ERROR) << "error reading from /sys/power/wakeup_count";
349 continue;
350 }
351
352 shouldSleep = false;
353
354 mAutosuspendCondVar.wait(autosuspendLock, [this]() REQUIRES(mAutosuspendLock) {
355 return mSuspendCounter == 0 || !mAutosuspendEnabled;
356 });
357
358 if (!mAutosuspendEnabled) continue;
359 autosuspendLock.unlock();
360 }
361
362 bool success;
363 {
364 auto tokensLock = std::lock_guard(mAutosuspendClientTokensLock);
365 checkAutosuspendClientsLivenessLocked();
366
367 autosuspendLock.lock();
368 base::ScopedLockAssertion autosuspendLocked(mAutosuspendLock);
369
370 if (!hasAliveAutosuspendTokenLocked()) {
371 disableAutosuspendLocked();
372 continue;
373 }
374
375 // Check suspend counter hasn't increased while checking client liveness
376 if (mSuspendCounter > 0) {
377 continue;
378 }
379
380 // The mutex is locked and *MUST* remain locked until we write to /sys/power/state.
381 // Otherwise, a WakeLock might be acquired after we check mSuspendCounter and before
382 // we write to /sys/power/state.
383
384 if (!WriteStringToFd(wakeupCount, mWakeupCountFd)) {
385 PLOG(VERBOSE) << "error writing to /sys/power/wakeup_count";
386 continue;
387 }
388 success = WriteStringToFd(kSleepState, mStateFd);
389 shouldSleep = true;
390
391 autosuspendLock.unlock();
392 }
393
394 if (!success) {
395 PLOG(VERBOSE) << "error writing to /sys/power/state";
396 }
397
398 struct SuspendTime suspendTime = readSuspendTime(mSuspendTimeFd);
399 updateSleepTime(success, suspendTime);
400
401 std::vector<std::string> wakeupReasons = readWakeupReasons(mWakeupReasonsFd);
402 if (wakeupReasons == std::vector<std::string>({kUnknownWakeup})) {
403 LOG(INFO) << "Unknown/empty wakeup reason. Re-opening wakeup_reason file.";
404
405 mWakeupReasonsFd = reopenFileUsingFd(mWakeupReasonsFd.get(), O_CLOEXEC | O_RDONLY);
406 }
407 mWakeupList.update(wakeupReasons);
408
409 mControlService->notifyWakeup(success, wakeupReasons);
410
411 logKernelWakeLockStats();
412
413 // Take the lock before returning to the start of the loop
414 autosuspendLock.lock();
415 }
416 });
417 autosuspendThread.detach();
418 mAutosuspendThreadCreated = true;
419 LOG(INFO) << "automatic system suspend enabled";
420 }
421
logKernelWakeLockStats()422 void SystemSuspend::logKernelWakeLockStats() {
423 [[clang::no_destroy]] static CachedProperty logStatsProp("suspend.debug.wakestats_log.enabled");
424 std::string prop(logStatsProp.Get(NULL));
425
426 if ((prop.compare("true") != 0) && (prop.compare("1") != 0)) return;
427
428 std::stringstream klStats;
429 klStats << "Kernel wakesource stats: ";
430 std::vector<WakeLockInfo> wlStats;
431 mStatsList.getWakeLockStats(
432 ISCSI::WAKE_LOCK_INFO_ACTIVE_COUNT | ISCSI::WAKE_LOCK_INFO_TOTAL_TIME, &wlStats);
433
434 for (const WakeLockInfo& wake : wlStats) {
435 if ((wake.isKernelWakelock) && (wake.activeCount > 0)) {
436 klStats << wake.name << "," << wake.totalTime << "," << wake.activeCount << ";";
437 }
438 }
439 LOG(INFO) << klStats.rdbuf();
440 }
441
442 /**
443 * Updates sleep time depending on the result of suspend attempt.
444 * Time (in milliseconds) between suspend attempts is described the formula
445 * t[n] = { B, 0 < n <= N
446 * { min(B * (S**(n - N)), M), n > N
447 * where:
448 * n is the number of consecutive bad suspend attempts,
449 * B = kBaseSleepTime,
450 * N = kSuspendBackoffThreshold,
451 * S = kSleepTimeScaleFactor,
452 * M = kMaxSleepTime
453 *
454 * kFailedSuspendBackoffEnabled determines whether a failed suspend is counted as a bad suspend
455 *
456 * kShortSuspendBackoffEnabled determines whether a suspend whose duration
457 * t < kShortSuspendThreshold is counted as a bad suspend
458 */
updateSleepTime(bool success,const struct SuspendTime & suspendTime)459 void SystemSuspend::updateSleepTime(bool success, const struct SuspendTime& suspendTime) {
460 std::scoped_lock lock(mSuspendInfoLock);
461 mSuspendInfo.suspendAttemptCount++;
462 mSuspendInfo.sleepTimeMillis +=
463 std::chrono::round<std::chrono::milliseconds>(mSleepTime).count();
464
465 bool shortSuspend = success && (suspendTime.suspendTime > 0ns) &&
466 (suspendTime.suspendTime < kSleepTimeConfig.shortSuspendThreshold);
467
468 bool badSuspend = (kSleepTimeConfig.failedSuspendBackoffEnabled && !success) ||
469 (kSleepTimeConfig.shortSuspendBackoffEnabled && shortSuspend);
470
471 auto suspendTimeMillis =
472 std::chrono::round<std::chrono::milliseconds>(suspendTime.suspendTime).count();
473 auto suspendOverheadMillis =
474 std::chrono::round<std::chrono::milliseconds>(suspendTime.suspendOverhead).count();
475
476 if (success) {
477 mSuspendInfo.suspendOverheadTimeMillis += suspendOverheadMillis;
478 mSuspendInfo.suspendTimeMillis += suspendTimeMillis;
479 } else {
480 mSuspendInfo.failedSuspendCount++;
481 mSuspendInfo.failedSuspendOverheadTimeMillis += suspendOverheadMillis;
482 }
483
484 if (shortSuspend) {
485 mSuspendInfo.shortSuspendCount++;
486 mSuspendInfo.shortSuspendTimeMillis += suspendTimeMillis;
487 }
488
489 if (!badSuspend) {
490 ATRACE_INSTANT_FOR_TRACK(ATRACE_TRACK_BACKOFF, "good");
491 mNumConsecutiveBadSuspends = 0;
492 mSleepTime = kSleepTimeConfig.baseSleepTime;
493 return;
494 }
495
496 const char* backoffDecision = "defer";
497
498 // Suspend attempt was bad (failed or short suspend)
499 if (mNumConsecutiveBadSuspends >= kSleepTimeConfig.backoffThreshold) {
500 if (mNumConsecutiveBadSuspends == kSleepTimeConfig.backoffThreshold) {
501 mSuspendInfo.newBackoffCount++;
502 backoffDecision = "new";
503 } else {
504 mSuspendInfo.backoffContinueCount++;
505 backoffDecision = "continue";
506 }
507
508 mSleepTime = std::min(std::chrono::round<std::chrono::milliseconds>(
509 mSleepTime * kSleepTimeConfig.sleepTimeScaleFactor),
510 kSleepTimeConfig.maxSleepTime);
511 }
512
513 mNumConsecutiveBadSuspends++;
514
515 std::string msg =
516 base::StringPrintf("bad %s %s %d %lld", backoffDecision, shortSuspend ? "short" : "failed",
517 mNumConsecutiveBadSuspends, mSleepTime.count());
518 ATRACE_INSTANT_FOR_TRACK(ATRACE_TRACK_BACKOFF, msg.c_str());
519 }
520
updateWakeLockStatOnAcquire(const std::string & name,int pid)521 void SystemSuspend::updateWakeLockStatOnAcquire(const std::string& name, int pid) {
522 // Update the stats first so that the stat time is right after
523 // suspend counter being incremented.
524 mStatsList.updateOnAcquire(name, pid);
525 mControlService->notifyWakelock(name, true);
526 }
527
updateWakeLockStatOnRelease(const std::string & name,int pid)528 void SystemSuspend::updateWakeLockStatOnRelease(const std::string& name, int pid) {
529 // Update the stats first so that the stat time is right after
530 // suspend counter being decremented.
531 mStatsList.updateOnRelease(name, pid);
532 mControlService->notifyWakelock(name, false);
533 }
534
getStatsList() const535 const WakeLockEntryList& SystemSuspend::getStatsList() const {
536 return mStatsList;
537 }
538
updateStatsNow()539 void SystemSuspend::updateStatsNow() {
540 mStatsList.updateNow();
541 }
542
getSuspendInfo(SuspendInfo * info)543 void SystemSuspend::getSuspendInfo(SuspendInfo* info) {
544 std::scoped_lock lock(mSuspendInfoLock);
545
546 *info = mSuspendInfo;
547 }
548
getWakeupList() const549 const WakeupList& SystemSuspend::getWakeupList() const {
550 return mWakeupList;
551 }
552
parseIntStat(std::string & statName,std::string & valStr)553 static int parseIntStat(std::string& statName, std::string& valStr) {
554 int statVal = -1;
555 bool parseSuccess = ParseInt(valStr, &statVal);
556 if (!parseSuccess) {
557 LOG(ERROR) << "Failed to parse " << statName << ", val: " << valStr;
558 }
559
560 return statVal;
561 }
562
parseUintStat(std::string & statName,std::string & valStr)563 static uint64_t parseUintStat(std::string& statName, std::string& valStr) {
564 uint64_t statVal = 0;
565 bool parseSuccess = ParseUint(valStr, &statVal);
566 if (!parseSuccess) {
567 LOG(ERROR) << "Failed to parse " << statName << ", val: " << valStr;
568 }
569
570 return statVal;
571 }
572
573 /**
574 * Returns suspend stats.
575 */
getSuspendStats()576 Result<SuspendStats> SystemSuspend::getSuspendStats() {
577 SuspendStats stats;
578 std::unique_ptr<DIR, decltype(&closedir)> dp(fdopendir(dup(mSuspendStatsFd.get())), &closedir);
579 if (!dp) {
580 return stats;
581 }
582
583 // rewinddir, else subsequent calls will not get any suspend_stats
584 rewinddir(dp.get());
585
586 struct dirent* de;
587
588 // Grab a wakelock before reading suspend stats, to ensure a consistent snapshot.
589 const std::string suspendInstance = std::string() + ISystemSuspend::descriptor + "/default";
590 auto suspendService = ISystemSuspend::fromBinder(
591 ndk::SpAIBinder(AServiceManager_checkService(suspendInstance.c_str())));
592
593 std::shared_ptr<IWakeLock> wl = nullptr;
594 if (suspendService) {
595 auto status =
596 suspendService->acquireWakeLock(WakeLockType::PARTIAL, "suspend_stats_lock", &wl);
597 }
598
599 while ((de = readdir(dp.get()))) {
600 std::string statName(de->d_name);
601 if ((statName == ".") || (statName == "..")) {
602 continue;
603 }
604
605 unique_fd statFd{TEMP_FAILURE_RETRY(
606 openat(mSuspendStatsFd.get(), statName.c_str(), O_CLOEXEC | O_RDONLY))};
607 if (statFd < 0) {
608 return Error() << "Failed to open " << statName;
609 }
610
611 std::string valStr;
612 if (!ReadFdToString(statFd.get(), &valStr)) {
613 return Error() << "Failed to read " << statName;
614 }
615
616 // Trim newline
617 valStr.erase(std::remove(valStr.begin(), valStr.end(), '\n'), valStr.end());
618
619 if (statName == "last_failed_dev") {
620 stats.lastFailedDev = valStr;
621 } else if (statName == "last_failed_step") {
622 stats.lastFailedStep = valStr;
623 } else if (statName == "success") {
624 stats.success = parseIntStat(statName, valStr);
625 } else if (statName == "fail") {
626 stats.fail = parseIntStat(statName, valStr);
627 } else if (statName == "failed_freeze") {
628 stats.failedFreeze = parseIntStat(statName, valStr);
629 } else if (statName == "failed_prepare") {
630 stats.failedPrepare = parseIntStat(statName, valStr);
631 } else if (statName == "failed_suspend") {
632 stats.failedSuspend = parseIntStat(statName, valStr);
633 } else if (statName == "failed_suspend_late") {
634 stats.failedSuspendLate = parseIntStat(statName, valStr);
635 } else if (statName == "failed_suspend_noirq") {
636 stats.failedSuspendNoirq = parseIntStat(statName, valStr);
637 } else if (statName == "failed_resume") {
638 stats.failedResume = parseIntStat(statName, valStr);
639 } else if (statName == "failed_resume_early") {
640 stats.failedResumeEarly = parseIntStat(statName, valStr);
641 } else if (statName == "failed_resume_noirq") {
642 stats.failedResumeNoirq = parseIntStat(statName, valStr);
643 } else if (statName == "last_failed_errno") {
644 stats.lastFailedErrno = parseIntStat(statName, valStr);
645 } else if (statName == "last_hw_sleep") {
646 stats.lastHwSleep = parseUintStat(statName, valStr);
647 } else if (statName == "total_hw_sleep") {
648 stats.totalHwSleep = parseUintStat(statName, valStr);
649 } else if (statName == "max_hw_sleep") {
650 stats.maxHwSleep = parseUintStat(statName, valStr);
651 }
652 }
653
654 return stats;
655 }
656
getSleepTime() const657 std::chrono::milliseconds SystemSuspend::getSleepTime() const {
658 return mSleepTime;
659 }
660
661 } // namespace V1_0
662 } // namespace suspend
663 } // namespace system
664 } // namespace android
665