/* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "VtsHalUsbV1_2TargetTest" #include #include #include #include #include #include #include #include #include #include #include #include using ::android::sp; using ::android::hardware::hidl_array; using ::android::hardware::hidl_memory; using ::android::hardware::hidl_string; using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; using ::android::hardware::usb::V1_0::PortDataRole; using ::android::hardware::usb::V1_0::PortMode; using ::android::hardware::usb::V1_0::PortPowerRole; using ::android::hardware::usb::V1_0::PortRole; using ::android::hardware::usb::V1_0::PortRoleType; using ::android::hardware::usb::V1_0::Status; using ::android::hardware::usb::V1_1::PortMode_1_1; using ::android::hardware::usb::V1_1::PortStatus_1_1; using ::android::hardware::usb::V1_2::ContaminantDetectionStatus; using ::android::hardware::usb::V1_2::ContaminantProtectionMode; using ::android::hardware::usb::V1_2::ContaminantProtectionStatus; using ::android::hardware::usb::V1_2::IUsb; using ::android::hardware::usb::V1_2::IUsbCallback; using ::android::hardware::usb::V1_2::PortStatus; using ::android::hidl::base::V1_0::IBase; constexpr char kCallbackNameNotifyPortStatusChange_1_2[] = "notifyPortStatusChange_1_2"; const int kCallbackIdentifier = 2; // Worst case wait time 20secs #define WAIT_FOR_TIMEOUT std::chrono::milliseconds(20000) class UsbClientCallbackArgs { public: // The last conveyed status of the USB ports. // Stores information of currentt_data_role, power_role for all the USB ports PortStatus usb_last_port_status; // Status of the last role switch operation. Status usb_last_status; // Identifier for the usb callback object. // Stores the cookie of the last invoked usb callback object. int last_usb_cookie; }; // Callback class for the USB HIDL hal. // Usb Hal will call this object upon role switch or port query. class UsbCallback : public ::testing::VtsHalHidlTargetCallbackBase, public IUsbCallback { int cookie; public: UsbCallback(int cookie) : cookie(cookie){}; virtual ~UsbCallback() = default; // V1_0 Callback method for the port status. // This should not be called so not signalling the Test here assuming that // the test thread will timeout Return notifyPortStatusChange(const hidl_vec& /* currentPortStatus */, Status /* retval */) override { return Void(); }; // V1_1 Callback method for the port status. // This should not be called so not signalling the Test here assuming that // the test thread will timeout Return notifyPortStatusChange_1_1(const hidl_vec& /* currentPortStatus */, Status /* retval */) override { return Void(); } // This callback method should be used. Return notifyPortStatusChange_1_2(const hidl_vec& currentPortStatus, Status retval) override { UsbClientCallbackArgs arg; if (retval == Status::SUCCESS) { arg.usb_last_port_status.status_1_1.status.supportedModes = currentPortStatus[0].status_1_1.status.supportedModes; arg.usb_last_port_status.status_1_1.status.currentMode = currentPortStatus[0].status_1_1.status.currentMode; arg.usb_last_port_status.status_1_1.status.portName = currentPortStatus[0].status_1_1.status.portName; arg.usb_last_port_status.contaminantDetectionStatus = currentPortStatus[0].contaminantDetectionStatus; arg.usb_last_port_status.contaminantProtectionStatus = currentPortStatus[0].contaminantProtectionStatus; arg.usb_last_port_status.supportsEnableContaminantPresenceProtection = currentPortStatus[0].supportsEnableContaminantPresenceProtection; arg.usb_last_port_status.supportsEnableContaminantPresenceDetection = currentPortStatus[0].supportsEnableContaminantPresenceDetection; arg.usb_last_port_status.supportedContaminantProtectionModes = currentPortStatus[0].supportedContaminantProtectionModes; } arg.usb_last_status = retval; arg.last_usb_cookie = cookie; NotifyFromCallback(kCallbackNameNotifyPortStatusChange_1_2, arg); return Void(); } // Callback method for the status of role switch operation. // RoleSwitch operation has not changed since V1_0 so leaving // the callback blank here. Return notifyRoleSwitchStatus(const hidl_string& /*portName*/, const PortRole& /*newRole*/, Status /*retval*/) override { return Void(); }; }; // Test environment for Usb HIDL HAL. class UsbHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { public: // get the test environment singleton static UsbHidlEnvironment* Instance() { static UsbHidlEnvironment* instance = new UsbHidlEnvironment; return instance; } virtual void registerTestServices() override { registerTestService(); } }; // The main test class for the USB hidl HAL class UsbHidlTest : public ::testing::VtsHalHidlTargetTestBase { public: virtual void SetUp() override { ALOGI(__FUNCTION__); usb = ::testing::VtsHalHidlTargetTestBase::getService(); ASSERT_NE(usb, nullptr); usb_cb_2 = new UsbCallback(kCallbackIdentifier); ASSERT_NE(usb_cb_2, nullptr); usb_cb_2->SetWaitTimeout(kCallbackNameNotifyPortStatusChange_1_2, WAIT_FOR_TIMEOUT); Return ret = usb->setCallback(usb_cb_2); ASSERT_TRUE(ret.isOk()); } virtual void TearDown() override { ALOGI("Teardown"); } // USB hidl hal Proxy sp usb; // Callback objects for usb hidl // Methods of these objects are called to notify port status updates. sp usb_cb_1; sp usb_cb_2; }; /* * Test to see if setCallback on V1_1 callback object succeeds. * Callback oject is created and registered. * Check to see if the hidl transaction succeeded. */ TEST_F(UsbHidlTest, setCallback) { usb_cb_1 = new UsbCallback(1); ASSERT_NE(usb_cb_1, nullptr); Return ret = usb->setCallback(usb_cb_1); ASSERT_TRUE(ret.isOk()); } /* * Check to see if querying type-c * port status succeeds. * HAL service should call notifyPortStatusChange_1_2 * instead of notifyPortStatusChange of V1_0/V1_1 interface */ TEST_F(UsbHidlTest, queryPortStatus) { Return ret = usb->queryPortStatus(); ASSERT_TRUE(ret.isOk()); auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); EXPECT_TRUE(res.no_timeout); EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); EXPECT_EQ(PortMode::NONE, res.args->usb_last_port_status.status_1_1.status.currentMode); EXPECT_EQ(PortMode::NONE, res.args->usb_last_port_status.status_1_1.status.supportedModes); EXPECT_EQ(Status::SUCCESS, res.args->usb_last_status); } /* * supportedContaminantProtectionModes is immutable. * Check if supportedContaminantProtectionModes changes across queryPortStatus * call. */ TEST_F(UsbHidlTest, checkSupportedContaminantProtectionModes) { Return ret = usb->queryPortStatus(); ASSERT_TRUE(ret.isOk()); auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); EXPECT_TRUE(res.no_timeout); EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); EXPECT_EQ(PortMode::NONE, res.args->usb_last_port_status.status_1_1.status.currentMode); EXPECT_EQ(PortMode::NONE, res.args->usb_last_port_status.status_1_1.status.supportedModes); EXPECT_EQ(Status::SUCCESS, res.args->usb_last_status); uint32_t supportedContaminantProtectionModes = static_cast( res.args->usb_last_port_status.supportedContaminantProtectionModes); for (int runs = 1; runs <= 10; runs++) { ret = usb->queryPortStatus(); ASSERT_TRUE(ret.isOk()); res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); EXPECT_TRUE(res.no_timeout); EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); EXPECT_EQ(PortMode::NONE, res.args->usb_last_port_status.status_1_1.status.currentMode); EXPECT_EQ(PortMode::NONE, res.args->usb_last_port_status.status_1_1.status.supportedModes); EXPECT_EQ(Status::SUCCESS, res.args->usb_last_status); EXPECT_EQ(supportedContaminantProtectionModes, static_cast( res.args->usb_last_port_status.supportedContaminantProtectionModes)); } } /* * When supportsEnableContaminantPresenceDetection is set false, * enableContaminantPresenceDetection should not enable/disable * contaminantPresenceProtection. */ TEST_F(UsbHidlTest, presenceDetectionSupportedCheck) { Return ret = usb->queryPortStatus(); ASSERT_TRUE(ret.isOk()); auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); EXPECT_TRUE(res.no_timeout); EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); EXPECT_EQ(Status::SUCCESS, res.args->usb_last_status); if (!res.args->usb_last_port_status.supportsEnableContaminantPresenceDetection) { for (int runs = 1; runs <= 10; runs++) { bool currentStatus = !(res.args->usb_last_port_status.contaminantDetectionStatus == ContaminantDetectionStatus::DISABLED); ret = usb->enableContaminantPresenceDetection( res.args->usb_last_port_status.status_1_1.status.portName, !currentStatus); ASSERT_TRUE(ret.isOk()); res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); EXPECT_TRUE(res.no_timeout); EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); EXPECT_EQ(currentStatus, !(res.args->usb_last_port_status.contaminantDetectionStatus == ContaminantDetectionStatus::DISABLED)); } } } /* * enableContaminantPresenceDetection should succeed atleast 90% when supported. */ TEST_F(UsbHidlTest, contaminantPresenceDetectionStability) { int successCount = 0; bool currentStatus; bool supported = true; Return ret = usb->queryPortStatus(); ASSERT_TRUE(ret.isOk()); auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); EXPECT_TRUE(res.no_timeout); EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); EXPECT_EQ(Status::SUCCESS, res.args->usb_last_status); if (!res.args->usb_last_port_status.supportsEnableContaminantPresenceDetection) return; for (int count = 1; count <= 10; count++) { currentStatus = !(res.args->usb_last_port_status.contaminantDetectionStatus == ContaminantDetectionStatus::DISABLED); ret = usb->enableContaminantPresenceDetection( res.args->usb_last_port_status.status_1_1.status.portName, !currentStatus); ASSERT_TRUE(ret.isOk()); res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); EXPECT_TRUE(res.no_timeout); EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); if (!currentStatus == !(res.args->usb_last_port_status.contaminantDetectionStatus == ContaminantDetectionStatus::DISABLED)) successCount++; } if (!supported) EXPECT_GE(successCount, 9); } /* * When supportsEnableContaminantPresenceProtection is set false, * enableContaminantPresenceProtection should not enable/disable * contaminantPresenceProtection. */ TEST_F(UsbHidlTest, presenceProtectionSupportedCheck) { Return ret = usb->queryPortStatus(); ASSERT_TRUE(ret.isOk()); auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); EXPECT_TRUE(res.no_timeout); EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); EXPECT_EQ(Status::SUCCESS, res.args->usb_last_status); if (!res.args->usb_last_port_status.supportsEnableContaminantPresenceProtection) { for (int runs = 1; runs <= 10; runs++) { bool currentStatus = !(res.args->usb_last_port_status.contaminantProtectionStatus == ContaminantProtectionStatus::DISABLED); ret = usb->enableContaminantPresenceProtection( res.args->usb_last_port_status.status_1_1.status.portName, !currentStatus); ASSERT_TRUE(ret.isOk()); res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); EXPECT_TRUE(res.no_timeout); EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); EXPECT_EQ(currentStatus, !(res.args->usb_last_port_status.contaminantProtectionStatus == ContaminantProtectionStatus::DISABLED)); } } } /* * enableContaminantPresenceProtection should succeed atleast 90% when supported. */ TEST_F(UsbHidlTest, contaminantPresenceProtectionStability) { int successCount = 0; bool currentStatus; bool supported = true; Return ret = usb->queryPortStatus(); ASSERT_TRUE(ret.isOk()); auto res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); EXPECT_TRUE(res.no_timeout); EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); EXPECT_EQ(Status::SUCCESS, res.args->usb_last_status); if (!res.args->usb_last_port_status.supportsEnableContaminantPresenceProtection) return; for (int count = 1; count <= 10; count++) { currentStatus = !(res.args->usb_last_port_status.contaminantProtectionStatus == ContaminantProtectionStatus::DISABLED); ret = usb->enableContaminantPresenceProtection( res.args->usb_last_port_status.status_1_1.status.portName, !currentStatus); ASSERT_TRUE(ret.isOk()); res = usb_cb_2->WaitForCallback(kCallbackNameNotifyPortStatusChange_1_2); EXPECT_TRUE(res.no_timeout); EXPECT_EQ(kCallbackIdentifier, res.args->last_usb_cookie); if (!currentStatus == !(res.args->usb_last_port_status.contaminantProtectionStatus == ContaminantProtectionStatus::DISABLED)) successCount++; } if (!supported) EXPECT_GE(successCount, 9); } int main(int argc, char** argv) { ::testing::AddGlobalTestEnvironment(UsbHidlEnvironment::Instance()); ::testing::InitGoogleTest(&argc, argv); UsbHidlEnvironment::Instance()->init(&argc, argv); int status = RUN_ALL_TESTS(); ALOGI("Test result = %d", status); return status; }