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