/* * Copyright (C) 2021 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 "nfc_aidl_hal_test" #include #include #include #include #include #include #include #include #include #include #include #include #include #include using aidl::android::hardware::nfc::INfc; using aidl::android::hardware::nfc::INfcClientCallback; using aidl::android::hardware::nfc::NfcCloseType; using aidl::android::hardware::nfc::NfcConfig; using aidl::android::hardware::nfc::NfcEvent; using aidl::android::hardware::nfc::NfcStatus; using aidl::android::hardware::nfc::PresenceCheckAlgorithm; using android::getAidlHalInstanceNames; using android::PrintInstanceNameToString; using android::base::StringPrintf; using ndk::enum_range; using ndk::ScopedAStatus; using ndk::SharedRefBase; using ndk::SpAIBinder; constexpr static int kCallbackTimeoutMs = 10000; // 261 bytes is the default and minimum transceive length constexpr unsigned int MIN_ISO_DEP_TRANSCEIVE_LENGTH = 261; // Range of valid off host route ids constexpr uint8_t MIN_OFFHOST_ROUTE_ID = 0x01; constexpr uint8_t MAX_OFFHOST_ROUTE_ID = 0xFE; class NfcClientCallback : public aidl::android::hardware::nfc::BnNfcClientCallback { public: NfcClientCallback(const std::function& on_hal_event_cb, const std::function&)>& on_nci_data_cb) : on_nci_data_cb_(on_nci_data_cb), on_hal_event_cb_(on_hal_event_cb) {} virtual ~NfcClientCallback() = default; ::ndk::ScopedAStatus sendEvent(NfcEvent event, NfcStatus event_status) override { on_hal_event_cb_(event, event_status); return ::ndk::ScopedAStatus::ok(); }; ::ndk::ScopedAStatus sendData(const std::vector& data) override { on_nci_data_cb_(data); return ::ndk::ScopedAStatus::ok(); }; private: std::function&)> on_nci_data_cb_; std::function on_hal_event_cb_; }; class NfcAidl : public testing::TestWithParam { public: void SetUp() override { SpAIBinder binder(AServiceManager_waitForService(GetParam().c_str())); infc_ = INfc::fromBinder(binder); ASSERT_NE(infc_, nullptr); } std::shared_ptr infc_; }; /* * OpenAndCloseForDisable: * Makes an open call, waits for NfcEvent::OPEN_CPLT * Immediately calls close(NfcCloseType::DISABLE) and * waits for NfcEvent::CLOSE_CPLT * */ TEST_P(NfcAidl, OpenAndCloseForDisable) { std::promise open_cb_promise; std::promise close_cb_promise; auto open_cb_future = open_cb_promise.get_future(); auto close_cb_future = close_cb_promise.get_future(); std::shared_ptr mCallback = ::ndk::SharedRefBase::make( [&open_cb_promise, &close_cb_promise](auto event, auto status) { EXPECT_EQ(status, NfcStatus::OK); LOG(INFO) << StringPrintf("%s,%d ", __func__, event); if (event == NfcEvent::OPEN_CPLT) open_cb_promise.set_value(); if (event == NfcEvent::CLOSE_CPLT) close_cb_promise.set_value(); }, [](auto) {}); std::chrono::milliseconds timeout{kCallbackTimeoutMs}; // Open and wait for OPEN_CPLT LOG(INFO) << "open"; EXPECT_TRUE(infc_->open(mCallback).isOk()); EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready); // Close and wait for CLOSE_CPLT LOG(INFO) << "close DISABLE"; EXPECT_TRUE(infc_->close(NfcCloseType::DISABLE).isOk()); LOG(INFO) << "wait for close"; EXPECT_EQ(close_cb_future.wait_for(timeout), std::future_status::ready); } /* * OpenAndCloseForHostSwitchedOff: * Makes an open call, waits for NfcEvent::OPEN_CPLT * Immediately calls close(NfcCloseType::HOST_SWITCHED_OFF) and * waits for NfcEvent::CLOSE_CPLT * */ TEST_P(NfcAidl, OpenAndCloseForHostSwitchedOff) { std::promise open_cb_promise; std::promise close_cb_promise; auto open_cb_future = open_cb_promise.get_future(); auto close_cb_future = close_cb_promise.get_future(); std::shared_ptr mCallback = ::ndk::SharedRefBase::make( [&open_cb_promise, &close_cb_promise](auto event, auto status) { EXPECT_EQ(status, NfcStatus::OK); if (event == NfcEvent::OPEN_CPLT) open_cb_promise.set_value(); if (event == NfcEvent::CLOSE_CPLT) close_cb_promise.set_value(); }, [](auto) {}); std::chrono::milliseconds timeout{kCallbackTimeoutMs}; // Open and wait for OPEN_CPLT LOG(INFO) << "open"; EXPECT_TRUE(infc_->open(mCallback).isOk()); EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready); // Close and wait for CLOSE_CPLT LOG(INFO) << "close HOST_SWITCHED_OFF"; EXPECT_TRUE(infc_->close(NfcCloseType::HOST_SWITCHED_OFF).isOk()); EXPECT_EQ(close_cb_future.wait_for(timeout), std::future_status::ready); } /* * OpenAfterOpen: * Calls open() multiple times * Checks status */ TEST_P(NfcAidl, OpenAfterOpen) { int open_count = 0; std::promise open_cb_promise; std::promise open2_cb_promise; auto open_cb_future = open_cb_promise.get_future(); auto open2_cb_future = open2_cb_promise.get_future(); std::shared_ptr mCallback = ::ndk::SharedRefBase::make( [&open_cb_promise, &open2_cb_promise, &open_count](auto event, auto status) { EXPECT_EQ(status, NfcStatus::OK); if (event == NfcEvent::OPEN_CPLT) { open_count == 0 ? open_cb_promise.set_value() : open2_cb_promise.set_value(); open_count++; } }, [](auto) {}); std::chrono::milliseconds timeout{kCallbackTimeoutMs}; // Open and wait for OPEN_CPLT LOG(INFO) << "open"; EXPECT_TRUE(infc_->open(mCallback).isOk()); EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready); // Open again and wait for OPEN_CPLT LOG(INFO) << "open again"; EXPECT_TRUE(infc_->open(mCallback).isOk()); EXPECT_EQ(open2_cb_future.wait_for(timeout), std::future_status::ready); } /* * CloseAfterClose: * Calls close() multiple times * Checks status */ TEST_P(NfcAidl, CloseAfterClose) { std::promise open_cb_promise; std::promise close_cb_promise; auto open_cb_future = open_cb_promise.get_future(); auto close_cb_future = close_cb_promise.get_future(); std::shared_ptr mCallback = ::ndk::SharedRefBase::make( [&open_cb_promise, &close_cb_promise](auto event, auto status) { EXPECT_EQ(status, NfcStatus::OK); if (event == NfcEvent::OPEN_CPLT) open_cb_promise.set_value(); if (event == NfcEvent::CLOSE_CPLT) close_cb_promise.set_value(); }, [](auto) {}); std::chrono::milliseconds timeout{kCallbackTimeoutMs}; // Open and wait for OPEN_CPLT LOG(INFO) << "open"; EXPECT_TRUE(infc_->open(mCallback).isOk()); EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready); // Close and wait for CLOSE_CPLT LOG(INFO) << "close"; EXPECT_TRUE(infc_->close(NfcCloseType::DISABLE).isOk()); EXPECT_EQ(close_cb_future.wait_for(timeout), std::future_status::ready); // Close again should fail. LOG(INFO) << "close again"; EXPECT_TRUE(!(infc_->close(NfcCloseType::DISABLE).isOk())); } /* * PowerCycleAfterOpen: * Calls powerCycle() after open * Waits for NfcEvent.OPEN_CPLT * Checks status */ TEST_P(NfcAidl, PowerCycleAfterOpen) { int open_cplt_count = 0; std::promise open_cb_promise; std::promise power_cycle_cb_promise; std::promise close_cb_promise; auto open_cb_future = open_cb_promise.get_future(); auto power_cycle_cb_future = power_cycle_cb_promise.get_future(); auto close_cb_future = close_cb_promise.get_future(); std::shared_ptr mCallback = ::ndk::SharedRefBase::make( [&open_cb_promise, &close_cb_promise, &power_cycle_cb_promise, &open_cplt_count]( auto event, auto status) { EXPECT_EQ(status, NfcStatus::OK); if (event == NfcEvent::OPEN_CPLT) { if (open_cplt_count == 0) { open_cplt_count++; open_cb_promise.set_value(); } else { power_cycle_cb_promise.set_value(); } } if (event == NfcEvent::CLOSE_CPLT) close_cb_promise.set_value(); }, [](auto) {}); std::chrono::milliseconds timeout{kCallbackTimeoutMs}; // Open and wait for OPEN_CPLT LOG(INFO) << "open"; EXPECT_TRUE(infc_->open(mCallback).isOk()); EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready); // PowerCycle and wait for OPEN_CPLT LOG(INFO) << "PowerCycle"; EXPECT_TRUE(infc_->powerCycle().isOk()); EXPECT_EQ(power_cycle_cb_future.wait_for(timeout), std::future_status::ready); // Close and wait for CLOSE_CPLT LOG(INFO) << "close"; EXPECT_TRUE(infc_->close(NfcCloseType::DISABLE).isOk()); EXPECT_EQ(close_cb_future.wait_for(timeout), std::future_status::ready); } /* * PowerCycleAfterClose: * Calls powerCycle() after close * PowerCycle should fail immediately */ TEST_P(NfcAidl, PowerCycleAfterClose) { std::promise open_cb_promise; std::promise close_cb_promise; auto open_cb_future = open_cb_promise.get_future(); auto close_cb_future = close_cb_promise.get_future(); std::shared_ptr mCallback = ::ndk::SharedRefBase::make( [&open_cb_promise, &close_cb_promise](auto event, auto status) { EXPECT_EQ(status, NfcStatus::OK); if (event == NfcEvent::OPEN_CPLT) open_cb_promise.set_value(); if (event == NfcEvent::CLOSE_CPLT) close_cb_promise.set_value(); }, [](auto) {}); std::chrono::milliseconds timeout{kCallbackTimeoutMs}; // Open and wait for OPEN_CPLT LOG(INFO) << "open"; EXPECT_TRUE(infc_->open(mCallback).isOk()); EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready); // Close and wait for CLOSE_CPLT LOG(INFO) << "close"; EXPECT_TRUE(infc_->close(NfcCloseType::DISABLE).isOk()); EXPECT_EQ(close_cb_future.wait_for(timeout), std::future_status::ready); // PowerCycle should fail LOG(INFO) << "PowerCycle"; EXPECT_TRUE(!(infc_->powerCycle().isOk())); } /* * CoreInitializedAfterOpen: * Calls coreInitialized() after open * Waits for NfcEvent.POST_INIT_CPLT */ TEST_P(NfcAidl, CoreInitializedAfterOpen) { std::promise open_cb_promise; std::promise core_init_cb_promise; std::promise close_cb_promise; auto open_cb_future = open_cb_promise.get_future(); auto core_init_cb_future = core_init_cb_promise.get_future(); auto close_cb_future = close_cb_promise.get_future(); std::shared_ptr mCallback = ::ndk::SharedRefBase::make( [&open_cb_promise, &close_cb_promise, &core_init_cb_promise](auto event, auto status) { EXPECT_EQ(status, NfcStatus::OK); if (event == NfcEvent::OPEN_CPLT) open_cb_promise.set_value(); if (event == NfcEvent::POST_INIT_CPLT) core_init_cb_promise.set_value(); if (event == NfcEvent::CLOSE_CPLT) close_cb_promise.set_value(); }, [](auto) {}); std::chrono::milliseconds timeout{kCallbackTimeoutMs}; // Open and wait for OPEN_CPLT LOG(INFO) << "open"; EXPECT_TRUE(infc_->open(mCallback).isOk()); EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready); // CoreInitialized and wait for POST_INIT_CPLT LOG(INFO) << "coreInitialized"; EXPECT_TRUE(infc_->coreInitialized().isOk()); EXPECT_EQ(core_init_cb_future.wait_for(timeout), std::future_status::ready); // Close and wait for CLOSE_CPLT LOG(INFO) << "close"; EXPECT_TRUE(infc_->close(NfcCloseType::DISABLE).isOk()); EXPECT_EQ(close_cb_future.wait_for(timeout), std::future_status::ready); } /* * CoreInitializedAfterClose: * Calls coreInitialized() after close * coreInitialized() should fail immediately */ TEST_P(NfcAidl, CoreInitializedAfterClose) { std::promise open_cb_promise; std::promise close_cb_promise; auto open_cb_future = open_cb_promise.get_future(); auto close_cb_future = close_cb_promise.get_future(); std::shared_ptr mCallback = ::ndk::SharedRefBase::make( [&open_cb_promise, &close_cb_promise](auto event, auto status) { EXPECT_EQ(status, NfcStatus::OK); if (event == NfcEvent::OPEN_CPLT) open_cb_promise.set_value(); if (event == NfcEvent::CLOSE_CPLT) close_cb_promise.set_value(); }, [](auto) {}); std::chrono::milliseconds timeout{kCallbackTimeoutMs}; // Open and wait for OPEN_CPLT LOG(INFO) << "open"; EXPECT_TRUE(infc_->open(mCallback).isOk()); EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready); // Close and wait for CLOSE_CPLT LOG(INFO) << "close"; EXPECT_TRUE(infc_->close(NfcCloseType::DISABLE).isOk()); EXPECT_EQ(close_cb_future.wait_for(timeout), std::future_status::ready); // coreInitialized should fail LOG(INFO) << "CoreInitialized"; EXPECT_TRUE(!(infc_->coreInitialized().isOk())); } /* * PreDiscoverAfterClose: * Call preDiscover() after close * preDiscover() should fail immediately */ TEST_P(NfcAidl, PreDiscoverAfterClose) { std::promise open_cb_promise; std::promise close_cb_promise; auto open_cb_future = open_cb_promise.get_future(); auto close_cb_future = close_cb_promise.get_future(); std::shared_ptr mCallback = ::ndk::SharedRefBase::make( [&open_cb_promise, &close_cb_promise](auto event, auto status) { EXPECT_EQ(status, NfcStatus::OK); if (event == NfcEvent::OPEN_CPLT) open_cb_promise.set_value(); if (event == NfcEvent::CLOSE_CPLT) close_cb_promise.set_value(); }, [](auto) {}); std::chrono::milliseconds timeout{kCallbackTimeoutMs}; // Open and wait for OPEN_CPLT LOG(INFO) << "open"; EXPECT_TRUE(infc_->open(mCallback).isOk()); EXPECT_EQ(open_cb_future.wait_for(timeout), std::future_status::ready); // Close and wait for CLOSE_CPLT LOG(INFO) << "close"; EXPECT_TRUE(infc_->close(NfcCloseType::DISABLE).isOk()); EXPECT_EQ(close_cb_future.wait_for(timeout), std::future_status::ready); // preDiscover should fail LOG(INFO) << "preDiscover"; EXPECT_TRUE(!(infc_->preDiscover().isOk())); } /* * checkGetConfigValues: * Calls getConfig() * checks if fields in NfcConfig are populated correctly */ TEST_P(NfcAidl, CheckGetConfigValues) { NfcConfig configValue; EXPECT_TRUE(infc_->getConfig(&configValue).isOk()); EXPECT_GE(configValue.maxIsoDepTransceiveLength, MIN_ISO_DEP_TRANSCEIVE_LENGTH); LOG(INFO) << StringPrintf("configValue.maxIsoDepTransceiveLength = %x", configValue.maxIsoDepTransceiveLength); for (auto uicc : configValue.offHostRouteUicc) { LOG(INFO) << StringPrintf("offHostRouteUicc = %x", uicc); EXPECT_GE(uicc, MIN_OFFHOST_ROUTE_ID); EXPECT_LE(uicc, MAX_OFFHOST_ROUTE_ID); } for (auto ese : configValue.offHostRouteEse) { LOG(INFO) << StringPrintf("offHostRouteEse = %x", ese); EXPECT_GE(ese, MIN_OFFHOST_ROUTE_ID); EXPECT_LE(ese, MAX_OFFHOST_ROUTE_ID); } if (configValue.defaultIsoDepRoute != 0) { EXPECT_GE((uint8_t)configValue.defaultIsoDepRoute, MIN_OFFHOST_ROUTE_ID); EXPECT_LE((uint8_t)configValue.defaultIsoDepRoute, MAX_OFFHOST_ROUTE_ID); } for (auto simPipeId : configValue.offHostSimPipeIds) { LOG(INFO) << StringPrintf("offHostSimPipeId= %x", simPipeId); EXPECT_GE(simPipeId, MIN_OFFHOST_ROUTE_ID); EXPECT_LE(simPipeId, MAX_OFFHOST_ROUTE_ID); } } /* * CheckisVerboseLoggingEnabledAfterSetEnableVerboseLogging: * Calls setEnableVerboseLogging() * checks the return value of isVerboseLoggingEnabled */ TEST_P(NfcAidl, CheckisVerboseLoggingEnabledAfterSetEnableVerboseLogging) { bool enabled = false; EXPECT_TRUE(infc_->setEnableVerboseLogging(true).isOk()); EXPECT_TRUE(infc_->isVerboseLoggingEnabled(&enabled).isOk()); EXPECT_TRUE(enabled); EXPECT_TRUE(infc_->setEnableVerboseLogging(false).isOk()); EXPECT_TRUE(infc_->isVerboseLoggingEnabled(&enabled).isOk()); EXPECT_TRUE(!enabled); } TEST_P(NfcAidl, CheckControlGrantedStatus) { int interface_version; EXPECT_TRUE(infc_->getInterfaceVersion(&interface_version).isOk()); if (interface_version > 1) { NfcStatus status; EXPECT_TRUE(infc_->controlGranted(&status).isOk()); EXPECT_EQ(status, NfcStatus::OK); } } GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(NfcAidl); INSTANTIATE_TEST_SUITE_P(Nfc, NfcAidl, testing::ValuesIn(::android::getAidlHalInstanceNames(INfc::descriptor)), ::android::PrintInstanceNameToString); int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); ABinderProcess_startThreadPool(); std::system("/system/bin/svc nfc disable"); /* Turn off NFC */ sleep(5); int status = RUN_ALL_TESTS(); LOG(INFO) << "Test result = " << status; std::system("/system/bin/svc nfc enable"); /* Turn on NFC */ sleep(5); return status; }