1 /*
2 * Copyright (C) 2019, 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 <cstdlib>
18 #include <ctime>
19 #include <iostream>
20 #include <numeric>
21 #include <string>
22 #include <thread>
23
24 #include <unistd.h>
25
26 #include <android/hardware/tests/lazy/1.1/ILazy.h>
27 #include <android/hidl/manager/1.2/IServiceManager.h>
28 #include <gtest/gtest.h>
29 #include <hidl-util/FqInstance.h>
30 #include <hidl/HidlSupport.h>
31 #include <hidl/HidlTransportSupport.h>
32 #include <hidl/HidlTransportUtils.h>
33 #include <hwbinder/IPCThreadState.h>
34
35 using ::android::FqInstance;
36 using ::android::sp;
37 using ::android::hardware::hidl_string;
38 using ::android::hardware::hidl_vec;
39 using ::android::hardware::IPCThreadState;
40 using ::android::hardware::tests::lazy::V1_1::ILazy;
41 using ::android::hidl::base::V1_0::IBase;
42 using ::android::hidl::manager::V1_2::IServiceManager;
43
44 static std::vector<FqInstance> gInstances;
45
getHal(const FqInstance & instance)46 sp<IBase> getHal(const FqInstance& instance) {
47 return ::android::hardware::details::getRawServiceInternal(instance.getFqName().string(),
48 instance.getInstance(),
49 true /*retry*/, false /*getStub*/);
50 }
51
52 class HidlLazyTest : public ::testing::Test {
53 protected:
54 sp<IServiceManager> manager;
55
SetUp()56 void SetUp() override {
57 manager = IServiceManager::getService();
58 ASSERT_NE(manager, nullptr);
59
60 for (const auto& instance : gInstances) {
61 ASSERT_FALSE(isServiceRunning(instance))
62 << "Service '" << instance.string()
63 << "' is already running. Please ensure this "
64 << "service is implemented as a lazy HAL, then kill all "
65 << "clients of this service and try again.";
66 }
67 }
68
69 static constexpr size_t SHUTDOWN_WAIT_TIME = 10;
TearDown()70 void TearDown() override {
71 std::cout << "Waiting " << SHUTDOWN_WAIT_TIME << " seconds before checking that the "
72 << "service has shut down." << std::endl;
73 IPCThreadState::self()->flushCommands();
74 sleep(SHUTDOWN_WAIT_TIME);
75 for (const auto& instance : gInstances) {
76 ASSERT_FALSE(isServiceRunning(instance))
77 << "Service failed to shutdown " << instance.string();
78 }
79 }
80
isServiceRunning(const FqInstance & instance)81 bool isServiceRunning(const FqInstance& instance) {
82 bool isRunning = false;
83 EXPECT_TRUE(manager->listByInterface(instance.getFqName().string(),
84 [&](const hidl_vec<hidl_string>& instanceNames) {
85 for (const hidl_string& name : instanceNames) {
86 if (name == instance.getInstance()) {
87 isRunning = true;
88 break;
89 }
90 }
91 })
92 .isOk());
93 return isRunning;
94 }
95 };
96
97 static constexpr size_t NUM_IMMEDIATE_GET_UNGETS = 100;
TEST_F(HidlLazyTest,GetUnget)98 TEST_F(HidlLazyTest, GetUnget) {
99 for (size_t i = 0; i < NUM_IMMEDIATE_GET_UNGETS; i++) {
100 IPCThreadState::self()->flushCommands();
101 for (const auto& instance : gInstances) {
102 sp<IBase> hal = getHal(instance);
103 ASSERT_NE(hal.get(), nullptr);
104 EXPECT_TRUE(hal->ping().isOk());
105 }
106 }
107 }
108
waitTimes(size_t numTimes,size_t maxWait)109 static std::vector<size_t> waitTimes(size_t numTimes, size_t maxWait) {
110 std::vector<size_t> times(numTimes);
111 for (size_t i = 0; i < numTimes; i++) {
112 times[i] = (size_t)(rand() % (maxWait + 1));
113 }
114 return times;
115 }
116
testWithTimes(const std::vector<size_t> & waitTimes,const FqInstance & instance)117 static void testWithTimes(const std::vector<size_t>& waitTimes, const FqInstance& instance) {
118 std::cout << "Note runtime expected from sleeps: "
119 << std::accumulate(waitTimes.begin(), waitTimes.end(), 0) << " second(s)."
120 << std::endl;
121
122 for (size_t sleepTime : waitTimes) {
123 IPCThreadState::self()->flushCommands();
124 std::cout << "Thread for " << instance.string() << " waiting " << sleepTime
125 << " while not holding HAL." << std::endl;
126 sleep(sleepTime);
127 sp<IBase> hal = getHal(instance);
128 ASSERT_NE(hal.get(), nullptr);
129 ASSERT_TRUE(hal->ping().isOk());
130 }
131 }
132
133 static constexpr size_t NUM_TIMES_GET_UNGET = 5;
134 static constexpr size_t MAX_WAITING_DURATION = 10;
135 static constexpr size_t NUM_CONCURRENT_THREADS = 5;
TEST_F(HidlLazyTest,GetWithWaitConcurrent)136 TEST_F(HidlLazyTest, GetWithWaitConcurrent) {
137 std::vector<std::vector<size_t>> threadWaitTimes(NUM_CONCURRENT_THREADS);
138
139 for (size_t i = 0; i < threadWaitTimes.size(); i++) {
140 threadWaitTimes[i] = waitTimes(NUM_TIMES_GET_UNGET, MAX_WAITING_DURATION);
141 }
142
143 std::vector<std::thread> threads(NUM_CONCURRENT_THREADS);
144 for (size_t i = 0; i < threads.size(); i++) {
145 const FqInstance& instance = gInstances[i % gInstances.size()];
146 threads[i] = std::thread(testWithTimes, threadWaitTimes[i], instance);
147 }
148
149 for (auto& thread : threads) {
150 thread.join();
151 }
152 }
153
TEST_F(HidlLazyTest,ActiveServicesCallbackTest)154 TEST_F(HidlLazyTest, ActiveServicesCallbackTest) {
155 sp<ILazy> lazy;
156
157 for (const auto& instance : gInstances) {
158 sp<IBase> hal = getHal(instance);
159 EXPECT_NE(hal, nullptr);
160 lazy = ILazy::castFrom(hal);
161 if (lazy) break;
162 }
163 if (!lazy) GTEST_SKIP() << "Services under test do not include ILazy";
164
165 ASSERT_TRUE(lazy->setCustomActiveServicesCallback().isOk());
166 }
167
main(int argc,char ** argv)168 int main(int argc, char** argv) {
169 ::testing::InitGoogleTest(&argc, argv);
170
171 srand(time(nullptr));
172
173 std::vector<std::string> fqInstances;
174
175 if (argc == 1) {
176 fqInstances.push_back("android.hardware.tests.lazy@1.0::ILazy/default1");
177 fqInstances.push_back("android.hardware.tests.lazy@1.0::ILazy/default2");
178 } else {
179 for (size_t arg = 1; arg < argc; arg++) {
180 fqInstances.push_back(argv[arg]);
181 }
182 }
183
184 for (const std::string& instance : fqInstances) {
185 FqInstance fqInstance;
186 if (!fqInstance.setTo(instance)) {
187 std::cerr << "Invalid fqinstance: " << instance << std::endl;
188 return 1;
189 }
190 gInstances.push_back(fqInstance);
191 }
192
193 return RUN_ALL_TESTS();
194 }
195