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