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