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