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 34using ::android::hardware::usb::V1_0::IUsbCallback; 35using ::android::hardware::usb::V1_0::IUsb; 36using ::android::hardware::usb::V1_0::PortDataRole; 37using ::android::hardware::usb::V1_0::PortMode; 38using ::android::hardware::usb::V1_0::PortPowerRole; 39using ::android::hardware::usb::V1_0::PortRole; 40using ::android::hardware::usb::V1_0::PortRoleType; 41using ::android::hardware::usb::V1_0::PortStatus; 42using ::android::hardware::usb::V1_0::Status; 43using ::android::hidl::base::V1_0::IBase; 44using ::android::hardware::hidl_array; 45using ::android::hardware::hidl_memory; 46using ::android::hardware::hidl_string; 47using ::android::hardware::hidl_vec; 48using ::android::hardware::Return; 49using ::android::hardware::Void; 50using ::android::sp; 51 52// Test environment for Usb HIDL HAL. 53class UsbHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { 54 public: 55 // get the test environment singleton 56 static UsbHidlEnvironment* Instance() { 57 static UsbHidlEnvironment* instance = new UsbHidlEnvironment; 58 return instance; 59 } 60 61 virtual void registerTestServices() override { registerTestService<IUsb>(); } 62}; 63 64// The main test class for the USB hidl HAL 65class 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: 74 UsbCallback(UsbHidlTest& parent, int cookie) 75 : parent_(parent), cookie(cookie){}; 76 77 virtual ~UsbCallback() = default; 78 79 // Callback method for the port status. 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. 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 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 122 virtual void TearDown() override { ALOGI("Teardown"); } 123 124 // Used as a mechanism to inform the test about data/event callback. 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. 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 */ 185TEST_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 */ 196TEST_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 */ 209TEST_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 */ 229TEST_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 276TEST_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 */ 322TEST_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 359int 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