1 /*
2 * Copyright (C) 2024 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 "nfc_behavior_changes_test"
18
19 #include <aidl/Gtest.h>
20 #include <aidl/Vintf.h>
21 #include <aidl/android/hardware/nfc/BnNfc.h>
22 #include <aidl/android/hardware/nfc/INfc.h>
23 #include <android-base/logging.h>
24 #include <android-base/stringprintf.h>
25 #include <android/binder_process.h>
26 #include <gtest/gtest.h>
27
28 #include <chrono>
29 #include <future>
30
31 #include "NfcAdaptation.h"
32 #include "SyncEvent.h"
33 #include "nci_defs.h"
34 #include "nfa_api.h"
35 #include "nfa_ee_api.h"
36
37 using aidl::android::hardware::nfc::INfc;
38 using android::getAidlHalInstanceNames;
39 using android::PrintInstanceNameToString;
40 using android::base::StringPrintf;
41
42 static SyncEvent sNfaEnableEvent; // event for NFA_Enable()
43 static SyncEvent sNfaVsCommand; // event for VS commands
44 static SyncEvent sNfaEnableDisablePollingEvent;
45 static SyncEvent sNfaPowerChangeEvent;
46 static bool sIsNfaEnabled;
47 static tNFA_STATUS sVSCmdStatus;
48
nfaDeviceManagementCallback(uint8_t dmEvent,tNFA_DM_CBACK_DATA * eventData)49 static void nfaDeviceManagementCallback(uint8_t dmEvent, tNFA_DM_CBACK_DATA* eventData) {
50 LOG(DEBUG) << StringPrintf("%s: enter; event=0x%X", __func__, dmEvent);
51
52 switch (dmEvent) {
53 case NFA_DM_ENABLE_EVT: /* Result of NFA_Enable */
54 {
55 SyncEventGuard guard(sNfaEnableEvent);
56 LOG(DEBUG) << StringPrintf("%s: NFA_DM_ENABLE_EVT; status=0x%X", __func__,
57 eventData->status);
58 sIsNfaEnabled = eventData->status == NFA_STATUS_OK;
59 sNfaEnableEvent.notifyOne();
60 } break;
61
62 case NFA_DM_DISABLE_EVT: /* Result of NFA_Disable */
63 {
64 SyncEventGuard guard(sNfaEnableEvent);
65 LOG(DEBUG) << StringPrintf("%s: NFA_DM_DISABLE_EVT; status=0x%X", __func__,
66 eventData->status);
67 sIsNfaEnabled = eventData->status == NFA_STATUS_OK;
68 sNfaEnableEvent.notifyOne();
69 } break;
70
71 case NFA_DM_PWR_MODE_CHANGE_EVT: {
72 SyncEventGuard guard(sNfaPowerChangeEvent);
73 LOG(DEBUG) << StringPrintf(
74 "%s: NFA_DM_PWR_MODE_CHANGE_EVT: status=0x%X, power_mode=0x%X", __func__,
75 eventData->status, eventData->power_mode.power_mode);
76
77 sNfaPowerChangeEvent.notifyOne();
78
79 } break;
80 }
81 }
82
nfaConnectionCallback(uint8_t connEvent,tNFA_CONN_EVT_DATA * eventData)83 static void nfaConnectionCallback(uint8_t connEvent, tNFA_CONN_EVT_DATA* eventData) {
84 LOG(DEBUG) << StringPrintf("%s: event= %u", __func__, connEvent);
85
86 switch (connEvent) {
87 case NFA_LISTEN_DISABLED_EVT: {
88 SyncEventGuard guard(sNfaEnableDisablePollingEvent);
89 sNfaEnableDisablePollingEvent.notifyOne();
90 } break;
91
92 case NFA_LISTEN_ENABLED_EVT: {
93 SyncEventGuard guard(sNfaEnableDisablePollingEvent);
94 sNfaEnableDisablePollingEvent.notifyOne();
95 } break;
96
97 case NFA_RF_DISCOVERY_STARTED_EVT: // RF Discovery started
98 {
99 LOG(DEBUG) << StringPrintf("%s: NFA_RF_DISCOVERY_STARTED_EVT: status = %u", __func__,
100 eventData->status);
101
102 SyncEventGuard guard(sNfaEnableDisablePollingEvent);
103 sNfaEnableDisablePollingEvent.notifyOne();
104 } break;
105
106 case NFA_RF_DISCOVERY_STOPPED_EVT: // RF Discovery stopped event
107 {
108 LOG(DEBUG) << StringPrintf("%s: NFA_RF_DISCOVERY_STOPPED_EVT: status = %u", __func__,
109 eventData->status);
110
111 SyncEventGuard guard(sNfaEnableDisablePollingEvent);
112 sNfaEnableDisablePollingEvent.notifyOne();
113 } break;
114 }
115 }
116
nfaVSCallback(uint8_t event,uint16_t,uint8_t * p_param)117 void static nfaVSCallback(uint8_t event, uint16_t /* param_len */, uint8_t* p_param) {
118 switch (event & NCI_OID_MASK) {
119 case NCI_MSG_PROP_ANDROID: {
120 uint8_t android_sub_opcode = p_param[3];
121 switch (android_sub_opcode) {
122 case NCI_ANDROID_PASSIVE_OBSERVE: {
123 sVSCmdStatus = p_param[4];
124 LOG(INFO) << StringPrintf("Observe mode RSP: status: %x", sVSCmdStatus);
125 SyncEventGuard guard(sNfaVsCommand);
126 sNfaVsCommand.notifyOne();
127 } break;
128 case NCI_ANDROID_POLLING_FRAME_NTF: {
129 // TODO
130 } break;
131 default:
132 LOG(WARNING) << StringPrintf("Unknown Android sub opcode %x",
133 android_sub_opcode);
134 }
135 } break;
136 default:
137 break;
138 }
139 }
140
141 /*
142 * Enable passive observe mode.
143 */
nfaObserveModeEnable(bool enable)144 tNFA_STATUS static nfaObserveModeEnable(bool enable) {
145 tNFA_STATUS status = NFA_STATUS_FAILED;
146
147 status = NFA_StopRfDiscovery();
148 if (status == NFA_STATUS_OK) {
149 if (!sNfaEnableDisablePollingEvent.wait(1000)) {
150 LOG(WARNING) << "Timeout waiting to disable NFC RF discovery";
151 return NFA_STATUS_TIMEOUT;
152 }
153 }
154
155 uint8_t cmd[] = {(NCI_MT_CMD << NCI_MT_SHIFT) | NCI_GID_PROP, NCI_MSG_PROP_ANDROID,
156 NCI_ANDROID_PASSIVE_OBSERVE_PARAM_SIZE, NCI_ANDROID_PASSIVE_OBSERVE,
157 static_cast<uint8_t>(enable ? NCI_ANDROID_PASSIVE_OBSERVE_PARAM_ENABLE
158 : NCI_ANDROID_PASSIVE_OBSERVE_PARAM_DISABLE)};
159
160 status = NFA_SendRawVsCommand(sizeof(cmd), cmd, nfaVSCallback);
161
162 if (status == NFA_STATUS_OK) {
163 if (!sNfaVsCommand.wait(1000)) {
164 LOG(WARNING) << "Timeout waiting for NFA VS command response";
165 return NFA_STATUS_TIMEOUT;
166 }
167 }
168
169 return status;
170 }
171
172 class NfcBehaviorChanges : public testing::TestWithParam<std::string> {
173 protected:
SetUp()174 void SetUp() override {
175 tNFA_STATUS status = NFA_STATUS_OK;
176
177 sIsNfaEnabled = false;
178 sVSCmdStatus = NFA_STATUS_OK;
179
180 NfcAdaptation& theInstance = NfcAdaptation::GetInstance();
181 theInstance.Initialize(); // start GKI, NCI task, NFC task
182
183 {
184 SyncEventGuard guard(sNfaEnableEvent);
185 tHAL_NFC_ENTRY* halFuncEntries = theInstance.GetHalEntryFuncs();
186
187 NFA_Init(halFuncEntries);
188
189 status = NFA_Enable(nfaDeviceManagementCallback, nfaConnectionCallback);
190 ASSERT_EQ(status, NFA_STATUS_OK);
191
192 // wait for NFA command to finish
193 ASSERT_TRUE(sNfaEnableEvent.wait(1000))
194 << "Timeout waiting for NFA command on NFA_Enable";
195 }
196
197 ASSERT_TRUE(sIsNfaEnabled) << "Could not initialize NFC controller";
198
199 status = NFA_StartRfDiscovery();
200 ASSERT_EQ(status, NFA_STATUS_OK);
201 ASSERT_TRUE(sNfaEnableDisablePollingEvent.wait(1000)) << "Timeout starting RF discovery";
202 }
203 };
204
205 /*
206 * ObserveModeEnable:
207 * Attempts to enable observe mode. Does not test Observe Mode functionality,
208 * but simply verifies that the enable command responds successfully.
209 *
210 * @VsrTest = GMS-VSR-3.2.8-001
211 */
TEST_P(NfcBehaviorChanges,ObserveModeEnableDisable)212 TEST_P(NfcBehaviorChanges, ObserveModeEnableDisable) {
213 tNFA_STATUS status = nfaObserveModeEnable(true);
214 ASSERT_EQ(status, NFA_STATUS_OK);
215
216 status = nfaObserveModeEnable(false);
217 ASSERT_EQ(status, NFA_STATUS_OK);
218 }
219
220 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(NfcBehaviorChanges);
221 INSTANTIATE_TEST_SUITE_P(Nfc, NfcBehaviorChanges,
222 testing::ValuesIn(::android::getAidlHalInstanceNames(INfc::descriptor)),
223 ::android::PrintInstanceNameToString);
224
main(int argc,char ** argv)225 int main(int argc, char** argv) {
226 testing::InitGoogleTest(&argc, argv);
227 ABinderProcess_startThreadPool();
228 std::system("/system/bin/svc nfc disable"); /* Turn off NFC service */
229 sleep(5);
230 int status = RUN_ALL_TESTS();
231 LOG(INFO) << "Test result = " << status;
232 std::system("/system/bin/svc nfc enable"); /* Turn on NFC service */
233 sleep(5);
234 return status;
235 }
236