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