Merge changes from topics "nfc_aosp_main_merge", "nfc_aosp_main_merge_stage2" into main
* changes:
Use parameterized test to disable test for devices without NFC
Add VSR min API level
Add VTS test for NFC observe mode
[Hal] Add request/release control event in aidl interface.
diff --git a/compatibility_matrices/compatibility_matrix.202504.xml b/compatibility_matrices/compatibility_matrix.202504.xml
index 3fd762a..3e5b74a 100644
--- a/compatibility_matrices/compatibility_matrix.202504.xml
+++ b/compatibility_matrices/compatibility_matrix.202504.xml
@@ -372,6 +372,7 @@
</hal>
<hal format="aidl" updatable-via-apex="true">
<name>android.hardware.nfc</name>
+ <version>1-2</version>
<interface>
<name>INfc</name>
<instance>default</instance>
diff --git a/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/INfc.aidl b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/INfc.aidl
index 7a0ae54..220912e 100644
--- a/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/INfc.aidl
+++ b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/INfc.aidl
@@ -44,4 +44,5 @@
int write(in byte[] data);
void setEnableVerboseLogging(in boolean enable);
boolean isVerboseLoggingEnabled();
+ android.hardware.nfc.NfcStatus controlGranted();
}
diff --git a/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcEvent.aidl b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcEvent.aidl
index dda258e..aebe836 100644
--- a/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcEvent.aidl
+++ b/nfc/aidl/aidl_api/android.hardware.nfc/current/android/hardware/nfc/NfcEvent.aidl
@@ -40,4 +40,6 @@
PRE_DISCOVER_CPLT = 3,
HCI_NETWORK_RESET = 4,
ERROR = 5,
+ REQUEST_CONTROL = 6,
+ RELEASE_CONTROL = 7,
}
diff --git a/nfc/aidl/android/hardware/nfc/INfc.aidl b/nfc/aidl/android/hardware/nfc/INfc.aidl
index 662f8d4..1d18b9e 100644
--- a/nfc/aidl/android/hardware/nfc/INfc.aidl
+++ b/nfc/aidl/android/hardware/nfc/INfc.aidl
@@ -140,4 +140,13 @@
* @return true if verbose logging flag value is enabled, false if disabled.
*/
boolean isVerboseLoggingEnabled();
+
+ /**
+ * Requests control of NFCC to libnfc-nci.
+ * If an API request is sent when the framework has no control of NFCC, the request will be
+ * queued until the control is released from HAL.
+ * The control will be taken out of the framework for at most 2 seconds.
+ * @return NfcStatus::OK on success and NfcStatus::FAILED on error.
+ */
+ NfcStatus controlGranted();
}
diff --git a/nfc/aidl/android/hardware/nfc/NfcEvent.aidl b/nfc/aidl/android/hardware/nfc/NfcEvent.aidl
index a78b1cd..7e0231a 100644
--- a/nfc/aidl/android/hardware/nfc/NfcEvent.aidl
+++ b/nfc/aidl/android/hardware/nfc/NfcEvent.aidl
@@ -50,4 +50,14 @@
* Error event to notify upper layer when there's an unknown error.
*/
ERROR = 5,
+ /**
+ * Request control event to notify upper layer when HAL
+ * request control of NFCC to libnfc-nci
+ */
+ REQUEST_CONTROL = 6,
+ /**
+ * Release control event to notify upper layer when HAL
+ * release control of NFCC to libnfc-nci.
+ */
+ RELEASE_CONTROL = 7,
}
diff --git a/nfc/aidl/vts/functional/Android.bp b/nfc/aidl/vts/functional/Android.bp
index 0dab2d8..82ce026 100644
--- a/nfc/aidl/vts/functional/Android.bp
+++ b/nfc/aidl/vts/functional/Android.bp
@@ -38,10 +38,55 @@
"libbinder_ndk",
],
static_libs: [
- "android.hardware.nfc-V1-ndk",
+ "android.hardware.nfc-V2-ndk",
],
test_suites: [
"general-tests",
"vts",
],
}
+
+cc_test {
+ name: "VtsNfcBehaviorChangesTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: [
+ "VtsNfcBehaviorChangesTest.cpp",
+ "CondVar.cpp",
+ ],
+ include_dirs: [
+ "system/nfc/src/gki/common",
+ "system/nfc/src/gki/ulinux",
+ "system/nfc/src/include",
+ "system/nfc/src/nfa/include",
+ "system/nfc/src/nfc/include",
+ "system/nfc/utils/include",
+ ],
+ shared_libs: [
+ "libbinder",
+ "libbinder_ndk",
+ "libnativehelper",
+ "libstatssocket",
+ ],
+ static_libs: [
+ "android.hardware.nfc-V2-ndk",
+ "android.hardware.nfc@1.0",
+ "android.hardware.nfc@1.1",
+ "android.hardware.nfc@1.2",
+ "android_nfc_flags_aconfig_c_lib",
+ "libnfc-nci",
+ "libnfc-nci_flags",
+ "libnfcutils",
+ "libstatslog_nfc",
+ "server_configurable_flags",
+ ],
+ require_root: true,
+ test_options: {
+ vsr_min_shipping_api_level: 202404, // 2024Q2
+ },
+ test_suites: [
+ "vts",
+ ],
+}
diff --git a/nfc/aidl/vts/functional/CondVar.cpp b/nfc/aidl/vts/functional/CondVar.cpp
new file mode 100644
index 0000000..59e5b51
--- /dev/null
+++ b/nfc/aidl/vts/functional/CondVar.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ * Encapsulate a condition variable for thread synchronization.
+ */
+
+#include "CondVar.h"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <errno.h>
+#include <string.h>
+
+using android::base::StringPrintf;
+
+/*******************************************************************************
+**
+** Function: CondVar
+**
+** Description: Initialize member variables.
+**
+** Returns: None.
+**
+*******************************************************************************/
+CondVar::CondVar() {
+ pthread_condattr_t attr;
+ pthread_condattr_init(&attr);
+ pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
+ memset(&mCondition, 0, sizeof(mCondition));
+ int const res = pthread_cond_init(&mCondition, &attr);
+ if (res) {
+ LOG(ERROR) << StringPrintf("CondVar::CondVar: fail init; error=0x%X", res);
+ }
+}
+
+/*******************************************************************************
+**
+** Function: ~CondVar
+**
+** Description: Cleanup all resources.
+**
+** Returns: None.
+**
+*******************************************************************************/
+CondVar::~CondVar() {
+ int const res = pthread_cond_destroy(&mCondition);
+ if (res) {
+ LOG(ERROR) << StringPrintf("CondVar::~CondVar: fail destroy; error=0x%X", res);
+ }
+}
+
+/*******************************************************************************
+**
+** Function: wait
+**
+** Description: Block the caller and wait for a condition.
+**
+** Returns: None.
+**
+*******************************************************************************/
+void CondVar::wait(std::mutex& mutex) {
+ int const res = pthread_cond_wait(&mCondition, mutex.native_handle());
+ if (res) {
+ LOG(ERROR) << StringPrintf("CondVar::wait: fail wait; error=0x%X", res);
+ }
+}
+
+/*******************************************************************************
+**
+** Function: wait
+**
+** Description: Block the caller and wait for a condition.
+** millisec: Timeout in milliseconds.
+**
+** Returns: True if wait is successful; false if timeout occurs.
+**
+*******************************************************************************/
+bool CondVar::wait(std::mutex& mutex, long millisec) {
+ bool retVal = false;
+ struct timespec absoluteTime;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &absoluteTime) == -1) {
+ LOG(ERROR) << StringPrintf("CondVar::wait: fail get time; errno=0x%X", errno);
+ } else {
+ absoluteTime.tv_sec += millisec / 1000;
+ long ns = absoluteTime.tv_nsec + ((millisec % 1000) * 1000000);
+ if (ns > 1000000000) {
+ absoluteTime.tv_sec++;
+ absoluteTime.tv_nsec = ns - 1000000000;
+ } else
+ absoluteTime.tv_nsec = ns;
+ }
+
+ int waitResult = pthread_cond_timedwait(&mCondition, mutex.native_handle(), &absoluteTime);
+ if ((waitResult != 0) && (waitResult != ETIMEDOUT))
+ LOG(ERROR) << StringPrintf("CondVar::wait: fail timed wait; error=0x%X", waitResult);
+ retVal = (waitResult == 0); // waited successfully
+ return retVal;
+}
+
+/*******************************************************************************
+**
+** Function: notifyOne
+**
+** Description: Unblock the waiting thread.
+**
+** Returns: None.
+**
+*******************************************************************************/
+void CondVar::notifyOne() {
+ int const res = pthread_cond_signal(&mCondition);
+ if (res) {
+ LOG(ERROR) << StringPrintf("CondVar::notifyOne: fail signal; error=0x%X", res);
+ }
+}
diff --git a/nfc/aidl/vts/functional/CondVar.h b/nfc/aidl/vts/functional/CondVar.h
new file mode 100644
index 0000000..5e0dcf7
--- /dev/null
+++ b/nfc/aidl/vts/functional/CondVar.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ * Encapsulate a condition variable for thread synchronization.
+ */
+
+#pragma once
+#include <pthread.h>
+
+#include <mutex>
+
+class CondVar {
+ public:
+ /*******************************************************************************
+ **
+ ** Function: CondVar
+ **
+ ** Description: Initialize member variables.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ CondVar();
+
+ /*******************************************************************************
+ **
+ ** Function: ~CondVar
+ **
+ ** Description: Cleanup all resources.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ ~CondVar();
+
+ /*******************************************************************************
+ **
+ ** Function: wait
+ **
+ ** Description: Block the caller and wait for a condition.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void wait(std::mutex& mutex);
+
+ /*******************************************************************************
+ **
+ ** Function: wait
+ **
+ ** Description: Block the caller and wait for a condition.
+ ** millisec: Timeout in milliseconds.
+ **
+ ** Returns: True if wait is successful; false if timeout occurs.
+ **
+ *******************************************************************************/
+ bool wait(std::mutex& mutex, long millisec);
+
+ /*******************************************************************************
+ **
+ ** Function: notifyOne
+ **
+ ** Description: Unblock the waiting thread.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void notifyOne();
+
+ private:
+ pthread_cond_t mCondition;
+};
diff --git a/nfc/aidl/vts/functional/SyncEvent.h b/nfc/aidl/vts/functional/SyncEvent.h
new file mode 100644
index 0000000..352a549
--- /dev/null
+++ b/nfc/aidl/vts/functional/SyncEvent.h
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ * Synchronize two or more threads using a condition variable and a mutex.
+ */
+#pragma once
+#include <mutex>
+
+#include "CondVar.h"
+
+class SyncEvent {
+ public:
+ /*******************************************************************************
+ **
+ ** Function: ~SyncEvent
+ **
+ ** Description: Cleanup all resources.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ ~SyncEvent() {}
+
+ /*******************************************************************************
+ **
+ ** Function: start
+ **
+ ** Description: Start a synchronization operation.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void start() { mMutex.lock(); }
+
+ /*******************************************************************************
+ **
+ ** Function: wait
+ **
+ ** Description: Block the thread and wait for the event to occur.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void wait() { mCondVar.wait(mMutex); }
+
+ /*******************************************************************************
+ **
+ ** Function: wait
+ **
+ ** Description: Block the thread and wait for the event to occur.
+ ** millisec: Timeout in milliseconds.
+ **
+ ** Returns: True if wait is successful; false if timeout occurs.
+ **
+ *******************************************************************************/
+ bool wait(long millisec) {
+ bool retVal = mCondVar.wait(mMutex, millisec);
+ return retVal;
+ }
+
+ /*******************************************************************************
+ **
+ ** Function: notifyOne
+ **
+ ** Description: Notify a blocked thread that the event has occurred.
+ *Unblocks it.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void notifyOne() { mCondVar.notifyOne(); }
+
+ /*******************************************************************************
+ **
+ ** Function: end
+ **
+ ** Description: End a synchronization operation.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ void end() { mMutex.unlock(); }
+
+ private:
+ CondVar mCondVar;
+ std::mutex mMutex;
+};
+
+/*****************************************************************************/
+/*****************************************************************************/
+
+/*****************************************************************************
+**
+** Name: SyncEventGuard
+**
+** Description: Automatically start and end a synchronization event.
+**
+*****************************************************************************/
+class SyncEventGuard {
+ public:
+ /*******************************************************************************
+ **
+ ** Function: SyncEventGuard
+ **
+ ** Description: Start a synchronization operation.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ SyncEventGuard(SyncEvent& event) : mEvent(event) {
+ event.start(); // automatically start operation
+ };
+
+ /*******************************************************************************
+ **
+ ** Function: ~SyncEventGuard
+ **
+ ** Description: End a synchronization operation.
+ **
+ ** Returns: None.
+ **
+ *******************************************************************************/
+ ~SyncEventGuard() {
+ mEvent.end(); // automatically end operation
+ };
+
+ private:
+ SyncEvent& mEvent;
+};
diff --git a/nfc/aidl/vts/functional/VtsAidlHalNfcTargetTest.cpp b/nfc/aidl/vts/functional/VtsAidlHalNfcTargetTest.cpp
index 977b25c..12f4364 100644
--- a/nfc/aidl/vts/functional/VtsAidlHalNfcTargetTest.cpp
+++ b/nfc/aidl/vts/functional/VtsAidlHalNfcTargetTest.cpp
@@ -440,6 +440,16 @@
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)),
diff --git a/nfc/aidl/vts/functional/VtsNfcBehaviorChangesTest.cpp b/nfc/aidl/vts/functional/VtsNfcBehaviorChangesTest.cpp
new file mode 100644
index 0000000..ff2522c
--- /dev/null
+++ b/nfc/aidl/vts/functional/VtsNfcBehaviorChangesTest.cpp
@@ -0,0 +1,235 @@
+/*
+ * 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;
+}