• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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