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