/* * Copyright (C) 2024 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_behavior_changes_test" #include <aidl/Gtest.h> #include <aidl/Vintf.h> #include <aidl/android/hardware/nfc/BnNfc.h> #include <aidl/android/hardware/nfc/INfc.h> #include <android-base/logging.h> #include <android-base/stringprintf.h> #include <android/binder_process.h> #include <gtest/gtest.h> #include <chrono> #include <future> #include "NfcAdaptation.h" #include "SyncEvent.h" #include "nci_defs.h" #include "nfa_api.h" #include "nfa_ee_api.h" using aidl::android::hardware::nfc::INfc; using android::getAidlHalInstanceNames; using android::PrintInstanceNameToString; using android::base::StringPrintf; static SyncEvent sNfaEnableEvent; // event for NFA_Enable() static SyncEvent sNfaVsCommand; // event for VS commands static SyncEvent sNfaEnableDisablePollingEvent; static SyncEvent sNfaPowerChangeEvent; static bool sIsNfaEnabled; static tNFA_STATUS sVSCmdStatus; static void nfaDeviceManagementCallback(uint8_t dmEvent, tNFA_DM_CBACK_DATA* eventData) { LOG(DEBUG) << StringPrintf("%s: enter; event=0x%X", __func__, dmEvent); switch (dmEvent) { case NFA_DM_ENABLE_EVT: /* Result of NFA_Enable */ { SyncEventGuard guard(sNfaEnableEvent); LOG(DEBUG) << StringPrintf("%s: NFA_DM_ENABLE_EVT; status=0x%X", __func__, eventData->status); sIsNfaEnabled = eventData->status == NFA_STATUS_OK; sNfaEnableEvent.notifyOne(); } break; case NFA_DM_DISABLE_EVT: /* Result of NFA_Disable */ { SyncEventGuard guard(sNfaEnableEvent); LOG(DEBUG) << StringPrintf("%s: NFA_DM_DISABLE_EVT; status=0x%X", __func__, eventData->status); sIsNfaEnabled = eventData->status == NFA_STATUS_OK; sNfaEnableEvent.notifyOne(); } break; case NFA_DM_PWR_MODE_CHANGE_EVT: { SyncEventGuard guard(sNfaPowerChangeEvent); LOG(DEBUG) << StringPrintf( "%s: NFA_DM_PWR_MODE_CHANGE_EVT: status=0x%X, power_mode=0x%X", __func__, eventData->status, eventData->power_mode.power_mode); sNfaPowerChangeEvent.notifyOne(); } break; } } static void nfaConnectionCallback(uint8_t connEvent, tNFA_CONN_EVT_DATA* eventData) { LOG(DEBUG) << StringPrintf("%s: event= %u", __func__, connEvent); switch (connEvent) { case NFA_LISTEN_DISABLED_EVT: { SyncEventGuard guard(sNfaEnableDisablePollingEvent); sNfaEnableDisablePollingEvent.notifyOne(); } break; case NFA_LISTEN_ENABLED_EVT: { SyncEventGuard guard(sNfaEnableDisablePollingEvent); sNfaEnableDisablePollingEvent.notifyOne(); } break; case NFA_RF_DISCOVERY_STARTED_EVT: // RF Discovery started { LOG(DEBUG) << StringPrintf("%s: NFA_RF_DISCOVERY_STARTED_EVT: status = %u", __func__, eventData->status); SyncEventGuard guard(sNfaEnableDisablePollingEvent); sNfaEnableDisablePollingEvent.notifyOne(); } break; case NFA_RF_DISCOVERY_STOPPED_EVT: // RF Discovery stopped event { LOG(DEBUG) << StringPrintf("%s: NFA_RF_DISCOVERY_STOPPED_EVT: status = %u", __func__, eventData->status); SyncEventGuard guard(sNfaEnableDisablePollingEvent); sNfaEnableDisablePollingEvent.notifyOne(); } break; } } void static nfaVSCallback(uint8_t event, uint16_t /* param_len */, uint8_t* p_param) { switch (event & NCI_OID_MASK) { case NCI_MSG_PROP_ANDROID: { uint8_t android_sub_opcode = p_param[3]; switch (android_sub_opcode) { case NCI_ANDROID_PASSIVE_OBSERVE: { sVSCmdStatus = p_param[4]; LOG(INFO) << StringPrintf("Observe mode RSP: status: %x", sVSCmdStatus); SyncEventGuard guard(sNfaVsCommand); sNfaVsCommand.notifyOne(); } break; case NCI_ANDROID_POLLING_FRAME_NTF: { // TODO } break; default: LOG(WARNING) << StringPrintf("Unknown Android sub opcode %x", android_sub_opcode); } } break; default: break; } } /* * Enable passive observe mode. */ tNFA_STATUS static nfaObserveModeEnable(bool enable) { tNFA_STATUS status = NFA_STATUS_FAILED; status = NFA_StopRfDiscovery(); if (status == NFA_STATUS_OK) { if (!sNfaEnableDisablePollingEvent.wait(1000)) { LOG(WARNING) << "Timeout waiting to disable NFC RF discovery"; return NFA_STATUS_TIMEOUT; } } uint8_t cmd[] = {(NCI_MT_CMD << NCI_MT_SHIFT) | NCI_GID_PROP, NCI_MSG_PROP_ANDROID, NCI_ANDROID_PASSIVE_OBSERVE_PARAM_SIZE, NCI_ANDROID_PASSIVE_OBSERVE, static_cast<uint8_t>(enable ? NCI_ANDROID_PASSIVE_OBSERVE_PARAM_ENABLE : NCI_ANDROID_PASSIVE_OBSERVE_PARAM_DISABLE)}; status = NFA_SendRawVsCommand(sizeof(cmd), cmd, nfaVSCallback); if (status == NFA_STATUS_OK) { if (!sNfaVsCommand.wait(1000)) { LOG(WARNING) << "Timeout waiting for NFA VS command response"; return NFA_STATUS_TIMEOUT; } } return status; } class NfcBehaviorChanges : public testing::TestWithParam<std::string> { protected: void SetUp() override { tNFA_STATUS status = NFA_STATUS_OK; sIsNfaEnabled = false; sVSCmdStatus = NFA_STATUS_OK; NfcAdaptation& theInstance = NfcAdaptation::GetInstance(); theInstance.Initialize(); // start GKI, NCI task, NFC task { SyncEventGuard guard(sNfaEnableEvent); tHAL_NFC_ENTRY* halFuncEntries = theInstance.GetHalEntryFuncs(); NFA_Init(halFuncEntries); status = NFA_Enable(nfaDeviceManagementCallback, nfaConnectionCallback); ASSERT_EQ(status, NFA_STATUS_OK); // wait for NFA command to finish ASSERT_TRUE(sNfaEnableEvent.wait(1000)) << "Timeout waiting for NFA command on NFA_Enable"; } ASSERT_TRUE(sIsNfaEnabled) << "Could not initialize NFC controller"; status = NFA_StartRfDiscovery(); ASSERT_EQ(status, NFA_STATUS_OK); ASSERT_TRUE(sNfaEnableDisablePollingEvent.wait(1000)) << "Timeout starting RF discovery"; } }; /* * ObserveModeEnable: * Attempts to enable observe mode. Does not test Observe Mode functionality, * but simply verifies that the enable command responds successfully. * * @VsrTest = GMS-VSR-3.2.8-001 */ TEST_P(NfcBehaviorChanges, ObserveModeEnableDisable) { tNFA_STATUS status = nfaObserveModeEnable(true); ASSERT_EQ(status, NFA_STATUS_OK); status = nfaObserveModeEnable(false); ASSERT_EQ(status, NFA_STATUS_OK); } GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(NfcBehaviorChanges); INSTANTIATE_TEST_SUITE_P(Nfc, NfcBehaviorChanges, 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 service */ sleep(5); int status = RUN_ALL_TESTS(); LOG(INFO) << "Test result = " << status; std::system("/system/bin/svc nfc enable"); /* Turn on NFC service */ sleep(5); return status; }