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