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