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 #define LOG_TAG "VtsHalUsbV1_2TargetTest"
18 #include <android-base/logging.h>
19 
20 #include <android/hardware/usb/1.2/IUsb.h>
21 #include <android/hardware/usb/1.2/IUsbCallback.h>
22 #include <android/hardware/usb/1.2/types.h>
23 
24 #include <VtsHalHidlTargetCallbackBase.h>
25 #include <gtest/gtest.h>
26 #include <hidl/GtestPrinter.h>
27 #include <hidl/ServiceManagement.h>
28 
29 #include <log/log.h>
30 #include <stdlib.h>
31 #include <chrono>
32 #include <condition_variable>
33 #include <mutex>
34 
35 using ::android::sp;
36 using ::android::hardware::hidl_array;
37 using ::android::hardware::hidl_memory;
38 using ::android::hardware::hidl_string;
39 using ::android::hardware::hidl_vec;
40 using ::android::hardware::Return;
41 using ::android::hardware::Void;
42 using ::android::hardware::usb::V1_0::PortDataRole;
43 using ::android::hardware::usb::V1_0::PortMode;
44 using ::android::hardware::usb::V1_0::PortPowerRole;
45 using ::android::hardware::usb::V1_0::PortRole;
46 using ::android::hardware::usb::V1_0::PortRoleType;
47 using ::android::hardware::usb::V1_0::Status;
48 using ::android::hardware::usb::V1_1::PortMode_1_1;
49 using ::android::hardware::usb::V1_1::PortStatus_1_1;
50 using ::android::hardware::usb::V1_2::ContaminantDetectionStatus;
51 using ::android::hardware::usb::V1_2::ContaminantProtectionMode;
52 using ::android::hardware::usb::V1_2::ContaminantProtectionStatus;
53 using ::android::hardware::usb::V1_2::IUsb;
54 using ::android::hardware::usb::V1_2::IUsbCallback;
55 using ::android::hardware::usb::V1_2::PortStatus;
56 using ::android::hidl::base::V1_0::IBase;
57 
58 constexpr char kCallbackNameNotifyPortStatusChange_1_2[] = "notifyPortStatusChange_1_2";
59 const int kCallbackIdentifier = 2;
60 
61 // Worst case wait time 20secs
62 #define WAIT_FOR_TIMEOUT std::chrono::milliseconds(20000)
63 
64 class UsbClientCallbackArgs {
65    public:
66     // The last conveyed status of the USB ports.
67     // Stores information of currentt_data_role, power_role for all the USB ports
68     PortStatus usb_last_port_status;
69 
70     // Status of the last role switch operation.
71     Status usb_last_status;
72 
73     // Identifier for the usb callback object.
74     // Stores the cookie of the last invoked usb callback object.
75     int last_usb_cookie;
76 };
77 
78 // Callback class for the USB HIDL hal.
79 // Usb Hal will call this object upon role switch or port query.
80 class UsbCallback : public ::testing::VtsHalHidlTargetCallbackBase<UsbClientCallbackArgs>,
81                     public IUsbCallback {
82     int cookie;
83 
84    public:
UsbCallback(int cookie)85     UsbCallback(int cookie) : cookie(cookie){};
86 
87     virtual ~UsbCallback() = default;
88 
89     // V1_0 Callback method for the port status.
90     // This should not be called so not signalling the Test here assuming that
91     // the test thread will timeout
notifyPortStatusChange(const hidl_vec<android::hardware::usb::V1_0::PortStatus> &,Status)92     Return<void> notifyPortStatusChange(const hidl_vec<android::hardware::usb::V1_0::PortStatus>&
93                                         /* currentPortStatus */,
94                                         Status /* retval */) override {
95         return Void();
96     };
97 
98     // V1_1 Callback method for the port status.
99     // This should not be called so not signalling the Test here assuming that
100     // the test thread will timeout
notifyPortStatusChange_1_1(const hidl_vec<PortStatus_1_1> &,Status)101     Return<void> notifyPortStatusChange_1_1(const hidl_vec<PortStatus_1_1>& /* currentPortStatus */,
102                                             Status /* retval */) override {
103         return Void();
104     }
105 
106     // This callback method should be used.
notifyPortStatusChange_1_2(const hidl_vec<PortStatus> & currentPortStatus,Status retval)107     Return<void> notifyPortStatusChange_1_2(const hidl_vec<PortStatus>& currentPortStatus,
108                                             Status retval) override {
109         UsbClientCallbackArgs arg;
110         if (retval == Status::SUCCESS) {
111             arg.usb_last_port_status.status_1_1.status.supportedModes =
112                     currentPortStatus[0].status_1_1.status.supportedModes;
113             arg.usb_last_port_status.status_1_1.status.currentMode =
114                     currentPortStatus[0].status_1_1.status.currentMode;
115             arg.usb_last_port_status.status_1_1.status.portName =
116                     currentPortStatus[0].status_1_1.status.portName;
117             arg.usb_last_port_status.contaminantDetectionStatus =
118                     currentPortStatus[0].contaminantDetectionStatus;
119             arg.usb_last_port_status.contaminantProtectionStatus =
120                     currentPortStatus[0].contaminantProtectionStatus;
121             arg.usb_last_port_status.supportsEnableContaminantPresenceProtection =
122                     currentPortStatus[0].supportsEnableContaminantPresenceProtection;
123             arg.usb_last_port_status.supportsEnableContaminantPresenceDetection =
124                     currentPortStatus[0].supportsEnableContaminantPresenceDetection;
125             arg.usb_last_port_status.supportedContaminantProtectionModes =
126                     currentPortStatus[0].supportedContaminantProtectionModes;
127         }
128         arg.usb_last_status = retval;
129         arg.last_usb_cookie = cookie;
130 
131         NotifyFromCallback(kCallbackNameNotifyPortStatusChange_1_2, arg);
132         return Void();
133     }
134 
135     // Callback method for the status of role switch operation.
136     // RoleSwitch operation has not changed since V1_0 so leaving
137     // the callback blank here.
notifyRoleSwitchStatus(const hidl_string &,const PortRole &,Status)138     Return<void> notifyRoleSwitchStatus(const hidl_string& /*portName*/,
139                                         const PortRole& /*newRole*/, Status /*retval*/) override {
140         return Void();
141     };
142 };
143 
144 // The main test class for the USB hidl HAL
145 class UsbHidlTest : public ::testing::TestWithParam<std::string> {
146   public:
SetUp()147     virtual void SetUp() override {
148         ALOGI(__FUNCTION__);
149         usb = IUsb::getService(GetParam());
150         ASSERT_NE(usb, nullptr);
151 
152         usb_cb_2 = new UsbCallback(kCallbackIdentifier);
153         ASSERT_NE(usb_cb_2, nullptr);
154         usb_cb_2->SetWaitTimeout(kCallbackNameNotifyPortStatusChange_1_2, WAIT_FOR_TIMEOUT);
155         Return<void> ret = usb->setCallback(usb_cb_2);
156         ASSERT_TRUE(ret.isOk());
157     }
158 
TearDown()159     virtual void TearDown() override { ALOGI("Teardown"); }
160 
161     // USB hidl hal Proxy
162     sp<IUsb> usb;
163 
164     // Callback objects for usb hidl
165     // Methods of these objects are called to notify port status updates.
166     sp<UsbCallback> usb_cb_1;
167     sp<UsbCallback> usb_cb_2;
168 };
169 
170 /*
171  * Test to see if setCallback on V1_1 callback object succeeds.
172  * Callback oject is created and registered.
173  * Check to see if the hidl transaction succeeded.
174  */
TEST_P(UsbHidlTest,setCallback)175 TEST_P(UsbHidlTest, setCallback) {
176     usb_cb_1 = new UsbCallback(1);
177     ASSERT_NE(usb_cb_1, nullptr);
178     Return<void> ret = usb->setCallback(usb_cb_1);
179     ASSERT_TRUE(ret.isOk());
180 }
181 
182 /*
183  * Check to see if querying type-c
184  * port status succeeds.
185  * HAL service should call notifyPortStatusChange_1_2
186  * instead of notifyPortStatusChange of V1_0/V1_1 interface
187  */
TEST_P(UsbHidlTest,queryPortStatus)188 TEST_P(UsbHidlTest, queryPortStatus) {
189     Return<void> ret = usb->queryPortStatus();
190     ASSERT_TRUE(ret.isOk());
191     auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2);
192     EXPECT_TRUE(res.no_timeout);
193     EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie);
194     EXPECT_EQ(PortMode::NONE, res.args->usb_last_port_status.status_1_1.status.currentMode);
195     EXPECT_EQ(PortMode::NONE, res.args->usb_last_port_status.status_1_1.status.supportedModes);
196     EXPECT_EQ(Status::SUCCESS, res.args->usb_last_status);
197 }
198 
199 /*
200  * supportedContaminantProtectionModes is immutable.
201  * Check if supportedContaminantProtectionModes changes across queryPortStatus
202  * call.
203  */
TEST_P(UsbHidlTest,checkSupportedContaminantProtectionModes)204 TEST_P(UsbHidlTest, checkSupportedContaminantProtectionModes) {
205     Return<void> ret = usb->queryPortStatus();
206     ASSERT_TRUE(ret.isOk());
207     auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2);
208     EXPECT_TRUE(res.no_timeout);
209     EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie);
210     EXPECT_EQ(PortMode::NONE, res.args->usb_last_port_status.status_1_1.status.currentMode);
211     EXPECT_EQ(PortMode::NONE, res.args->usb_last_port_status.status_1_1.status.supportedModes);
212     EXPECT_EQ(Status::SUCCESS, res.args->usb_last_status);
213 
214     uint32_t supportedContaminantProtectionModes = static_cast<uint32_t>(
215             res.args->usb_last_port_status.supportedContaminantProtectionModes);
216     for (int runs = 1; runs <= 10; runs++) {
217         ret = usb->queryPortStatus();
218         ASSERT_TRUE(ret.isOk());
219         res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2);
220         EXPECT_TRUE(res.no_timeout);
221         EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie);
222         EXPECT_EQ(PortMode::NONE, res.args->usb_last_port_status.status_1_1.status.currentMode);
223         EXPECT_EQ(PortMode::NONE, res.args->usb_last_port_status.status_1_1.status.supportedModes);
224         EXPECT_EQ(Status::SUCCESS, res.args->usb_last_status);
225         EXPECT_EQ(supportedContaminantProtectionModes,
226                   static_cast<uint32_t>(
227                           res.args->usb_last_port_status.supportedContaminantProtectionModes));
228     }
229 }
230 
231 /*
232  * When supportsEnableContaminantPresenceDetection is set false,
233  * enableContaminantPresenceDetection should not enable/disable
234  * contaminantPresenceProtection.
235  */
TEST_P(UsbHidlTest,presenceDetectionSupportedCheck)236 TEST_P(UsbHidlTest, presenceDetectionSupportedCheck) {
237     Return<void> ret = usb->queryPortStatus();
238     ASSERT_TRUE(ret.isOk());
239     auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2);
240     EXPECT_TRUE(res.no_timeout);
241     EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie);
242     EXPECT_EQ(Status::SUCCESS, res.args->usb_last_status);
243 
244     if (!res.args->usb_last_port_status.supportsEnableContaminantPresenceDetection) {
245         for (int runs = 1; runs <= 10; runs++) {
246             bool currentStatus = !(res.args->usb_last_port_status.contaminantDetectionStatus ==
247                                    ContaminantDetectionStatus::DISABLED);
248 
249             ret = usb->enableContaminantPresenceDetection(
250                     res.args->usb_last_port_status.status_1_1.status.portName, !currentStatus);
251             ASSERT_TRUE(ret.isOk());
252 
253             res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2);
254             EXPECT_TRUE(res.no_timeout);
255             EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie);
256             EXPECT_EQ(currentStatus, !(res.args->usb_last_port_status.contaminantDetectionStatus ==
257                                        ContaminantDetectionStatus::DISABLED));
258         }
259     }
260 }
261 
262 /*
263  * enableContaminantPresenceDetection should succeed atleast 90% when supported.
264  */
TEST_P(UsbHidlTest,contaminantPresenceDetectionStability)265 TEST_P(UsbHidlTest, contaminantPresenceDetectionStability) {
266     int successCount = 0;
267     bool currentStatus;
268     bool supported = true;
269 
270     Return<void> ret = usb->queryPortStatus();
271     ASSERT_TRUE(ret.isOk());
272     auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2);
273     EXPECT_TRUE(res.no_timeout);
274     EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie);
275     EXPECT_EQ(Status::SUCCESS, res.args->usb_last_status);
276 
277     if (!res.args->usb_last_port_status.supportsEnableContaminantPresenceDetection) return;
278 
279     for (int count = 1; count <= 10; count++) {
280         currentStatus = !(res.args->usb_last_port_status.contaminantDetectionStatus ==
281                           ContaminantDetectionStatus::DISABLED);
282 
283         ret = usb->enableContaminantPresenceDetection(
284                 res.args->usb_last_port_status.status_1_1.status.portName, !currentStatus);
285         ASSERT_TRUE(ret.isOk());
286         res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2);
287         EXPECT_TRUE(res.no_timeout);
288         EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie);
289         if (!currentStatus == !(res.args->usb_last_port_status.contaminantDetectionStatus ==
290                                 ContaminantDetectionStatus::DISABLED))
291             successCount++;
292     }
293 
294     if (!supported) EXPECT_GE(successCount, 9);
295 }
296 
297 /*
298  * When supportsEnableContaminantPresenceProtection is set false,
299  * enableContaminantPresenceProtection should not enable/disable
300  * contaminantPresenceProtection.
301  */
TEST_P(UsbHidlTest,presenceProtectionSupportedCheck)302 TEST_P(UsbHidlTest, presenceProtectionSupportedCheck) {
303     Return<void> ret = usb->queryPortStatus();
304     ASSERT_TRUE(ret.isOk());
305     auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2);
306     EXPECT_TRUE(res.no_timeout);
307     EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie);
308     EXPECT_EQ(Status::SUCCESS, res.args->usb_last_status);
309 
310     if (!res.args->usb_last_port_status.supportsEnableContaminantPresenceProtection) {
311         for (int runs = 1; runs <= 10; runs++) {
312             bool currentStatus = !(res.args->usb_last_port_status.contaminantProtectionStatus ==
313                                    ContaminantProtectionStatus::DISABLED);
314 
315             ret = usb->enableContaminantPresenceProtection(
316                     res.args->usb_last_port_status.status_1_1.status.portName, !currentStatus);
317             ASSERT_TRUE(ret.isOk());
318 
319             res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2);
320             EXPECT_TRUE(res.no_timeout);
321             EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie);
322             EXPECT_EQ(currentStatus, !(res.args->usb_last_port_status.contaminantProtectionStatus ==
323                                        ContaminantProtectionStatus::DISABLED));
324         }
325     }
326 }
327 
328 /*
329  * enableContaminantPresenceProtection should succeed atleast 90% when supported.
330  */
TEST_P(UsbHidlTest,contaminantPresenceProtectionStability)331 TEST_P(UsbHidlTest, contaminantPresenceProtectionStability) {
332     int successCount = 0;
333     bool currentStatus;
334     bool supported = true;
335 
336     Return<void> ret = usb->queryPortStatus();
337     ASSERT_TRUE(ret.isOk());
338     auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2);
339     EXPECT_TRUE(res.no_timeout);
340     EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie);
341     EXPECT_EQ(Status::SUCCESS, res.args->usb_last_status);
342 
343     if (!res.args->usb_last_port_status.supportsEnableContaminantPresenceProtection) return;
344 
345     for (int count = 1; count <= 10; count++) {
346         currentStatus = !(res.args->usb_last_port_status.contaminantProtectionStatus ==
347                           ContaminantProtectionStatus::DISABLED);
348 
349         ret = usb->enableContaminantPresenceProtection(
350                 res.args->usb_last_port_status.status_1_1.status.portName, !currentStatus);
351         ASSERT_TRUE(ret.isOk());
352         res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2);
353         EXPECT_TRUE(res.no_timeout);
354         EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie);
355         if (!currentStatus == !(res.args->usb_last_port_status.contaminantProtectionStatus ==
356                                 ContaminantProtectionStatus::DISABLED))
357             successCount++;
358     }
359 
360     if (!supported) EXPECT_GE(successCount, 9);
361 }
362 
363 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(UsbHidlTest);
364 INSTANTIATE_TEST_SUITE_P(
365         PerInstance, UsbHidlTest,
366         testing::ValuesIn(android::hardware::getAllHalInstanceNames(IUsb::descriptor)),
367         android::hardware::PrintInstanceNameToString);
368