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 <sys/epoll.h>
25 #include <sys/eventfd.h>
26 #include <unistd.h>
27 
28 #include <android-base/properties.h>
29 #include <android-base/unique_fd.h>
30 #include <android/hardware/tests/lazy/1.1/ILazy.h>
31 #include <android/hardware/tests/lazy_cb/1.0/ILazyCb.h>
32 #include <android/hidl/manager/1.2/IServiceManager.h>
33 #include <cutils/native_handle.h>
34 #include <gtest/gtest.h>
35 #include <hidl-util/FqInstance.h>
36 #include <hidl/HidlSupport.h>
37 #include <hidl/HidlTransportSupport.h>
38 #include <hidl/HidlTransportUtils.h>
39 #include <hwbinder/IPCThreadState.h>
40 
41 using ::android::FqInstance;
42 using ::android::sp;
43 using ::android::base::unique_fd;
44 using ::android::hardware::hidl_handle;
45 using ::android::hardware::hidl_string;
46 using ::android::hardware::hidl_vec;
47 using ::android::hardware::IPCThreadState;
48 using ::android::hardware::Return;
49 using ::android::hardware::tests::lazy::V1_1::ILazy;
50 using ::android::hardware::tests::lazy_cb::V1_0::ILazyCb;
51 using ::android::hidl::base::V1_0::IBase;
52 using ::android::hidl::manager::V1_2::IServiceManager;
53 
54 static std::vector<FqInstance> gInstances;
55 
getHal(const FqInstance & instance)56 sp<IBase> getHal(const FqInstance& instance) {
57     return ::android::hardware::details::getRawServiceInternal(instance.getFqName().string(),
58                                                                instance.getInstance(),
59                                                                true /*retry*/, false /*getStub*/);
60 }
61 
62 class HidlLazyTestBase : public ::testing::Test {
63   protected:
64     static constexpr size_t SHUTDOWN_WAIT_TIME = 10;
65     sp<IServiceManager> manager;
66 
SetUp()67     void SetUp() override {
68         manager = IServiceManager::getService();
69         ASSERT_NE(manager, nullptr);
70         // if the services aren't installed/declared on the device, skip.
71         // if one is installed, the other(s) are also installed so skip on the
72         // first instance that isn't declared.
73         for (const auto& instance : gInstances) {
74             if (!isServiceDeclared(instance))
75                 GTEST_SKIP() << "No HIDL lazy test services on device";
76         }
77     }
78 
isServiceRunning(const FqInstance & instance)79     bool isServiceRunning(const FqInstance& instance) {
80         bool isRunning = false;
81         EXPECT_TRUE(manager->listByInterface(instance.getFqName().string(),
82                                              [&](const hidl_vec<hidl_string>& instanceNames) {
83                                                  for (const hidl_string& name : instanceNames) {
84                                                      if (name == instance.getInstance()) {
85                                                          isRunning = true;
86                                                          break;
87                                                      }
88                                                  }
89                                              })
90                             .isOk());
91         return isRunning;
92     }
isServiceDeclared(const FqInstance & instance)93     bool isServiceDeclared(const FqInstance& instance) {
94         const auto transport =
95                 manager->getTransport(instance.getFqName().string(), instance.getInstance());
96         EXPECT_TRUE(transport.isOk());
97         if (transport == IServiceManager::Transport::HWBINDER) return true;
98         return false;
99     }
100 };
101 
102 class HidlLazyTest : public HidlLazyTestBase {
103   protected:
SetUp()104     void SetUp() override {
105         HidlLazyTestBase::SetUp();
106         for (const auto& instance : gInstances) {
107             ASSERT_FALSE(isServiceRunning(instance))
108                     << "Service '" << instance.string()
109                     << "' is already running. Please ensure this "
110                     << "service is implemented as a lazy HAL, then kill all "
111                     << "clients of this service and try again.";
112         }
113     }
114 
TearDown()115     void TearDown() override {
116         std::cout << "Waiting " << SHUTDOWN_WAIT_TIME << " seconds before checking that the "
117                   << "service has shut down." << std::endl;
118         IPCThreadState::self()->flushCommands();
119         int timeout_multiplier = android::base::GetIntProperty("ro.hw_timeout_multiplier", 1);
120         sleep(SHUTDOWN_WAIT_TIME * timeout_multiplier);
121         for (const auto& instance : gInstances) {
122             ASSERT_FALSE(isServiceRunning(instance))
123                     << "Service failed to shutdown " << instance.string();
124         }
125     }
126 };
127 
128 class HidlLazyCbTest : public HidlLazyTestBase {
129   protected:
130     static constexpr size_t CALLBACK_SHUTDOWN_WAIT_TIME = 5;
131 };
132 
133 static constexpr size_t NUM_IMMEDIATE_GET_UNGETS = 100;
TEST_F(HidlLazyTest,GetUnget)134 TEST_F(HidlLazyTest, GetUnget) {
135     for (size_t i = 0; i < NUM_IMMEDIATE_GET_UNGETS; i++) {
136         IPCThreadState::self()->flushCommands();
137         for (const auto& instance : gInstances) {
138             sp<IBase> hal = getHal(instance);
139             ASSERT_NE(hal.get(), nullptr);
140             EXPECT_TRUE(hal->ping().isOk());
141         }
142     }
143 }
144 
waitTimes(size_t numTimes,size_t maxWait)145 static std::vector<size_t> waitTimes(size_t numTimes, size_t maxWait) {
146     std::vector<size_t> times(numTimes);
147     for (size_t i = 0; i < numTimes; i++) {
148         times[i] = (size_t)(rand() % (maxWait + 1));
149     }
150     return times;
151 }
152 
testWithTimes(const std::vector<size_t> & waitTimes,const FqInstance & instance)153 static void testWithTimes(const std::vector<size_t>& waitTimes, const FqInstance& instance) {
154     std::cout << "Note runtime expected from sleeps: "
155               << std::accumulate(waitTimes.begin(), waitTimes.end(), 0) << " second(s)."
156               << std::endl;
157 
158     for (size_t sleepTime : waitTimes) {
159         IPCThreadState::self()->flushCommands();
160         std::cout << "Thread for " << instance.string() << " waiting " << sleepTime
161                   << " while not holding HAL." << std::endl;
162         int timeout_multiplier = android::base::GetIntProperty("ro.hw_timeout_multiplier", 1);
163         sleep(sleepTime * timeout_multiplier);
164         sp<IBase> hal = getHal(instance);
165         ASSERT_NE(hal.get(), nullptr);
166         ASSERT_TRUE(hal->ping().isOk());
167     }
168 }
169 
170 static constexpr size_t NUM_TIMES_GET_UNGET = 5;
171 static constexpr size_t MAX_WAITING_DURATION = 10;
172 static constexpr size_t NUM_CONCURRENT_THREADS = 5;
TEST_F(HidlLazyTest,GetWithWaitConcurrent)173 TEST_F(HidlLazyTest, GetWithWaitConcurrent) {
174     std::vector<std::vector<size_t>> threadWaitTimes(NUM_CONCURRENT_THREADS);
175 
176     for (size_t i = 0; i < threadWaitTimes.size(); i++) {
177         threadWaitTimes[i] = waitTimes(NUM_TIMES_GET_UNGET, MAX_WAITING_DURATION);
178     }
179 
180     std::vector<std::thread> threads(NUM_CONCURRENT_THREADS);
181     for (size_t i = 0; i < threads.size(); i++) {
182         const FqInstance& instance = gInstances[i % gInstances.size()];
183         threads[i] = std::thread(testWithTimes, threadWaitTimes[i], instance);
184     }
185 
186     for (auto& thread : threads) {
187         thread.join();
188     }
189 }
190 
TEST_F(HidlLazyCbTest,ActiveServicesCallbackTest)191 TEST_F(HidlLazyCbTest, ActiveServicesCallbackTest) {
192     const std::string fqInstanceName = "android.hardware.tests.lazy_cb@1.0::ILazyCb/default";
193     FqInstance fqInstance;
194     ASSERT_TRUE(fqInstance.setTo(fqInstanceName));
195 
196     // b/251244025 - this service logic is coupled with this test, but other
197     // things may have started it
198     (void)android::base::SetProperty("ctl.stop", "hidl_lazy_cb_test_server");
199 
200     ASSERT_FALSE(isServiceRunning(fqInstance)) << "Lazy service already running.";
201 
202     sp<IBase> hal = getHal(fqInstance);
203     ASSERT_NE(hal, nullptr);
204 
205     sp<ILazyCb> lazyCb = ILazyCb::castFrom(hal);
206     ASSERT_NE(lazyCb, nullptr);
207     hal = nullptr;
208 
209     int efd = eventfd(0, 0);
210     ASSERT_GE(efd, 0) << "Failed to create eventfd";
211     unique_fd uniqueEventFd(efd);
212 
213     native_handle_t* h = native_handle_create(/* numFds */ 1, /* numInts */ 0);
214     h->data[0] = efd;
215     hidl_handle handle(h);
216     Return<bool> setEventFdRet = lazyCb->setEventFd(handle);
217     native_handle_delete(h);
218     ASSERT_TRUE(setEventFdRet.isOk());
219     ASSERT_TRUE(setEventFdRet);
220 
221     lazyCb = nullptr;
222 
223     IPCThreadState::self()->flushCommands();
224 
225     std::cout << "Waiting " << SHUTDOWN_WAIT_TIME << " seconds for callback completion "
226               << "notification." << std::endl;
227 
228     int epollFd = epoll_create1(EPOLL_CLOEXEC);
229     ASSERT_GE(epollFd, 0) << "Failed to create epoll";
230     unique_fd epollUniqueFd(epollFd);
231 
232     const int EPOLL_MAX_EVENTS = 1;
233     struct epoll_event event, events[EPOLL_MAX_EVENTS];
234 
235     event.events = EPOLLIN;
236     event.data.fd = efd;
237     int rc = epoll_ctl(epollFd, EPOLL_CTL_ADD, efd, &event);
238     ASSERT_GE(rc, 0) << "Failed to add fd to epoll";
239 
240     rc = TEMP_FAILURE_RETRY(
241             epoll_wait(epollFd, events, EPOLL_MAX_EVENTS, SHUTDOWN_WAIT_TIME * 1000));
242     ASSERT_NE(rc, 0) << "Service shutdown timeout";
243     ASSERT_GT(rc, 0) << "Error waiting for service shutdown notification";
244 
245     eventfd_t counter;
246     rc = TEMP_FAILURE_RETRY(eventfd_read(uniqueEventFd.get(), &counter));
247     ASSERT_GE(rc, 0) << "Failed to get callback completion notification from service";
248     ASSERT_EQ(counter, 1);
249 
250     std::cout << "Waiting " << CALLBACK_SHUTDOWN_WAIT_TIME
251               << " seconds before checking whether the "
252               << "service is still running." << std::endl;
253 
254     int timeout_multiplier = android::base::GetIntProperty("ro.hw_timeout_multiplier", 1);
255     sleep(CALLBACK_SHUTDOWN_WAIT_TIME * timeout_multiplier);
256 
257     ASSERT_FALSE(isServiceRunning(fqInstance)) << "Service failed to shut down.";
258 }
259 
main(int argc,char ** argv)260 int main(int argc, char** argv) {
261     ::testing::InitGoogleTest(&argc, argv);
262 
263     srand(time(nullptr));
264 
265     std::vector<std::string> fqInstances;
266 
267     if (argc == 1) {
268         fqInstances.push_back("android.hardware.tests.lazy@1.0::ILazy/default1");
269         fqInstances.push_back("android.hardware.tests.lazy@1.0::ILazy/default2");
270     } else {
271         for (size_t arg = 1; arg < argc; arg++) {
272             fqInstances.push_back(argv[arg]);
273         }
274     }
275 
276     for (const std::string& instance : fqInstances) {
277         FqInstance fqInstance;
278         if (!fqInstance.setTo(instance)) {
279             std::cerr << "Invalid fqinstance: " << instance << std::endl;
280             return 1;
281         }
282         gInstances.push_back(fqInstance);
283     }
284 
285     return RUN_ALL_TESTS();
286 }
287