xref: /aosp_15_r20/hardware/libhardware_legacy/power_test.cpp (revision 79330504eb3d14022296e3b041867f86289dd52c)
1*79330504STreehugger Robot /*
2*79330504STreehugger Robot  * Copyright 2018 The Android Open Source Project
3*79330504STreehugger Robot  *
4*79330504STreehugger Robot  * Licensed under the Apache License, Version 2.0 (the "License");
5*79330504STreehugger Robot  * you may not use this file except in compliance with the License.
6*79330504STreehugger Robot  * You may obtain a copy of the License at
7*79330504STreehugger Robot  *
8*79330504STreehugger Robot  *      http://www.apache.org/licenses/LICENSE-2.0
9*79330504STreehugger Robot  *
10*79330504STreehugger Robot  * Unless required by applicable law or agreed to in writing, software
11*79330504STreehugger Robot  * distributed under the License is distributed on an "AS IS" BASIS,
12*79330504STreehugger Robot  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*79330504STreehugger Robot  * See the License for the specific language governing permissions and
14*79330504STreehugger Robot  * limitations under the License.
15*79330504STreehugger Robot  */
16*79330504STreehugger Robot 
17*79330504STreehugger Robot #include <aidl/android/system/suspend/internal/ISuspendControlServiceInternal.h>
18*79330504STreehugger Robot #include <android/binder_manager.h>
19*79330504STreehugger Robot #include <gtest/gtest.h>
20*79330504STreehugger Robot #include <hardware_legacy/power.h>
21*79330504STreehugger Robot #include <wakelock/wakelock.h>
22*79330504STreehugger Robot 
23*79330504STreehugger Robot #include <csignal>
24*79330504STreehugger Robot #include <cstdlib>
25*79330504STreehugger Robot #include <memory>
26*79330504STreehugger Robot #include <string>
27*79330504STreehugger Robot #include <thread>
28*79330504STreehugger Robot #include <vector>
29*79330504STreehugger Robot 
30*79330504STreehugger Robot using aidl::android::system::suspend::internal::ISuspendControlServiceInternal;
31*79330504STreehugger Robot using aidl::android::system::suspend::internal::WakeLockInfo;
32*79330504STreehugger Robot using namespace std::chrono_literals;
33*79330504STreehugger Robot 
34*79330504STreehugger Robot namespace android {
35*79330504STreehugger Robot 
36*79330504STreehugger Robot // Test acquiring/releasing WakeLocks concurrently with process exit.
TEST(LibpowerTest,ProcessExitTest)37*79330504STreehugger Robot TEST(LibpowerTest, ProcessExitTest) {
38*79330504STreehugger Robot     std::atexit([] {
39*79330504STreehugger Robot         // We want to give the other thread enough time trigger a failure and
40*79330504STreehugger Robot         // dump the stack traces.
41*79330504STreehugger Robot         std::this_thread::sleep_for(1s);
42*79330504STreehugger Robot     });
43*79330504STreehugger Robot 
44*79330504STreehugger Robot     ASSERT_EXIT(
45*79330504STreehugger Robot     {
46*79330504STreehugger Robot         constexpr int numThreads = 20;
47*79330504STreehugger Robot         std::vector<std::thread> tds;
48*79330504STreehugger Robot         for (int i = 0; i < numThreads; i++) {
49*79330504STreehugger Robot             tds.emplace_back([] {
50*79330504STreehugger Robot             while (true) {
51*79330504STreehugger Robot                 // We want ids to be unique.
52*79330504STreehugger Robot                 std::string id = std::to_string(rand());
53*79330504STreehugger Robot                 ASSERT_EQ(acquire_wake_lock(PARTIAL_WAKE_LOCK, id.c_str()), 0);
54*79330504STreehugger Robot                 ASSERT_EQ(release_wake_lock(id.c_str()), 0);
55*79330504STreehugger Robot             }
56*79330504STreehugger Robot         });
57*79330504STreehugger Robot         }
58*79330504STreehugger Robot         for (auto& td : tds) {
59*79330504STreehugger Robot             td.detach();
60*79330504STreehugger Robot         }
61*79330504STreehugger Robot 
62*79330504STreehugger Robot         // Give some time for the threads to actually start.
63*79330504STreehugger Robot         std::this_thread::sleep_for(100ms);
64*79330504STreehugger Robot         std::exit(0);
65*79330504STreehugger Robot     },
66*79330504STreehugger Robot     ::testing::ExitedWithCode(0), "");
67*79330504STreehugger Robot }
68*79330504STreehugger Robot 
69*79330504STreehugger Robot // Stress test acquiring/releasing WakeLocks.
TEST(LibpowerTest,WakeLockStressTest)70*79330504STreehugger Robot TEST(LibpowerTest, WakeLockStressTest) {
71*79330504STreehugger Robot     // numThreads threads will acquire/release numLocks locks each.
72*79330504STreehugger Robot     constexpr int numThreads = 20;
73*79330504STreehugger Robot     constexpr int numLocks = 1000;
74*79330504STreehugger Robot     std::vector<std::thread> tds;
75*79330504STreehugger Robot 
76*79330504STreehugger Robot     for (int i = 0; i < numThreads; i++) {
77*79330504STreehugger Robot         tds.emplace_back([i] {
78*79330504STreehugger Robot             for (int j = 0; j < numLocks; j++) {
79*79330504STreehugger Robot                 // We want ids to be unique.
80*79330504STreehugger Robot                 std::string id = std::to_string(i) + "/" + std::to_string(j);
81*79330504STreehugger Robot                 ASSERT_EQ(acquire_wake_lock(PARTIAL_WAKE_LOCK, id.c_str()), 0)
82*79330504STreehugger Robot                     << "id: " << id;
83*79330504STreehugger Robot                 ASSERT_EQ(release_wake_lock(id.c_str()), 0)
84*79330504STreehugger Robot                     << "id: " << id;;
85*79330504STreehugger Robot             }
86*79330504STreehugger Robot         });
87*79330504STreehugger Robot     }
88*79330504STreehugger Robot     for (auto& td : tds) {
89*79330504STreehugger Robot         td.join();
90*79330504STreehugger Robot     }
91*79330504STreehugger Robot }
92*79330504STreehugger Robot 
93*79330504STreehugger Robot class WakeLockTest : public ::testing::Test {
94*79330504STreehugger Robot    public:
SetUp()95*79330504STreehugger Robot     virtual void SetUp() override {
96*79330504STreehugger Robot         ndk::SpAIBinder binder(AServiceManager_waitForService("suspend_control_internal"));
97*79330504STreehugger Robot         controlService = ISuspendControlServiceInternal::fromBinder(binder);
98*79330504STreehugger Robot         ASSERT_NE(controlService, nullptr) << "failed to get the internal suspend control service";
99*79330504STreehugger Robot     }
100*79330504STreehugger Robot 
101*79330504STreehugger Robot     // Returns true iff found.
findWakeLockInfoByName(const std::string & name,WakeLockInfo * info)102*79330504STreehugger Robot     bool findWakeLockInfoByName(const std::string& name,
103*79330504STreehugger Robot                                 WakeLockInfo* info) {
104*79330504STreehugger Robot         std::vector<WakeLockInfo> wlStats;
105*79330504STreehugger Robot         controlService->getWakeLockStats(&wlStats);
106*79330504STreehugger Robot         auto it = std::find_if(wlStats.begin(), wlStats.end(),
107*79330504STreehugger Robot                                [&name](const auto& x) { return x.name == name; });
108*79330504STreehugger Robot         if (it != wlStats.end()) {
109*79330504STreehugger Robot             *info = *it;
110*79330504STreehugger Robot             return true;
111*79330504STreehugger Robot         }
112*79330504STreehugger Robot         return false;
113*79330504STreehugger Robot     }
114*79330504STreehugger Robot 
115*79330504STreehugger Robot     // All userspace wake locks are registered with system suspend.
116*79330504STreehugger Robot     std::shared_ptr<ISuspendControlServiceInternal> controlService;
117*79330504STreehugger Robot };
118*79330504STreehugger Robot 
119*79330504STreehugger Robot // Test RAII properties of WakeLock destructor.
TEST_F(WakeLockTest,WakeLockDestructor)120*79330504STreehugger Robot TEST_F(WakeLockTest, WakeLockDestructor) {
121*79330504STreehugger Robot     auto name = std::to_string(rand());
122*79330504STreehugger Robot     {
123*79330504STreehugger Robot         auto wl = android::wakelock::WakeLock::tryGet(name);
124*79330504STreehugger Robot         if (!wl.has_value()) {
125*79330504STreehugger Robot             return;
126*79330504STreehugger Robot         }
127*79330504STreehugger Robot 
128*79330504STreehugger Robot         WakeLockInfo info;
129*79330504STreehugger Robot         auto success = findWakeLockInfoByName(name, &info);
130*79330504STreehugger Robot         ASSERT_TRUE(success);
131*79330504STreehugger Robot         ASSERT_EQ(info.name, name);
132*79330504STreehugger Robot         ASSERT_EQ(info.pid, getpid());
133*79330504STreehugger Robot         ASSERT_TRUE(info.isActive);
134*79330504STreehugger Robot     }
135*79330504STreehugger Robot 
136*79330504STreehugger Robot     // Allow the system suspend service sufficient time to release the wake
137*79330504STreehugger Robot     // lock, obtain the autosuspend lock to decrement the suspend counter and
138*79330504STreehugger Robot     // update the wake lock stats.
139*79330504STreehugger Robot     std::this_thread::sleep_for(50ms);
140*79330504STreehugger Robot     WakeLockInfo info;
141*79330504STreehugger Robot     auto success = findWakeLockInfoByName(name, &info);
142*79330504STreehugger Robot     ASSERT_TRUE(success);
143*79330504STreehugger Robot     ASSERT_EQ(info.name, name);
144*79330504STreehugger Robot     ASSERT_EQ(info.pid, getpid());
145*79330504STreehugger Robot     ASSERT_FALSE(info.isActive);
146*79330504STreehugger Robot }
147*79330504STreehugger Robot 
148*79330504STreehugger Robot }  // namespace android
149