Home | History | Annotate | Download | only in functional
      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
     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
     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:
     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  */
    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  */
    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  */
    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  */
    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 
    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  */
    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 
    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