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