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 <android-base/file.h>
18 #include <android-base/logging.h>
19 #include <android-base/result.h>
20 #include <android-base/unique_fd.h>
21 #include <android/system/suspend/BnSuspendCallback.h>
22 #include <binder/IPCThreadState.h>
23 #include <binder/IServiceManager.h>
24 #include <binder/ProcessState.h>
25 #include <cutils/native_handle.h>
26 #include <ftw.h>
27 #include <gmock/gmock.h>
28 #include <gtest/gtest.h>
29 #include <hidl/HidlTransportSupport.h>
30 #include <sys/poll.h>
31 #include <sys/socket.h>
32 #include <sys/types.h>
33
34 #include <chrono>
35 #include <cmath>
36 #include <csignal>
37 #include <cstdlib>
38 #include <future>
39 #include <string>
40 #include <thread>
41
42 #include "SuspendControlService.h"
43 #include "SystemSuspend.h"
44
45 using android::sp;
46 using android::base::Result;
47 using android::base::Socketpair;
48 using android::base::unique_fd;
49 using android::base::WriteStringToFd;
50 using android::hardware::configureRpcThreadpool;
51 using android::hardware::joinRpcThreadpool;
52 using android::hardware::Return;
53 using android::hardware::Void;
54 using android::system::suspend::BnSuspendCallback;
55 using android::system::suspend::ISuspendControlService;
56 using android::system::suspend::WakeLockInfo;
57 using android::system::suspend::V1_0::getTimeNow;
58 using android::system::suspend::V1_0::ISystemSuspend;
59 using android::system::suspend::V1_0::IWakeLock;
60 using android::system::suspend::V1_0::readFd;
61 using android::system::suspend::V1_0::SuspendControlService;
62 using android::system::suspend::V1_0::SuspendStats;
63 using android::system::suspend::V1_0::SystemSuspend;
64 using android::system::suspend::V1_0::TimestampType;
65 using android::system::suspend::V1_0::WakeLockType;
66 using namespace std::chrono_literals;
67
68 namespace android {
69
70 static constexpr char kServiceName[] = "TestService";
71 static constexpr char kControlServiceName[] = "TestControlService";
72
isReadBlocked(int fd,int timeout_ms=20)73 static bool isReadBlocked(int fd, int timeout_ms = 20) {
74 struct pollfd pfd {
75 .fd = fd, .events = POLLIN,
76 };
77 return poll(&pfd, 1, timeout_ms) == 0;
78 }
79
80 class SystemSuspendTest : public ::testing::Test {
81 protected:
registerTestService()82 static void registerTestService() {
83 std::thread testService([] {
84 configureRpcThreadpool(1, true /* callerWillJoin */);
85
86 sp<SuspendControlService> suspendControl = new SuspendControlService();
87 auto controlStatus = ::android::defaultServiceManager()->addService(
88 android::String16(kControlServiceName), suspendControl);
89 if (android::OK != controlStatus) {
90 LOG(FATAL) << "Unable to register service " << kControlServiceName << controlStatus;
91 }
92
93 // Create non-HW binder threadpool for SuspendControlService.
94 sp<android::ProcessState> ps{android::ProcessState::self()};
95 ps->startThreadPool();
96
97 sp<ISystemSuspend> suspend = new SystemSuspend(
98 std::move(wakeupCountFds[1]), std::move(stateFds[1]),
99 unique_fd(-1) /*suspendStatsFd*/, 1 /* maxNativeStatsEntries */,
100 unique_fd(-1) /* kernelWakelockStatsFd */, 0ms /* baseSleepTime */, suspendControl);
101 status_t status = suspend->registerAsService(kServiceName);
102 if (android::OK != status) {
103 LOG(FATAL) << "Unable to register service: " << status;
104 }
105
106 joinRpcThreadpool();
107 });
108 testService.detach();
109 }
110
SetUpTestSuite()111 static void SetUpTestSuite() {
112 Socketpair(SOCK_STREAM, &wakeupCountFds[0], &wakeupCountFds[1]);
113 Socketpair(SOCK_STREAM, &stateFds[0], &stateFds[1]);
114
115 registerTestService();
116 ::android::hardware::details::waitForHwService(ISystemSuspend::descriptor, kServiceName);
117 sp<ISystemSuspend> suspendService = ISystemSuspend::getService(kServiceName);
118 ASSERT_NE(suspendService, nullptr) << "failed to get suspend service";
119
120 sp<IBinder> control =
121 android::defaultServiceManager()->getService(android::String16(kControlServiceName));
122 ASSERT_NE(control, nullptr) << "failed to get the suspend control service";
123 sp<ISuspendControlService> controlService = interface_cast<ISuspendControlService>(control);
124
125 // Start auto-suspend.
126 bool enabled = false;
127 controlService->enableAutosuspend(&enabled);
128 ASSERT_EQ(enabled, true) << "failed to start autosuspend";
129 }
130
131 public:
SetUp()132 virtual void SetUp() override {
133 ::android::hardware::details::waitForHwService(ISystemSuspend::descriptor, kServiceName);
134 suspendService = ISystemSuspend::getService(kServiceName);
135 ASSERT_NE(suspendService, nullptr) << "failed to get suspend service";
136
137 sp<IBinder> control =
138 android::defaultServiceManager()->getService(android::String16(kControlServiceName));
139 ASSERT_NE(control, nullptr) << "failed to get the suspend control service";
140 controlService = interface_cast<ISuspendControlService>(control);
141
142 wakeupCountFd = wakeupCountFds[0];
143 stateFd = stateFds[0];
144
145 // SystemSuspend HAL should not have written back to wakeupCountFd or stateFd yet.
146 ASSERT_TRUE(isReadBlocked(wakeupCountFd));
147 ASSERT_TRUE(isReadBlocked(stateFd));
148 }
149
TearDown()150 virtual void TearDown() override {
151 if (!isReadBlocked(wakeupCountFd)) readFd(wakeupCountFd);
152 if (!isReadBlocked(stateFd)) readFd(stateFd).empty();
153 ASSERT_TRUE(isReadBlocked(wakeupCountFd));
154 ASSERT_TRUE(isReadBlocked(stateFd));
155 }
156
unblockSystemSuspendFromWakeupCount()157 void unblockSystemSuspendFromWakeupCount() {
158 std::string wakeupCount = std::to_string(rand());
159 ASSERT_TRUE(WriteStringToFd(wakeupCount, wakeupCountFd));
160 }
161
isSystemSuspendBlocked(int timeout_ms=20)162 bool isSystemSuspendBlocked(int timeout_ms = 20) { return isReadBlocked(stateFd, timeout_ms); }
163
acquireWakeLock(const std::string & name="TestLock")164 sp<IWakeLock> acquireWakeLock(const std::string& name = "TestLock") {
165 return suspendService->acquireWakeLock(WakeLockType::PARTIAL, name);
166 }
167
getActiveWakeLockCount()168 size_t getActiveWakeLockCount() {
169 std::vector<WakeLockInfo> wlStats;
170 controlService->getWakeLockStats(&wlStats);
171 return count_if(wlStats.begin(), wlStats.end(), [](auto entry) { return entry.isActive; });
172 }
173
checkLoop(int numIter)174 void checkLoop(int numIter) {
175 for (int i = 0; i < numIter; i++) {
176 // Mock value for /sys/power/wakeup_count.
177 std::string wakeupCount = std::to_string(rand());
178 ASSERT_TRUE(WriteStringToFd(wakeupCount, wakeupCountFd));
179 ASSERT_EQ(readFd(wakeupCountFd), wakeupCount)
180 << "wakeup count value written by SystemSuspend is not equal to value given to it";
181 ASSERT_EQ(readFd(stateFd), "mem")
182 << "SystemSuspend failed to write correct sleep state.";
183 }
184 }
185 sp<ISystemSuspend> suspendService;
186 sp<ISuspendControlService> controlService;
187 static unique_fd wakeupCountFds[2];
188 static unique_fd stateFds[2];
189 static int wakeupCountFd;
190 static int stateFd;
191 };
192
193 // SystemSuspendTest test suite resources
194 unique_fd SystemSuspendTest::wakeupCountFds[2];
195 unique_fd SystemSuspendTest::stateFds[2];
196 int SystemSuspendTest::wakeupCountFd;
197 int SystemSuspendTest::stateFd;
198
199 // Tests that autosuspend thread can only be enabled once.
TEST_F(SystemSuspendTest,OnlyOneEnableAutosuspend)200 TEST_F(SystemSuspendTest, OnlyOneEnableAutosuspend) {
201 bool enabled = false;
202 controlService->enableAutosuspend(&enabled);
203 ASSERT_EQ(enabled, false);
204 }
205
TEST_F(SystemSuspendTest,AutosuspendLoop)206 TEST_F(SystemSuspendTest, AutosuspendLoop) {
207 checkLoop(5);
208 }
209
210 // Tests that upon WakeLock destruction SystemSuspend HAL is unblocked.
TEST_F(SystemSuspendTest,WakeLockDestructor)211 TEST_F(SystemSuspendTest, WakeLockDestructor) {
212 {
213 sp<IWakeLock> wl = acquireWakeLock();
214 ASSERT_NE(wl, nullptr);
215 unblockSystemSuspendFromWakeupCount();
216 ASSERT_TRUE(isSystemSuspendBlocked());
217 }
218 ASSERT_FALSE(isSystemSuspendBlocked());
219 }
220
221 // Tests that upon WakeLock::release() SystemSuspend HAL is unblocked.
TEST_F(SystemSuspendTest,WakeLockRelease)222 TEST_F(SystemSuspendTest, WakeLockRelease) {
223 sp<IWakeLock> wl = acquireWakeLock();
224 ASSERT_NE(wl, nullptr);
225 unblockSystemSuspendFromWakeupCount();
226 ASSERT_TRUE(isSystemSuspendBlocked());
227 wl->release();
228 ASSERT_FALSE(isSystemSuspendBlocked());
229 }
230
231 // Tests that multiple WakeLocks correctly block SystemSuspend HAL.
TEST_F(SystemSuspendTest,MultipleWakeLocks)232 TEST_F(SystemSuspendTest, MultipleWakeLocks) {
233 {
234 sp<IWakeLock> wl1 = acquireWakeLock();
235 ASSERT_NE(wl1, nullptr);
236 ASSERT_TRUE(isSystemSuspendBlocked());
237 unblockSystemSuspendFromWakeupCount();
238 {
239 sp<IWakeLock> wl2 = acquireWakeLock();
240 ASSERT_NE(wl2, nullptr);
241 ASSERT_TRUE(isSystemSuspendBlocked());
242 }
243 ASSERT_TRUE(isSystemSuspendBlocked());
244 }
245 ASSERT_FALSE(isSystemSuspendBlocked());
246 }
247
248 // Tests that upon thread deallocation WakeLock is destructed and SystemSuspend HAL is unblocked.
TEST_F(SystemSuspendTest,ThreadCleanup)249 TEST_F(SystemSuspendTest, ThreadCleanup) {
250 std::thread clientThread([this] {
251 sp<IWakeLock> wl = acquireWakeLock();
252 ASSERT_NE(wl, nullptr);
253 unblockSystemSuspendFromWakeupCount();
254 ASSERT_TRUE(isSystemSuspendBlocked());
255 });
256 clientThread.join();
257 ASSERT_FALSE(isSystemSuspendBlocked());
258 }
259
260 // Test that binder driver correctly deallocates acquired WakeLocks, even if the client processs
261 // is terminated without ability to do clean up.
TEST_F(SystemSuspendTest,CleanupOnAbort)262 TEST_F(SystemSuspendTest, CleanupOnAbort) {
263 ASSERT_EXIT(
264 {
265 sp<IWakeLock> wl = acquireWakeLock();
266 ASSERT_NE(wl, nullptr);
267 std::abort();
268 },
269 ::testing::KilledBySignal(SIGABRT), "");
270 ASSERT_TRUE(isSystemSuspendBlocked());
271 unblockSystemSuspendFromWakeupCount();
272 // Timing of the wake lock clean-up after process death is scheduler-dependent.
273 // Increase the timeout to avoid flakes.
274 ASSERT_FALSE(isSystemSuspendBlocked(200));
275 }
276
277 // Stress test acquiring/releasing WakeLocks.
TEST_F(SystemSuspendTest,WakeLockStressTest)278 TEST_F(SystemSuspendTest, WakeLockStressTest) {
279 // numThreads threads will acquire/release numLocks locks each.
280 constexpr int numThreads = 10;
281 constexpr int numLocks = 10000;
282 std::thread tds[numThreads];
283
284 for (int i = 0; i < numThreads; i++) {
285 tds[i] = std::thread([this] {
286 for (int j = 0; j < numLocks; j++) {
287 sp<IWakeLock> wl1 = acquireWakeLock();
288 sp<IWakeLock> wl2 = acquireWakeLock();
289 wl2->release();
290 }
291 });
292 }
293 for (int i = 0; i < numThreads; i++) {
294 tds[i].join();
295 }
296 ASSERT_EQ(getActiveWakeLockCount(), 0);
297 }
298
299 // Callbacks are passed around as sp<>. However, mock expectations are verified when mock objects
300 // are destroyed, i.e. the test needs to control lifetime of the mock object.
301 // MockCallbackImpl can be destroyed independently of its wrapper MockCallback which is passed to
302 // SystemSuspend.
303 struct MockCallbackImpl {
304 MOCK_METHOD1(notifyWakeup, binder::Status(bool));
305 };
306
307 class MockCallback : public BnSuspendCallback {
308 public:
MockCallback(MockCallbackImpl * impl)309 MockCallback(MockCallbackImpl* impl) : mImpl(impl), mDisabled(false) {}
notifyWakeup(bool x)310 binder::Status notifyWakeup(bool x) {
311 return mDisabled ? binder::Status::ok() : mImpl->notifyWakeup(x);
312 }
313 // In case we pull the rug from under MockCallback, but SystemSuspend still has an sp<> to the
314 // object.
disable()315 void disable() { mDisabled = true; }
316
317 private:
318 MockCallbackImpl* mImpl;
319 bool mDisabled;
320 };
321
322 // Tests that nullptr can't be registered as callbacks.
TEST_F(SystemSuspendTest,RegisterInvalidCallback)323 TEST_F(SystemSuspendTest, RegisterInvalidCallback) {
324 bool retval = false;
325 controlService->registerCallback(nullptr, &retval);
326 ASSERT_FALSE(retval);
327 }
328
329 // Tests that SystemSuspend HAL correctly notifies wakeup events.
TEST_F(SystemSuspendTest,CallbackNotifyWakeup)330 TEST_F(SystemSuspendTest, CallbackNotifyWakeup) {
331 constexpr int numWakeups = 5;
332 MockCallbackImpl impl;
333 // SystemSuspend should suspend numWakeup + 1 times. However, it might
334 // only be able to notify numWakeup times. The test case might have
335 // finished by the time last notification completes.
336 EXPECT_CALL(impl, notifyWakeup).Times(testing::AtLeast(numWakeups));
337 sp<MockCallback> cb = new MockCallback(&impl);
338 bool retval = false;
339 controlService->registerCallback(cb, &retval);
340 ASSERT_TRUE(retval);
341 checkLoop(numWakeups + 1);
342 cb->disable();
343 }
344
345 // Tests that SystemSuspend HAL correctly deals with a dead callback.
TEST_F(SystemSuspendTest,DeadCallback)346 TEST_F(SystemSuspendTest, DeadCallback) {
347 ASSERT_EXIT(
348 {
349 sp<MockCallback> cb = new MockCallback(nullptr);
350 bool retval = false;
351 controlService->registerCallback(cb, &retval);
352 ASSERT_TRUE(retval);
353 std::exit(0);
354 },
355 ::testing::ExitedWithCode(0), "");
356
357 // Dead process callback must still be dealt with either by unregistering it
358 // or checking isOk() on every call.
359 checkLoop(3);
360 }
361
362 // Callback that registers another callback.
363 class CbRegisteringCb : public BnSuspendCallback {
364 public:
CbRegisteringCb(sp<ISuspendControlService> controlService)365 CbRegisteringCb(sp<ISuspendControlService> controlService) : mControlService(controlService) {}
notifyWakeup(bool x)366 binder::Status notifyWakeup(bool x) {
367 sp<MockCallback> cb = new MockCallback(nullptr);
368 cb->disable();
369 bool retval = false;
370 mControlService->registerCallback(cb, &retval);
371 return binder::Status::ok();
372 }
373
374 private:
375 sp<ISuspendControlService> mControlService;
376 };
377
378 // Tests that callback registering another callback doesn't result in a deadlock.
TEST_F(SystemSuspendTest,CallbackRegisterCallbackNoDeadlock)379 TEST_F(SystemSuspendTest, CallbackRegisterCallbackNoDeadlock) {
380 sp<CbRegisteringCb> cb = new CbRegisteringCb(controlService);
381 bool retval = false;
382 controlService->registerCallback(cb, &retval);
383 ASSERT_TRUE(retval);
384 checkLoop(3);
385 }
386
387 class SystemSuspendSameThreadTest : public ::testing::Test {
388 public:
acquireWakeLock(const std::string & name="TestLock")389 sp<IWakeLock> acquireWakeLock(const std::string& name = "TestLock") {
390 return suspendService->acquireWakeLock(WakeLockType::PARTIAL, name);
391 }
392
393 /**
394 * Returns true if wake lock is found else false.
395 */
findWakeLockInfoByName(const std::vector<WakeLockInfo> & wlStats,const std::string & name,WakeLockInfo * info)396 bool findWakeLockInfoByName(const std::vector<WakeLockInfo>& wlStats, const std::string& name,
397 WakeLockInfo* info) {
398 auto it = std::find_if(wlStats.begin(), wlStats.end(),
399 [&name](const auto& x) { return x.name == name; });
400 if (it != wlStats.end()) {
401 *info = *it;
402 return true;
403 }
404 return false;
405 }
406
writeStatToFile(int statDirFd,const std::string & fileName,const std::string & stat)407 bool writeStatToFile(int statDirFd, const std::string& fileName, const std::string& stat) {
408 unique_fd statFd{TEMP_FAILURE_RETRY(
409 openat(statDirFd, fileName.c_str(), O_CREAT | O_CLOEXEC | O_RDWR, S_IRWXU))};
410 if (statFd < 0) {
411 PLOG(ERROR) << "SystemSuspend: Error opening " << fileName;
412 return false;
413 }
414
415 if (!WriteStringToFd(stat, statFd.get())) {
416 PLOG(ERROR) << "SystemSuspend: Error writing stat to " << fileName;
417 return false;
418 }
419
420 return true;
421 }
422
writeStatToFile(int statDirFd,const std::string & fileName,int64_t stat)423 bool writeStatToFile(int statDirFd, const std::string& fileName, int64_t stat) {
424 return writeStatToFile(statDirFd, fileName, std::to_string(stat));
425 }
426
427 /**
428 * Creates a kernel wakelock directory and stats files.
429 * Returns true on success else false.
430 */
addKernelWakelock(const std::string & name,int64_t activeCount=42,int64_t activeTime=42,int64_t eventCount=42,int64_t expireCount=42,int64_t lastChange=42,int64_t maxTime=42,int64_t preventSuspendTime=42,int64_t totalTime=42,int64_t wakeupCount=42)431 bool addKernelWakelock(const std::string& name, int64_t activeCount = 42,
432 int64_t activeTime = 42, int64_t eventCount = 42,
433 int64_t expireCount = 42, int64_t lastChange = 42, int64_t maxTime = 42,
434 int64_t preventSuspendTime = 42, int64_t totalTime = 42,
435 int64_t wakeupCount = 42) {
436 static int id = 0;
437 std::string kwlId = "wakeup" + std::to_string(id++);
438
439 if ((mkdirat(kernelWakelockStatsFd, kwlId.c_str(), S_IRWXU)) < 0) {
440 PLOG(ERROR) << "SystemSuspend: Error creating directory for " << kwlId;
441 return false;
442 }
443
444 unique_fd kernelWakelockFd{TEMP_FAILURE_RETRY(
445 openat(kernelWakelockStatsFd, kwlId.c_str(), O_DIRECTORY | O_CLOEXEC | O_RDONLY))};
446 if (kernelWakelockFd < 0) {
447 PLOG(ERROR) << "SystemSuspend: Error opening " << kwlId;
448 return false;
449 }
450
451 int fd = kernelWakelockFd.get();
452
453 return writeStatToFile(fd, "name", name) &&
454 writeStatToFile(fd, "active_count", activeCount) &&
455 writeStatToFile(fd, "active_time_ms", activeTime) &&
456 writeStatToFile(fd, "event_count", eventCount) &&
457 writeStatToFile(fd, "expire_count", expireCount) &&
458 writeStatToFile(fd, "last_change_ms", lastChange) &&
459 writeStatToFile(fd, "max_time_ms", maxTime) &&
460 writeStatToFile(fd, "prevent_suspend_time_ms", preventSuspendTime) &&
461 writeStatToFile(fd, "total_time_ms", totalTime) &&
462 writeStatToFile(fd, "wakeup_count", wakeupCount);
463 }
464
465 /**
466 * Adds Suspend stats files to suspendStatDir.
467 * Returns true on success else false.
468 */
addSuspendStats(int64_t success=42,int64_t fail=42,int64_t failedFreeze=42,int64_t failedPrepare=42,int64_t failedSuspend=42,int64_t failedSuspendLate=42,int64_t failedSuspendNoirq=42,int64_t failedResume=42,int64_t failedResumeEarly=42,int64_t failedResumeNoirq=42,const std::string & lastFailedDev="fakeDev",int64_t lastFailedErrno=42,const std::string & lastFailedStep="fakeStep")469 bool addSuspendStats(int64_t success = 42, int64_t fail = 42, int64_t failedFreeze = 42,
470 int64_t failedPrepare = 42, int64_t failedSuspend = 42,
471 int64_t failedSuspendLate = 42, int64_t failedSuspendNoirq = 42,
472 int64_t failedResume = 42, int64_t failedResumeEarly = 42,
473 int64_t failedResumeNoirq = 42,
474 const std::string& lastFailedDev = "fakeDev", int64_t lastFailedErrno = 42,
475 const std::string& lastFailedStep = "fakeStep") {
476 int fd = suspendStatsFd.get();
477
478 return writeStatToFile(fd, "success", success) && writeStatToFile(fd, "fail", fail) &&
479 writeStatToFile(fd, "failed_freeze", failedFreeze) &&
480 writeStatToFile(fd, "failed_prepare", failedPrepare) &&
481 writeStatToFile(fd, "failed_suspend", failedSuspend) &&
482 writeStatToFile(fd, "failed_suspend_late", failedSuspendLate) &&
483 writeStatToFile(fd, "failed_suspend_noirq", failedSuspendNoirq) &&
484 writeStatToFile(fd, "failed_resume", failedResume) &&
485 writeStatToFile(fd, "failed_resume_early", failedResumeEarly) &&
486 writeStatToFile(fd, "failed_resume_noirq", failedResumeNoirq) &&
487 writeStatToFile(fd, "last_failed_dev", lastFailedDev) &&
488 writeStatToFile(fd, "last_failed_errno", lastFailedErrno) &&
489 writeStatToFile(fd, "last_failed_step", lastFailedStep);
490 }
491
removeDirectoryEntry(const std::string & path)492 bool removeDirectoryEntry(const std::string& path) {
493 auto callback = [](const char* child, const struct stat*, int file_type,
494 struct FTW*) -> int {
495 switch (file_type) {
496 case FTW_D:
497 case FTW_DP:
498 case FTW_DNR:
499 if (rmdir(child) == -1) {
500 PLOG(ERROR) << "rmdir " << child;
501 }
502 break;
503 case FTW_NS:
504 default:
505 if (rmdir(child) != -1) break;
506 // FALLTHRU (for gcc, lint, pcc, etc; and following for clang)
507 FALLTHROUGH_INTENDED;
508 case FTW_F:
509 case FTW_SL:
510 case FTW_SLN:
511 if (unlink(child) == -1) {
512 PLOG(ERROR) << "unlink " << child;
513 }
514 break;
515 }
516 return 0;
517 };
518 return nftw(path.c_str(), callback, 128, FTW_DEPTH | FTW_MOUNT | FTW_PHYS) == 0;
519 }
520
521 /**
522 * Removes all entries from directory.
523 * Returns true on success else false.
524 */
clearDirectory(const std::string & dirPath)525 bool clearDirectory(const std::string& dirPath) {
526 std::unique_ptr<DIR, decltype(&closedir)> dp(opendir(dirPath.c_str()), &closedir);
527 if (!dp) {
528 return false;
529 }
530
531 rewinddir(dp.get());
532 struct dirent* de;
533 while ((de = readdir(dp.get()))) {
534 std::string name(de->d_name);
535 if ((name == ".") || (name == "..")) {
536 continue;
537 }
538 if (!removeDirectoryEntry(dirPath + "/" + name)) {
539 PLOG(ERROR) << "SystemSuspend: Failed to remove " << name;
540 return false;
541 }
542 }
543
544 return true;
545 }
546
547 /**
548 * Returns wakelock stats.
549 */
getWakelockStats()550 std::vector<WakeLockInfo> getWakelockStats() {
551 std::vector<WakeLockInfo> wlStats;
552 controlService->getWakeLockStats(&wlStats);
553 return wlStats;
554 }
555
556 /**
557 * Returns suspend stats.
558 */
getSuspendStats()559 Result<SuspendStats> getSuspendStats() {
560 return reinterpret_cast<SystemSuspend*>(suspendService.get())->getSuspendStats();
561 }
562
SetUp()563 virtual void SetUp() override {
564 kernelWakelockStatsFd = unique_fd(TEMP_FAILURE_RETRY(
565 open(kernelWakelockStatsDir.path, O_DIRECTORY | O_CLOEXEC | O_RDONLY)));
566 if (kernelWakelockStatsFd < 0) {
567 PLOG(FATAL) << "SystemSuspend: Failed to open kernel wakelock stats directory";
568 }
569
570 suspendStatsFd = unique_fd(
571 TEMP_FAILURE_RETRY(open(suspendStatsDir.path, O_DIRECTORY | O_CLOEXEC | O_RDONLY)));
572 if (suspendStatsFd < 0) {
573 PLOG(FATAL) << "SystemSuspend: Failed to open suspend_stats directory";
574 }
575
576 // Set up same thread suspend services
577 sp<SuspendControlService> suspendControl = new SuspendControlService();
578 controlService = suspendControl;
579 suspendService = new SystemSuspend(
580 unique_fd(-1) /* wakeupCountFd */, unique_fd(-1) /* stateFd */,
581 unique_fd(dup(suspendStatsFd)), 1 /* maxNativeStatsEntries */,
582 unique_fd(dup(kernelWakelockStatsFd.get())), 0ms /* baseSleepTime */, suspendControl);
583 }
584
TearDown()585 virtual void TearDown() override {
586 ASSERT_TRUE(clearDirectory(kernelWakelockStatsDir.path));
587 ASSERT_TRUE(clearDirectory(suspendStatsDir.path));
588 }
589
590 sp<ISystemSuspend> suspendService;
591 sp<ISuspendControlService> controlService;
592 unique_fd kernelWakelockStatsFd;
593 unique_fd suspendStatsFd;
594 TemporaryDir kernelWakelockStatsDir;
595 TemporaryDir suspendStatsDir;
596 };
597
598 // Test that getWakeLockStats has correct information about Native WakeLocks.
TEST_F(SystemSuspendSameThreadTest,GetNativeWakeLockStats)599 TEST_F(SystemSuspendSameThreadTest, GetNativeWakeLockStats) {
600 std::string fakeWlName = "FakeLock";
601 {
602 sp<IWakeLock> fakeLock = acquireWakeLock(fakeWlName);
603 std::vector<WakeLockInfo> wlStats = getWakelockStats();
604 ASSERT_EQ(wlStats.size(), 1);
605
606 WakeLockInfo nwlInfo;
607 ASSERT_TRUE(findWakeLockInfoByName(wlStats, fakeWlName, &nwlInfo));
608 ASSERT_EQ(nwlInfo.name, fakeWlName);
609 ASSERT_EQ(nwlInfo.activeCount, 1);
610 ASSERT_EQ(nwlInfo.isActive, true);
611 ASSERT_FALSE(nwlInfo.isKernelWakelock);
612
613 ASSERT_EQ(nwlInfo.pid, getpid());
614
615 ASSERT_EQ(nwlInfo.eventCount, 0);
616 ASSERT_EQ(nwlInfo.expireCount, 0);
617 ASSERT_EQ(nwlInfo.preventSuspendTime, 0);
618 ASSERT_EQ(nwlInfo.wakeupCount, 0);
619
620 // We sleep so that the wake lock stats entry get updated with a different timestamp.
621 std::this_thread::sleep_for(1s);
622 }
623 std::vector<WakeLockInfo> wlStats = getWakelockStats();
624 ASSERT_EQ(wlStats.size(), 1);
625
626 WakeLockInfo nwlInfo;
627 ASSERT_TRUE(findWakeLockInfoByName(wlStats, fakeWlName, &nwlInfo));
628 ASSERT_EQ(nwlInfo.name, fakeWlName);
629 ASSERT_EQ(nwlInfo.activeCount, 1);
630 ASSERT_GE(nwlInfo.maxTime, 1000);
631 ASSERT_GE(nwlInfo.totalTime, 1000);
632 ASSERT_EQ(nwlInfo.isActive, false);
633 ASSERT_EQ(nwlInfo.activeTime, 0); // No longer active
634 ASSERT_FALSE(nwlInfo.isKernelWakelock);
635
636 ASSERT_EQ(nwlInfo.pid, getpid());
637
638 ASSERT_EQ(nwlInfo.eventCount, 0);
639 ASSERT_EQ(nwlInfo.expireCount, 0);
640 ASSERT_EQ(nwlInfo.preventSuspendTime, 0);
641 ASSERT_EQ(nwlInfo.wakeupCount, 0);
642 }
643
644 // Test that getWakeLockStats has correct information about Kernel WakeLocks.
TEST_F(SystemSuspendSameThreadTest,GetKernelWakeLockStats)645 TEST_F(SystemSuspendSameThreadTest, GetKernelWakeLockStats) {
646 std::string fakeKwlName1 = "fakeKwl1";
647 std::string fakeKwlName2 = "fakeKwl2";
648 addKernelWakelock(fakeKwlName1);
649 addKernelWakelock(fakeKwlName2, 10 /* activeCount */);
650
651 std::vector<WakeLockInfo> wlStats = getWakelockStats();
652
653 ASSERT_EQ(wlStats.size(), 2);
654
655 WakeLockInfo kwlInfo1;
656 ASSERT_TRUE(findWakeLockInfoByName(wlStats, fakeKwlName1, &kwlInfo1));
657 ASSERT_EQ(kwlInfo1.name, fakeKwlName1);
658 ASSERT_EQ(kwlInfo1.activeCount, 42);
659 ASSERT_EQ(kwlInfo1.lastChange, 42);
660 ASSERT_EQ(kwlInfo1.maxTime, 42);
661 ASSERT_EQ(kwlInfo1.totalTime, 42);
662 ASSERT_EQ(kwlInfo1.isActive, true);
663 ASSERT_EQ(kwlInfo1.activeTime, 42);
664 ASSERT_TRUE(kwlInfo1.isKernelWakelock);
665
666 ASSERT_EQ(kwlInfo1.pid, -1);
667
668 ASSERT_EQ(kwlInfo1.eventCount, 42);
669 ASSERT_EQ(kwlInfo1.expireCount, 42);
670 ASSERT_EQ(kwlInfo1.preventSuspendTime, 42);
671 ASSERT_EQ(kwlInfo1.wakeupCount, 42);
672
673 WakeLockInfo kwlInfo2;
674 ASSERT_TRUE(findWakeLockInfoByName(wlStats, fakeKwlName2, &kwlInfo2));
675 ASSERT_EQ(kwlInfo2.name, fakeKwlName2);
676 ASSERT_EQ(kwlInfo2.activeCount, 10);
677 ASSERT_EQ(kwlInfo2.lastChange, 42);
678 ASSERT_EQ(kwlInfo2.maxTime, 42);
679 ASSERT_EQ(kwlInfo2.totalTime, 42);
680 ASSERT_EQ(kwlInfo2.isActive, true);
681 ASSERT_EQ(kwlInfo2.activeTime, 42);
682 ASSERT_TRUE(kwlInfo2.isKernelWakelock);
683
684 ASSERT_EQ(kwlInfo2.pid, -1);
685
686 ASSERT_EQ(kwlInfo2.eventCount, 42);
687 ASSERT_EQ(kwlInfo2.expireCount, 42);
688 ASSERT_EQ(kwlInfo2.preventSuspendTime, 42);
689 ASSERT_EQ(kwlInfo2.wakeupCount, 42);
690 }
691
692 // Test that getWakeLockStats has correct information about Native AND Kernel WakeLocks.
TEST_F(SystemSuspendSameThreadTest,GetNativeAndKernelWakeLockStats)693 TEST_F(SystemSuspendSameThreadTest, GetNativeAndKernelWakeLockStats) {
694 std::string fakeNwlName = "fakeNwl";
695 std::string fakeKwlName = "fakeKwl";
696
697 addKernelWakelock(fakeKwlName);
698
699 {
700 sp<IWakeLock> fakeLock = acquireWakeLock(fakeNwlName);
701 std::vector<WakeLockInfo> wlStats = getWakelockStats();
702 ASSERT_EQ(wlStats.size(), 2);
703
704 // Native Wakelock Stats
705 WakeLockInfo nwlInfo;
706 ASSERT_TRUE(findWakeLockInfoByName(wlStats, fakeNwlName, &nwlInfo));
707 ASSERT_EQ(nwlInfo.name, fakeNwlName);
708 ASSERT_EQ(nwlInfo.activeCount, 1);
709 ASSERT_EQ(nwlInfo.isActive, true);
710 ASSERT_FALSE(nwlInfo.isKernelWakelock);
711
712 ASSERT_EQ(nwlInfo.pid, getpid());
713
714 ASSERT_EQ(nwlInfo.eventCount, 0);
715 ASSERT_EQ(nwlInfo.expireCount, 0);
716 ASSERT_EQ(nwlInfo.preventSuspendTime, 0);
717 ASSERT_EQ(nwlInfo.wakeupCount, 0);
718
719 // Kernel Wakelock Stats
720 WakeLockInfo kwlInfo;
721 ASSERT_TRUE(findWakeLockInfoByName(wlStats, fakeKwlName, &kwlInfo));
722 ASSERT_EQ(kwlInfo.name, fakeKwlName);
723 ASSERT_EQ(kwlInfo.activeCount, 42);
724 ASSERT_EQ(kwlInfo.lastChange, 42);
725 ASSERT_EQ(kwlInfo.maxTime, 42);
726 ASSERT_EQ(kwlInfo.totalTime, 42);
727 ASSERT_EQ(kwlInfo.isActive, true);
728 ASSERT_EQ(kwlInfo.activeTime, 42);
729 ASSERT_TRUE(kwlInfo.isKernelWakelock);
730
731 ASSERT_EQ(kwlInfo.pid, -1);
732
733 ASSERT_EQ(kwlInfo.eventCount, 42);
734 ASSERT_EQ(kwlInfo.expireCount, 42);
735 ASSERT_EQ(kwlInfo.preventSuspendTime, 42);
736 ASSERT_EQ(kwlInfo.wakeupCount, 42);
737
738 // We sleep so that the wake lock stats entry get updated with a different timestamp.
739 std::this_thread::sleep_for(1s);
740 }
741 std::vector<WakeLockInfo> wlStats = getWakelockStats();
742 ASSERT_EQ(wlStats.size(), 2);
743
744 // Native Wakelock Stats
745 WakeLockInfo nwlInfo;
746 ASSERT_TRUE(findWakeLockInfoByName(wlStats, fakeNwlName, &nwlInfo));
747 ASSERT_EQ(nwlInfo.name, fakeNwlName);
748 ASSERT_EQ(nwlInfo.activeCount, 1);
749 ASSERT_GE(nwlInfo.maxTime, 1000);
750 ASSERT_GE(nwlInfo.totalTime, 1000);
751 ASSERT_EQ(nwlInfo.isActive, false);
752 ASSERT_EQ(nwlInfo.activeTime, 0); // No longer active
753 ASSERT_FALSE(nwlInfo.isKernelWakelock);
754
755 ASSERT_EQ(nwlInfo.pid, getpid());
756
757 ASSERT_EQ(nwlInfo.eventCount, 0);
758 ASSERT_EQ(nwlInfo.expireCount, 0);
759 ASSERT_EQ(nwlInfo.preventSuspendTime, 0);
760 ASSERT_EQ(nwlInfo.wakeupCount, 0);
761
762 // Kernel Wakelock Stats (No changes expected here)
763 WakeLockInfo kwlInfo;
764 ASSERT_TRUE(findWakeLockInfoByName(wlStats, fakeKwlName, &kwlInfo));
765 ASSERT_EQ(kwlInfo.name, fakeKwlName);
766 ASSERT_EQ(kwlInfo.activeCount, 42);
767 ASSERT_EQ(kwlInfo.lastChange, 42);
768 ASSERT_EQ(kwlInfo.maxTime, 42);
769 ASSERT_EQ(kwlInfo.totalTime, 42);
770 ASSERT_EQ(kwlInfo.isActive, true);
771 ASSERT_EQ(kwlInfo.activeTime, 42);
772 ASSERT_TRUE(kwlInfo.isKernelWakelock);
773
774 ASSERT_EQ(kwlInfo.pid, -1);
775
776 ASSERT_EQ(kwlInfo.eventCount, 42);
777 ASSERT_EQ(kwlInfo.expireCount, 42);
778 ASSERT_EQ(kwlInfo.preventSuspendTime, 42);
779 ASSERT_EQ(kwlInfo.wakeupCount, 42);
780 }
781
782 // Test that the least recently used native wake lock stats entry is evicted after a given
783 // threshold.
TEST_F(SystemSuspendSameThreadTest,NativeWakeLockStatsLruEviction)784 TEST_F(SystemSuspendSameThreadTest, NativeWakeLockStatsLruEviction) {
785 std::string fakeWlName1 = "FakeLock1";
786 std::string fakeWlName2 = "FakeLock2";
787
788 acquireWakeLock(fakeWlName1);
789 acquireWakeLock(fakeWlName2);
790
791 std::vector<WakeLockInfo> wlStats = getWakelockStats();
792
793 // Max number of native stats entries was set to 1 in SystemSuspend constructor.
794 ASSERT_EQ(wlStats.size(), 1);
795 ASSERT_EQ(wlStats.begin()->name, fakeWlName2);
796
797 WakeLockInfo wlInfo;
798 ASSERT_TRUE(findWakeLockInfoByName(wlStats, fakeWlName2, &wlInfo));
799 ASSERT_FALSE(findWakeLockInfoByName(wlStats, fakeWlName1, &wlInfo)); // Evicted
800 }
801
802 // Test that GetSuspendStats has correct information.
TEST_F(SystemSuspendSameThreadTest,GetSuspendStats)803 TEST_F(SystemSuspendSameThreadTest, GetSuspendStats) {
804 addSuspendStats();
805
806 Result<SuspendStats> res = getSuspendStats();
807 ASSERT_RESULT_OK(res);
808
809 SuspendStats stats = res.value();
810
811 ASSERT_EQ(stats.success, 42);
812 ASSERT_EQ(stats.fail, 42);
813 ASSERT_EQ(stats.failedFreeze, 42);
814 ASSERT_EQ(stats.failedPrepare, 42);
815 ASSERT_EQ(stats.failedSuspend, 42);
816 ASSERT_EQ(stats.failedSuspendLate, 42);
817 ASSERT_EQ(stats.failedSuspendNoirq, 42);
818 ASSERT_EQ(stats.failedResume, 42);
819 ASSERT_EQ(stats.failedResumeEarly, 42);
820 ASSERT_EQ(stats.failedResumeNoirq, 42);
821 ASSERT_EQ(stats.lastFailedDev, "fakeDev");
822 ASSERT_EQ(stats.lastFailedErrno, 42);
823 ASSERT_EQ(stats.lastFailedStep, "fakeStep");
824 }
825
826 } // namespace android
827
main(int argc,char ** argv)828 int main(int argc, char** argv) {
829 android::hardware::details::setTrebleTestingOverride(true);
830 ::testing::InitGoogleMock(&argc, argv);
831 ::testing::InitGoogleTest(&argc, argv);
832 return RUN_ALL_TESTS();
833 }
834