1 /*
2 * Copyright (C) 2017 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_0TargetTest"
18 #include <android-base/logging.h>
19
20 #include <android/hardware/usb/1.0/IUsb.h>
21 #include <android/hardware/usb/1.0/IUsbCallback.h>
22 #include <android/hardware/usb/1.0/types.h>
23
24 #include <VtsHalHidlTargetTestBase.h>
25 #include <VtsHalHidlTargetTestEnvBase.h>
26 #include <log/log.h>
27 #include <stdlib.h>
28 #include <chrono>
29 #include <condition_variable>
30 #include <mutex>
31
32 #define TIMEOUT_PERIOD 10
33
34 using ::android::hardware::usb::V1_0::IUsbCallback;
35 using ::android::hardware::usb::V1_0::IUsb;
36 using ::android::hardware::usb::V1_0::PortDataRole;
37 using ::android::hardware::usb::V1_0::PortMode;
38 using ::android::hardware::usb::V1_0::PortPowerRole;
39 using ::android::hardware::usb::V1_0::PortRole;
40 using ::android::hardware::usb::V1_0::PortRoleType;
41 using ::android::hardware::usb::V1_0::PortStatus;
42 using ::android::hardware::usb::V1_0::Status;
43 using ::android::hidl::base::V1_0::IBase;
44 using ::android::hardware::hidl_array;
45 using ::android::hardware::hidl_memory;
46 using ::android::hardware::hidl_string;
47 using ::android::hardware::hidl_vec;
48 using ::android::hardware::Return;
49 using ::android::hardware::Void;
50 using ::android::sp;
51
52 // Test environment for Usb HIDL HAL.
53 class UsbHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
54 public:
55 // get the test environment singleton
Instance()56 static UsbHidlEnvironment* Instance() {
57 static UsbHidlEnvironment* instance = new UsbHidlEnvironment;
58 return instance;
59 }
60
registerTestServices()61 virtual void registerTestServices() override { registerTestService<IUsb>(); }
62 };
63
64 // The main test class for the USB hidl HAL
65 class UsbHidlTest : public ::testing::VtsHalHidlTargetTestBase {
66 public:
67 // Callback class for the USB HIDL hal.
68 // Usb Hal will call this object upon role switch or port query.
69 class UsbCallback : public IUsbCallback {
70 UsbHidlTest& parent_;
71 int cookie;
72
73 public:
UsbCallback(UsbHidlTest & parent,int cookie)74 UsbCallback(UsbHidlTest& parent, int cookie)
75 : parent_(parent), cookie(cookie){};
76
77 virtual ~UsbCallback() = default;
78
79 // Callback method for the port status.
notifyPortStatusChange(const hidl_vec<PortStatus> & currentPortStatus,Status retval)80 Return<void> notifyPortStatusChange(
81 const hidl_vec<PortStatus>& currentPortStatus, Status retval) override {
82 if (retval == Status::SUCCESS) {
83 parent_.usb_last_port_status.portName =
84 currentPortStatus[0].portName.c_str();
85 parent_.usb_last_port_status.currentDataRole =
86 currentPortStatus[0].currentDataRole;
87 parent_.usb_last_port_status.currentPowerRole =
88 currentPortStatus[0].currentPowerRole;
89 parent_.usb_last_port_status.currentMode =
90 currentPortStatus[0].currentMode;
91 }
92 parent_.usb_last_cookie = cookie;
93 parent_.notify();
94 return Void();
95 };
96
97 // Callback method for the status of role switch operation.
notifyRoleSwitchStatus(const hidl_string &,const PortRole & newRole,Status retval)98 Return<void> notifyRoleSwitchStatus(const hidl_string& /*portName*/,
99 const PortRole& newRole,
100 Status retval) override {
101 parent_.usb_last_status = retval;
102 parent_.usb_last_cookie = cookie;
103 parent_.usb_last_port_role = newRole;
104 parent_.usb_role_switch_done = true;
105 parent_.notify();
106 return Void();
107 };
108 };
109
SetUp()110 virtual void SetUp() override {
111 ALOGI("Setup");
112 usb = ::testing::VtsHalHidlTargetTestBase::getService<IUsb>(
113 UsbHidlEnvironment::Instance()->getServiceName<IUsb>());
114 ASSERT_NE(usb, nullptr);
115
116 usb_cb_2 = new UsbCallback(*this, 2);
117 ASSERT_NE(usb_cb_2, nullptr);
118 Return<void> ret = usb->setCallback(usb_cb_2);
119 ASSERT_TRUE(ret.isOk());
120 }
121
TearDown()122 virtual void TearDown() override { ALOGI("Teardown"); }
123
124 // Used as a mechanism to inform the test about data/event callback.
notify()125 inline void notify() {
126 std::unique_lock<std::mutex> lock(usb_mtx);
127 usb_count++;
128 usb_cv.notify_one();
129 }
130
131 // Test code calls this function to wait for data/event callback.
wait()132 inline std::cv_status wait() {
133 std::unique_lock<std::mutex> lock(usb_mtx);
134
135 std::cv_status status = std::cv_status::no_timeout;
136 auto now = std::chrono::system_clock::now();
137 while (usb_count == 0) {
138 status =
139 usb_cv.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
140 if (status == std::cv_status::timeout) {
141 ALOGI("timeout");
142 return status;
143 }
144 }
145 usb_count--;
146 return status;
147 }
148
149 // USB hidl hal Proxy
150 sp<IUsb> usb;
151
152 // Callback objects for usb hidl
153 // Methods of these objects are called to notify port status updates.
154 sp<IUsbCallback> usb_cb_1, usb_cb_2;
155
156 // The last conveyed status of the USB ports.
157 // Stores information of currentt_data_role, power_role for all the USB ports
158 PortStatus usb_last_port_status;
159
160 // Status of the last role switch operation.
161 Status usb_last_status;
162
163 // Port role information of the last role switch operation.
164 PortRole usb_last_port_role;
165
166 // Flag to indicate the invocation of role switch callback.
167 bool usb_role_switch_done;
168
169 // Identifier for the usb callback object.
170 // Stores the cookie of the last invoked usb callback object.
171 int usb_last_cookie;
172
173 // synchronization primitives to coordinate between main test thread
174 // and the callback thread.
175 std::mutex usb_mtx;
176 std::condition_variable usb_cv;
177 int usb_count = 0;
178 };
179
180 /*
181 * Test to see if setCallback succeeds.
182 * Callback oject is created and registered.
183 * Check to see if the hidl transaction succeeded.
184 */
TEST_F(UsbHidlTest,setCallback)185 TEST_F(UsbHidlTest, setCallback) {
186 usb_cb_1 = new UsbCallback(*this, 1);
187 ASSERT_NE(usb_cb_1, nullptr);
188 Return<void> ret = usb->setCallback(usb_cb_1);
189 ASSERT_TRUE(ret.isOk());
190 }
191
192 /*
193 * Check to see if querying type-c
194 * port status succeeds.
195 */
TEST_F(UsbHidlTest,queryPortStatus)196 TEST_F(UsbHidlTest, queryPortStatus) {
197 Return<void> ret = usb->queryPortStatus();
198 ASSERT_TRUE(ret.isOk());
199 EXPECT_EQ(std::cv_status::no_timeout, wait());
200 EXPECT_EQ(2, usb_last_cookie);
201 ALOGI("rightafter: %s", usb_last_port_status.portName.c_str());
202 }
203
204 /*
205 * Trying to switch a non-existent port should fail.
206 * This test case tried to switch the port with empty
207 * name which is expected to fail.
208 */
TEST_F(UsbHidlTest,switchEmptyPort)209 TEST_F(UsbHidlTest, switchEmptyPort) {
210 struct PortRole role;
211 role.type = PortRoleType::DATA_ROLE;
212
213 Return<void> ret = usb->switchRole("", role);
214 ASSERT_TRUE(ret.isOk());
215 EXPECT_EQ(std::cv_status::no_timeout, wait());
216 EXPECT_EQ(Status::ERROR, usb_last_status);
217 EXPECT_EQ(2, usb_last_cookie);
218 }
219
220 /*
221 * Test switching the mode of usb port.
222 * Test case queries the usb ports present in device.
223 * If there is atleast one usb port, a mode switch
224 * to DFP is attempted for the port.
225 * The callback parametes are checked to see if the mode
226 * switch was successfull. Upon success, Status::SUCCESS
227 * is expected to be returned.
228 */
TEST_F(UsbHidlTest,switchModetoDFP)229 TEST_F(UsbHidlTest, switchModetoDFP) {
230 struct PortRole role;
231 role.type = PortRoleType::MODE;
232 role.role = static_cast<uint32_t>(PortMode::DFP);
233
234 Return<void> ret = usb->queryPortStatus();
235 ASSERT_TRUE(ret.isOk());
236 EXPECT_EQ(std::cv_status::no_timeout, wait());
237 EXPECT_EQ(2, usb_last_cookie);
238
239 if (!usb_last_port_status.portName.empty()) {
240 hidl_string portBeingSwitched = usb_last_port_status.portName;
241 ALOGI("mode portname:%s", portBeingSwitched.c_str());
242 usb_role_switch_done = false;
243 Return<void> ret = usb->switchRole(portBeingSwitched.c_str(), role);
244 ASSERT_TRUE(ret.isOk());
245
246 std::cv_status waitStatus = wait();
247 while (waitStatus == std::cv_status::no_timeout &&
248 usb_role_switch_done == false)
249 waitStatus = wait();
250
251 EXPECT_EQ(std::cv_status::no_timeout, waitStatus);
252 EXPECT_EQ(2, usb_last_cookie);
253
254 EXPECT_EQ(static_cast<uint32_t>(PortRoleType::MODE),
255 static_cast<uint32_t>(usb_last_port_role.type));
256 if (usb_last_status == Status::SUCCESS) {
257 EXPECT_EQ(static_cast<uint32_t>(PortMode::DFP),
258 static_cast<uint32_t>(usb_last_port_role.role));
259 } else {
260 EXPECT_NE(static_cast<uint32_t>(PortMode::UFP),
261 static_cast<uint32_t>(usb_last_port_role.role));
262 }
263 }
264 }
265
266 /*
267 * Test switching the power role of usb port.
268 * Test case queries the usb ports present in device.
269 * If there is atleast one usb port, a power role switch
270 * to SOURCE is attempted for the port.
271 * The callback parametes are checked to see if the power role
272 * switch was successfull. Upon success, Status::SUCCESS
273 * is expected to be returned.
274 */
275
TEST_F(UsbHidlTest,switchPowerRole)276 TEST_F(UsbHidlTest, switchPowerRole) {
277 struct PortRole role;
278 role.type = PortRoleType::POWER_ROLE;
279 role.role = static_cast<uint32_t>(PortPowerRole::SOURCE);
280
281 Return<void> ret = usb->queryPortStatus();
282 ASSERT_TRUE(ret.isOk());
283 EXPECT_EQ(std::cv_status::no_timeout, wait());
284 EXPECT_EQ(2, usb_last_cookie);
285
286 if (!usb_last_port_status.portName.empty()) {
287 hidl_string portBeingSwitched = usb_last_port_status.portName;
288 ALOGI("switchPower role portname:%s", portBeingSwitched.c_str());
289 usb_role_switch_done = false;
290 Return<void> ret = usb->switchRole(portBeingSwitched.c_str(), role);
291 ASSERT_TRUE(ret.isOk());
292
293 std::cv_status waitStatus = wait();
294 while (waitStatus == std::cv_status::no_timeout &&
295 usb_role_switch_done == false)
296 waitStatus = wait();
297
298 EXPECT_EQ(std::cv_status::no_timeout, waitStatus);
299 EXPECT_EQ(2, usb_last_cookie);
300
301 EXPECT_EQ(static_cast<uint32_t>(PortRoleType::POWER_ROLE),
302 static_cast<uint32_t>(usb_last_port_role.type));
303 if (usb_last_status == Status::SUCCESS) {
304 EXPECT_EQ(static_cast<uint32_t>(PortPowerRole::SOURCE),
305 static_cast<uint32_t>(usb_last_port_role.role));
306 } else {
307 EXPECT_NE(static_cast<uint32_t>(PortPowerRole::SINK),
308 static_cast<uint32_t>(usb_last_port_role.role));
309 }
310 }
311 }
312
313 /*
314 * Test switching the data role of usb port.
315 * Test case queries the usb ports present in device.
316 * If there is atleast one usb port, a power role switch
317 * to HOST is attempted for the port.
318 * The callback parametes are checked to see if the power role
319 * switch was successfull. Upon success, Status::SUCCESS
320 * is expected to be returned.
321 */
TEST_F(UsbHidlTest,switchDataRole)322 TEST_F(UsbHidlTest, switchDataRole) {
323 struct PortRole role;
324 role.type = PortRoleType::DATA_ROLE;
325 role.role = static_cast<uint32_t>(PortDataRole::HOST);
326
327 Return<void> ret = usb->queryPortStatus();
328 ASSERT_TRUE(ret.isOk());
329 EXPECT_EQ(std::cv_status::no_timeout, wait());
330 EXPECT_EQ(2, usb_last_cookie);
331
332 if (!usb_last_port_status.portName.empty()) {
333 hidl_string portBeingSwitched = usb_last_port_status.portName;
334 ALOGI("portname:%s", portBeingSwitched.c_str());
335 usb_role_switch_done = false;
336 Return<void> ret = usb->switchRole(portBeingSwitched.c_str(), role);
337 ASSERT_TRUE(ret.isOk());
338
339 std::cv_status waitStatus = wait();
340 while (waitStatus == std::cv_status::no_timeout &&
341 usb_role_switch_done == false)
342 waitStatus = wait();
343
344 EXPECT_EQ(std::cv_status::no_timeout, waitStatus);
345 EXPECT_EQ(2, usb_last_cookie);
346
347 EXPECT_EQ(static_cast<uint32_t>(PortRoleType::DATA_ROLE),
348 static_cast<uint32_t>(usb_last_port_role.type));
349 if (usb_last_status == Status::SUCCESS) {
350 EXPECT_EQ(static_cast<uint32_t>(PortDataRole::HOST),
351 static_cast<uint32_t>(usb_last_port_role.role));
352 } else {
353 EXPECT_NE(static_cast<uint32_t>(PortDataRole::DEVICE),
354 static_cast<uint32_t>(usb_last_port_role.role));
355 }
356 }
357 }
358
main(int argc,char ** argv)359 int main(int argc, char** argv) {
360 ::testing::AddGlobalTestEnvironment(UsbHidlEnvironment::Instance());
361 ::testing::InitGoogleTest(&argc, argv);
362 UsbHidlEnvironment::Instance()->init(&argc, argv);
363 int status = RUN_ALL_TESTS();
364 ALOGI("Test result = %d", status);
365 return status;
366 }
367