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