blob: 09cb096702eacb112f5a535c8f8d50577af1defd [file] [log] [blame]
Badhri Jagan Sridharanaef9dec2021-12-27 14:02:56 -08001/*
2 * Copyright (C) 2021 The Android Open Source Probject
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#define LOG_TAG "UsbAidlTest"
18#include <android-base/logging.h>
19
20#include <aidl/android/hardware/usb/IUsb.h>
21#include <aidl/android/hardware/usb/IUsbCallback.h>
22#include <aidl/android/hardware/usb/BnUsbCallback.h>
23#include <aidl/android/hardware/usb/PortDataRole.h>
24#include <aidl/android/hardware/usb/PortMode.h>
25#include <aidl/android/hardware/usb/PortPowerRole.h>
26#include <aidl/android/hardware/usb/PortRole.h>
27#include <aidl/android/hardware/usb/PortStatus.h>
28#include <aidl/android/hardware/usb/Status.h>
29#include <aidl/Vintf.h>
30#include <aidl/Gtest.h>
31
32#include <android/binder_auto_utils.h>
33#include <android/binder_manager.h>
34#include <android/binder_process.h>
35#include <gtest/gtest.h>
36
37#include <log/log.h>
38#include <stdlib.h>
39#include <chrono>
40#include <condition_variable>
41#include <mutex>
42
43#define TIMEOUT_PERIOD 10
44
45using ::aidl::android::hardware::usb::BnUsbCallback;
46using ::aidl::android::hardware::usb::IUsb;
47using ::aidl::android::hardware::usb::IUsbCallback;
48using ::aidl::android::hardware::usb::PortDataRole;
49using ::aidl::android::hardware::usb::PortMode;
50using ::aidl::android::hardware::usb::PortPowerRole;
51using ::aidl::android::hardware::usb::PortRole;
52using ::aidl::android::hardware::usb::PortStatus;
53using ::aidl::android::hardware::usb::Status;
54
55using ::ndk::ScopedAStatus;
56using ::ndk::SpAIBinder;
57using std::vector;
58using std::shared_ptr;
59using std::string;
60
61// The main test class for the USB aidl hal
62class UsbAidlTest : public testing::TestWithParam<std::string> {
63 public:
64 // Callback class for the USB aidl hal.
65 // Usb Hal will call this object upon role switch or port query.
66 class UsbCallback : public BnUsbCallback {
67 UsbAidlTest& parent_;
68 int cookie;
69
70 public:
71 UsbCallback(UsbAidlTest& parent, int cookie)
72 : parent_(parent), cookie(cookie){};
73
74 virtual ~UsbCallback() = default;
75
76 // Callback method for the port status.
77 ScopedAStatus notifyPortStatusChange(const vector<PortStatus>& currentPortStatus,
78 Status retval) override {
79 if (retval == Status::SUCCESS && currentPortStatus.size() > 0) {
80 parent_.usb_last_port_status.portName =
81 currentPortStatus[0].portName.c_str();
82 parent_.usb_last_port_status.currentDataRole =
83 currentPortStatus[0].currentDataRole;
84 parent_.usb_last_port_status.currentPowerRole =
85 currentPortStatus[0].currentPowerRole;
86 parent_.usb_last_port_status.currentMode =
87 currentPortStatus[0].currentMode;
88 }
89 parent_.usb_last_cookie = cookie;
90 return ScopedAStatus::ok();
91 }
92
93 // Callback method for the status of role switch operation.
94 ScopedAStatus notifyRoleSwitchStatus(const string& /*portName*/, const PortRole& newRole,
95 Status retval, int64_t transactionId) override {
96 parent_.usb_last_status = retval;
97 parent_.usb_last_cookie = cookie;
98 parent_.usb_last_port_role = newRole;
99 parent_.usb_role_switch_done = true;
100 parent_.last_transactionId = transactionId;
101 parent_.notify();
102 return ScopedAStatus::ok();
103 }
104
105 // Callback method for the status of enableUsbData operation
106 ScopedAStatus notifyEnableUsbDataStatus(const string& /*portName*/, bool /*enable*/,
107 Status /*retval*/, int64_t transactionId) override {
108 parent_.last_transactionId = transactionId;
109 parent_.usb_last_cookie = cookie;
110 parent_.enable_usb_data_done = true;
111 parent_.notify();
112 return ScopedAStatus::ok();
113 }
114
115 // Callback method for the status of enableContaminantPresenceDetection
116 ScopedAStatus notifyContaminantEnabledStatus(const string& /*portName*/, bool /*enable*/,
117 Status /*retval*/, int64_t transactionId) override {
118 parent_.last_transactionId = transactionId;
119 parent_.usb_last_cookie = cookie;
120 parent_.enable_contaminant_done = true;
121 parent_.notify();
122 return ScopedAStatus::ok();
123 }
124
125 // Callback method for the status of queryPortStatus operation
126 ScopedAStatus notifyQueryPortStatus(const string& /*portName*/, Status /*retval*/,
127 int64_t transactionId) override {
128 parent_.last_transactionId = transactionId;
129 parent_.notify();
130 return ScopedAStatus::ok();
131 }
132 };
133
134 virtual void SetUp() override {
135 ALOGI("Setup");
136 usb = IUsb::fromBinder(
137 SpAIBinder(AServiceManager_waitForService(GetParam().c_str())));
138 ASSERT_NE(usb, nullptr);
139
140 usb_cb_2 = ::ndk::SharedRefBase::make<UsbCallback>(*this, 2);
141 ASSERT_NE(usb_cb_2, nullptr);
142 const auto& ret = usb->setCallback(usb_cb_2);
143 ASSERT_TRUE(ret.isOk());
144 }
145
146 virtual void TearDown() override { ALOGI("Teardown"); }
147
148 // Used as a mechanism to inform the test about data/event callback.
149 inline void notify() {
150 std::unique_lock<std::mutex> lock(usb_mtx);
151 usb_count++;
152 usb_cv.notify_one();
153 }
154
155 // Test code calls this function to wait for data/event callback.
156 inline std::cv_status wait() {
157 std::unique_lock<std::mutex> lock(usb_mtx);
158
159 std::cv_status status = std::cv_status::no_timeout;
160 auto now = std::chrono::system_clock::now();
161 while (usb_count == 0) {
162 status =
163 usb_cv.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
164 if (status == std::cv_status::timeout) {
165 ALOGI("timeout");
166 return status;
167 }
168 }
169 usb_count--;
170 return status;
171 }
172
173 // USB aidl hal Proxy
174 shared_ptr<IUsb> usb;
175
176 // Callback objects for usb aidl
177 // Methods of these objects are called to notify port status updates.
178 shared_ptr<IUsbCallback> usb_cb_1, usb_cb_2;
179
180 // The last conveyed status of the USB ports.
181 // Stores information of currentt_data_role, power_role for all the USB ports
182 PortStatus usb_last_port_status;
183
184 // Status of the last role switch operation.
185 Status usb_last_status;
186
187 // Port role information of the last role switch operation.
188 PortRole usb_last_port_role;
189
190 // Flag to indicate the invocation of role switch callback.
191 bool usb_role_switch_done;
192
193 // Flag to indicate the invocation of notifyContaminantEnabledStatus callback.
194 bool enable_contaminant_done;
195
196 // Flag to indicate the invocation of notifyEnableUsbDataStatus callback.
197 bool enable_usb_data_done;
198
199 // Stores the cookie of the last invoked usb callback object.
200 int usb_last_cookie;
201
202 // Last transaction ID that was recorded.
203 int64_t last_transactionId;
204 // synchronization primitives to coordinate between main test thread
205 // and the callback thread.
206 std::mutex usb_mtx;
207 std::condition_variable usb_cv;
208 int usb_count = 0;
209};
210
211/*
212 * Test to see if setCallback succeeds.
213 * Callback object is created and registered.
214 */
215TEST_P(UsbAidlTest, setCallback) {
216 ALOGI("UsbAidlTest setCallback start");
217 usb_cb_1 = ::ndk::SharedRefBase::make<UsbCallback>(*this, 1);
218 ASSERT_NE(usb_cb_1, nullptr);
219 const auto& ret = usb->setCallback(usb_cb_1);
220 ASSERT_TRUE(ret.isOk());
221 ALOGI("UsbAidlTest setCallback end");
222}
223
224/*
225 * Check to see if querying type-c
226 * port status succeeds.
227 * The callback parameters are checked to see if the transaction id
228 * matches.
229 */
230TEST_P(UsbAidlTest, queryPortStatus) {
231 ALOGI("UsbAidlTest queryPortStatus start");
232 int64_t transactionId = rand() % 10000;
233 const auto& ret = usb->queryPortStatus(transactionId);
234 ASSERT_TRUE(ret.isOk());
235 EXPECT_EQ(std::cv_status::no_timeout, wait());
236 EXPECT_EQ(2, usb_last_cookie);
237 EXPECT_EQ(transactionId, last_transactionId);
238 ALOGI("UsbAidlTest queryPortStatus end: %s", usb_last_port_status.portName.c_str());
239}
240
241/*
242 * Trying to switch a non-existent port should fail.
243 * This test case tried to switch the port with empty
244 * name which is expected to fail.
245 * The callback parameters are checked to see if the transaction id
246 * matches.
247 */
248TEST_P(UsbAidlTest, switchEmptyPort) {
249 ALOGI("UsbAidlTest switchEmptyPort start");
250 PortRole role;
251 role.set<PortRole::powerRole>(PortPowerRole::SOURCE);
252 int64_t transactionId = rand() % 10000;
253 const auto& ret = usb->switchRole("", role, transactionId);
254 ASSERT_TRUE(ret.isOk());
255 EXPECT_EQ(std::cv_status::no_timeout, wait());
256 EXPECT_EQ(Status::ERROR, usb_last_status);
257 EXPECT_EQ(transactionId, last_transactionId);
258 EXPECT_EQ(2, usb_last_cookie);
259 ALOGI("UsbAidlTest switchEmptyPort end");
260}
261
262/*
263 * Test switching the power role of usb port.
264 * Test case queries the usb ports present in device.
265 * If there is at least one usb port, a power role switch
266 * to SOURCE is attempted for the port.
267 * The callback parameters are checked to see if the transaction id
268 * matches.
269 */
270TEST_P(UsbAidlTest, switchPowerRole) {
271 ALOGI("UsbAidlTest switchPowerRole start");
272 PortRole role;
273 role.set<PortRole::powerRole>(PortPowerRole::SOURCE);
274 int64_t transactionId = rand() % 10000;
275 const auto& ret = usb->queryPortStatus(transactionId);
276 ASSERT_TRUE(ret.isOk());
277 EXPECT_EQ(std::cv_status::no_timeout, wait());
278 EXPECT_EQ(2, usb_last_cookie);
279 EXPECT_EQ(transactionId, last_transactionId);
280
281 if (!usb_last_port_status.portName.empty()) {
282 string portBeingSwitched = usb_last_port_status.portName;
283 ALOGI("switchPower role portname:%s", portBeingSwitched.c_str());
284 usb_role_switch_done = false;
285 transactionId = rand() % 10000;
286 const auto& ret = usb->switchRole(portBeingSwitched, role, transactionId);
287 ASSERT_TRUE(ret.isOk());
288
289 std::cv_status waitStatus = wait();
290 while (waitStatus == std::cv_status::no_timeout &&
291 usb_role_switch_done == false)
292 waitStatus = wait();
293
294 EXPECT_EQ(std::cv_status::no_timeout, waitStatus);
295 EXPECT_EQ(2, usb_last_cookie);
296 EXPECT_EQ(transactionId, last_transactionId);
297 }
298 ALOGI("UsbAidlTest switchPowerRole end");
299}
300
301/*
302 * Test switching the data role of usb port.
303 * Test case queries the usb ports present in device.
304 * If there is at least one usb port, a data role switch
305 * to device is attempted for the port.
306 * The callback parameters are checked to see if transaction id
307 * matches.
308 */
309TEST_P(UsbAidlTest, switchDataRole) {
310 ALOGI("UsbAidlTest switchDataRole start");
311 PortRole role;
312 role.set<PortRole::dataRole>(PortDataRole::DEVICE);
313 int64_t transactionId = rand() % 10000;
314 const auto& ret = usb->queryPortStatus(transactionId);
315 ASSERT_TRUE(ret.isOk());
316 EXPECT_EQ(std::cv_status::no_timeout, wait());
317 EXPECT_EQ(2, usb_last_cookie);
318 EXPECT_EQ(transactionId, last_transactionId);
319
320 if (!usb_last_port_status.portName.empty()) {
321 string portBeingSwitched = usb_last_port_status.portName;
322 ALOGI("portname:%s", portBeingSwitched.c_str());
323 usb_role_switch_done = false;
324 transactionId = rand() % 10000;
325 const auto& ret = usb->switchRole(portBeingSwitched, role, transactionId);
326 ASSERT_TRUE(ret.isOk());
327
328 std::cv_status waitStatus = wait();
329 while (waitStatus == std::cv_status::no_timeout &&
330 usb_role_switch_done == false)
331 waitStatus = wait();
332
333 EXPECT_EQ(std::cv_status::no_timeout, waitStatus);
334 EXPECT_EQ(2, usb_last_cookie);
335 EXPECT_EQ(transactionId, last_transactionId);
336 }
337 ALOGI("UsbAidlTest switchDataRole end");
338}
339
340/*
341 * Test enabling contaminant presence detection of the port.
342 * Test case queries the usb ports present in device.
343 * If there is at least one usb port, enabling contaminant detection
344 * is attempted for the port.
345 * The callback parameters are checked to see if transaction id
346 * matches.
347 */
348TEST_P(UsbAidlTest, enableContaminantPresenceDetection) {
349 ALOGI("UsbAidlTest enableContaminantPresenceDetection start");
350 int64_t transactionId = rand() % 10000;
351 const auto& ret = usb->queryPortStatus(transactionId);
352 ASSERT_TRUE(ret.isOk());
353 EXPECT_EQ(std::cv_status::no_timeout, wait());
354 EXPECT_EQ(2, usb_last_cookie);
355 EXPECT_EQ(transactionId, last_transactionId);
356
357 if (!usb_last_port_status.portName.empty()) {
358 ALOGI("portname:%s", usb_last_port_status.portName.c_str());
359 enable_contaminant_done = false;
360 transactionId = rand() % 10000;
361 const auto& ret = usb->enableContaminantPresenceDetection(usb_last_port_status.portName,
362 true, transactionId);
363 ASSERT_TRUE(ret.isOk());
364
365 std::cv_status waitStatus = wait();
366 while (waitStatus == std::cv_status::no_timeout &&
367 enable_contaminant_done == false)
368 waitStatus = wait();
369
370 EXPECT_EQ(std::cv_status::no_timeout, waitStatus);
371 EXPECT_EQ(2, usb_last_cookie);
372 EXPECT_EQ(transactionId, last_transactionId);
373 }
374 ALOGI("UsbAidlTest enableContaminantPresenceDetection end");
375}
376
377/*
378 * Test enabling Usb data of the port.
379 * Test case queries the usb ports present in device.
380 * If there is at least one usb port, enabling Usb data is attempted
381 * for the port.
382 * The callback parameters are checked to see if transaction id
383 * matches.
384 */
385TEST_P(UsbAidlTest, enableUsbData) {
386 ALOGI("UsbAidlTest enableUsbData start");
387 int64_t transactionId = rand() % 10000;
388 const auto& ret = usb->queryPortStatus(transactionId);
389 ASSERT_TRUE(ret.isOk());
390 EXPECT_EQ(std::cv_status::no_timeout, wait());
391 EXPECT_EQ(2, usb_last_cookie);
392 EXPECT_EQ(transactionId, last_transactionId);
393
394 if (!usb_last_port_status.portName.empty()) {
395 ALOGI("portname:%s", usb_last_port_status.portName.c_str());
396 enable_usb_data_done = false;
397 transactionId = rand() % 10000;
398 const auto& ret = usb->enableUsbData(usb_last_port_status.portName, true, transactionId);
399 ASSERT_TRUE(ret.isOk());
400
401 std::cv_status waitStatus = wait();
402 while (waitStatus == std::cv_status::no_timeout &&
403 enable_usb_data_done == false)
404 waitStatus = wait();
405
406 EXPECT_EQ(std::cv_status::no_timeout, waitStatus);
407 EXPECT_EQ(2, usb_last_cookie);
408 EXPECT_EQ(transactionId, last_transactionId);
409 }
410 ALOGI("UsbAidlTest enableUsbData end");
411}
412
413GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UsbAidlTest);
414INSTANTIATE_TEST_SUITE_P(
415 PerInstance, UsbAidlTest,
416 testing::ValuesIn(::android::getAidlHalInstanceNames(IUsb::descriptor)),
417 ::android::PrintInstanceNameToString);
418
419int main(int argc, char** argv) {
420 ::testing::InitGoogleTest(&argc, argv);
421 ABinderProcess_setThreadPoolMaxThreadCount(1);
422 ABinderProcess_startThreadPool();
423 return RUN_ALL_TESTS();
424}