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