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