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 #include "nfc_api.h"
18 #define LOG_TAG "nfc_behavior_changes_test"
19
20 #include <aidl/Gtest.h>
21 #include <aidl/Vintf.h>
22 #include <aidl/android/hardware/nfc/BnNfc.h>
23 #include <aidl/android/hardware/nfc/INfc.h>
24 #include <android-base/logging.h>
25 #include <android-base/properties.h>
26 #include <android-base/stringprintf.h>
27 #include <android/binder_process.h>
28 #include <gtest/gtest.h>
29
30 #include <chrono>
31 #include <future>
32
33 #include "NfcAdaptation.h"
34 #include "SyncEvent.h"
35 #include "nci_defs.h"
36 #include "nfa_api.h"
37 #include "nfa_ee_api.h"
38
39 using aidl::android::hardware::nfc::INfc;
40 using android::getAidlHalInstanceNames;
41 using android::PrintInstanceNameToString;
42 using android::base::StringPrintf;
43
44 static SyncEvent sNfaEnableEvent; // event for NFA_Enable()
45 static SyncEvent sNfaVsCommand; // event for VS commands
46 static SyncEvent sNfaEnableDisablePollingEvent;
47 static SyncEvent sNfaPowerChangeEvent;
48 static std::vector<uint8_t> sCaps(0);
49 static uint8_t sObserveModeState;
50 static bool sIsNfaEnabled;
51 static tNFA_STATUS sVSCmdStatus;
52
53 static const int SET_PASSIVE_OBSERVER_TECH_TIMEOUT_MS = 15;
54
get_vsr_api_level()55 static int get_vsr_api_level() {
56 int api_level =
57 ::android::base::GetIntProperty("ro.vendor.api_level", -1);
58 if (api_level != -1) {
59 return api_level;
60 }
61
62 api_level =
63 ::android::base::GetIntProperty("ro.board.api_level", -1);
64 if (api_level != -1) {
65 return api_level;
66 }
67
68 api_level =
69 ::android::base::GetIntProperty("ro.board.first_api_level", -1);
70 EXPECT_NE(api_level, -1) << "Could not find VSR API level.";
71
72 return api_level;
73
74 }
75
nfaDeviceManagementCallback(uint8_t dmEvent,tNFA_DM_CBACK_DATA * eventData)76 static void nfaDeviceManagementCallback(uint8_t dmEvent, tNFA_DM_CBACK_DATA* eventData) {
77 LOG(DEBUG) << StringPrintf("%s: enter; event=0x%X", __func__, dmEvent);
78
79 switch (dmEvent) {
80 case NFA_DM_ENABLE_EVT: /* Result of NFA_Enable */
81 {
82 SyncEventGuard guard(sNfaEnableEvent);
83 LOG(DEBUG) << StringPrintf("%s: NFA_DM_ENABLE_EVT; status=0x%X", __func__,
84 eventData->status);
85 sIsNfaEnabled = eventData->status == NFA_STATUS_OK;
86 sNfaEnableEvent.notifyOne();
87 } break;
88
89 case NFA_DM_DISABLE_EVT: /* Result of NFA_Disable */
90 {
91 SyncEventGuard guard(sNfaEnableEvent);
92 LOG(DEBUG) << StringPrintf("%s: NFA_DM_DISABLE_EVT; status=0x%X", __func__,
93 eventData->status);
94 sIsNfaEnabled = eventData->status == NFA_STATUS_OK;
95 sNfaEnableEvent.notifyOne();
96 } break;
97
98 case NFA_DM_PWR_MODE_CHANGE_EVT: {
99 SyncEventGuard guard(sNfaPowerChangeEvent);
100 LOG(DEBUG) << StringPrintf(
101 "%s: NFA_DM_PWR_MODE_CHANGE_EVT: status=0x%X, power_mode=0x%X", __func__,
102 eventData->status, eventData->power_mode.power_mode);
103
104 sNfaPowerChangeEvent.notifyOne();
105
106 } break;
107 }
108 }
109
nfaConnectionCallback(uint8_t connEvent,tNFA_CONN_EVT_DATA * eventData)110 static void nfaConnectionCallback(uint8_t connEvent, tNFA_CONN_EVT_DATA* eventData) {
111 LOG(DEBUG) << StringPrintf("%s: event= %u", __func__, connEvent);
112
113 switch (connEvent) {
114 case NFA_LISTEN_DISABLED_EVT: {
115 SyncEventGuard guard(sNfaEnableDisablePollingEvent);
116 sNfaEnableDisablePollingEvent.notifyOne();
117 } break;
118
119 case NFA_LISTEN_ENABLED_EVT: {
120 SyncEventGuard guard(sNfaEnableDisablePollingEvent);
121 sNfaEnableDisablePollingEvent.notifyOne();
122 } break;
123
124 case NFA_RF_DISCOVERY_STARTED_EVT: // RF Discovery started
125 {
126 LOG(DEBUG) << StringPrintf("%s: NFA_RF_DISCOVERY_STARTED_EVT: status = %u", __func__,
127 eventData->status);
128
129 SyncEventGuard guard(sNfaEnableDisablePollingEvent);
130 sNfaEnableDisablePollingEvent.notifyOne();
131 } break;
132
133 case NFA_RF_DISCOVERY_STOPPED_EVT: // RF Discovery stopped event
134 {
135 LOG(DEBUG) << StringPrintf("%s: NFA_RF_DISCOVERY_STOPPED_EVT: status = %u", __func__,
136 eventData->status);
137
138 SyncEventGuard guard(sNfaEnableDisablePollingEvent);
139 sNfaEnableDisablePollingEvent.notifyOne();
140 } break;
141 }
142 }
143
nfaVSCallback(uint8_t event,uint16_t param_len,uint8_t * p_param)144 void static nfaVSCallback(uint8_t event, uint16_t param_len, uint8_t* p_param) {
145 switch (event & NCI_OID_MASK) {
146 case NCI_MSG_PROP_ANDROID: {
147 uint8_t android_sub_opcode = p_param[3];
148 switch (android_sub_opcode) {
149 case NCI_QUERY_ANDROID_PASSIVE_OBSERVE: {
150 sObserveModeState = p_param[5];
151 LOG(INFO) << StringPrintf("Query observe mode state response is %x",
152 sObserveModeState);
153 SyncEventGuard guard(sNfaVsCommand);
154 sNfaVsCommand.notifyOne();
155 } break;
156 case NCI_ANDROID_SET_PASSIVE_OBSERVER_TECH: {
157 if (param_len == 5) {
158 if ((p_param[0] & NCI_MT_MASK) == (NCI_MT_RSP << NCI_MT_SHIFT)) {
159 sVSCmdStatus = p_param[4];
160 LOG(INFO) << StringPrintf("Observe mode RSP: status: %x", sVSCmdStatus);
161 SyncEventGuard guard(sNfaVsCommand);
162 sNfaVsCommand.notifyOne();
163 } else {
164 LOG(WARNING) << StringPrintf(
165 "Observe Mode RSP has incorrect message type: %x", p_param[0]);
166 }
167 } else {
168 LOG(WARNING) << StringPrintf("Observe Mode RSP has incorrect length: %d",
169 param_len);
170 }
171 } break;
172 case NCI_ANDROID_POLLING_FRAME_NTF: {
173 // TODO
174 } break;
175 case NCI_ANDROID_GET_CAPS: {
176 sVSCmdStatus = p_param[4];
177 SyncEventGuard guard(sNfaVsCommand);
178 sCaps.assign(p_param + 8, p_param + param_len);
179 sNfaVsCommand.notifyOne();
180 } break;
181 default:
182 LOG(WARNING) << StringPrintf("Unknown Android sub opcode %x",
183 android_sub_opcode);
184 }
185 } break;
186 default:
187 break;
188 }
189 }
190
191 /*
192 * Get observe mode state.
193 */
nfaQueryObserveModeState()194 tNFA_STATUS static nfaQueryObserveModeState() {
195 tNFA_STATUS status = NFA_STATUS_FAILED;
196
197 uint8_t cmd[] = {NCI_QUERY_ANDROID_PASSIVE_OBSERVE};
198
199 status = NFA_SendVsCommand(NCI_MSG_PROP_ANDROID, sizeof(cmd), cmd, nfaVSCallback);
200
201 if (status == NFA_STATUS_OK) {
202 if (!sNfaVsCommand.wait(1000)) {
203 LOG(WARNING) << "Timeout waiting for query observe mode response";
204 return NFA_STATUS_TIMEOUT;
205 }
206 }
207
208 return status;
209 }
210
211 /*
212 * Enable per-technology observe mode.
213 */
nfaSetPassiveObserverTech(uint8_t tech_mask)214 tNFA_STATUS static nfaSetPassiveObserverTech(uint8_t tech_mask) {
215 tNFA_STATUS status = NFA_STATUS_FAILED;
216
217 uint8_t cmd[] = {NCI_ANDROID_SET_PASSIVE_OBSERVER_TECH, tech_mask};
218
219 status = NFA_SendVsCommand(NCI_MSG_PROP_ANDROID, sizeof(cmd), cmd, nfaVSCallback);
220
221 if (status == NFA_STATUS_OK) {
222 if (!sNfaVsCommand.wait(SET_PASSIVE_OBSERVER_TECH_TIMEOUT_MS)) {
223 LOG(WARNING) << "Timeout waiting for set observer tech response";
224 return NFA_STATUS_TIMEOUT;
225 }
226 }
227
228 return status;
229 }
230
231 /*
232 * Get chipset capabilities.
233 */
nfaGetCaps()234 tNFA_STATUS static nfaGetCaps() {
235 tNFA_STATUS status = NFA_STATUS_FAILED;
236
237 uint8_t cmd[] = {NCI_ANDROID_GET_CAPS};
238 status = NFA_SendVsCommand(NCI_MSG_PROP_ANDROID, sizeof(cmd), cmd, nfaVSCallback);
239
240 if (status == NFA_STATUS_OK) {
241 if (!sNfaVsCommand.wait(1000)) {
242 LOG(WARNING) << "Timeout waiting for GET_CAPS response";
243 return NFA_STATUS_TIMEOUT;
244 }
245 }
246
247 return status;
248 }
249
250 /*
251 * Get observe mode capabilities.
252 */
getCapsPassiveObserverModeValue()253 uint8_t static getCapsPassiveObserverModeValue() {
254 return sCaps[2];
255 }
256
257 class NfcBehaviorChanges : public testing::TestWithParam<std::string> {
258 protected:
SetUp()259 void SetUp() override {
260 tNFA_STATUS status = NFA_STATUS_OK;
261 status = NFA_StartRfDiscovery();
262 ASSERT_EQ(status, NFA_STATUS_OK);
263 ASSERT_TRUE(sNfaEnableDisablePollingEvent.wait(1000)) << "Timeout starting RF discovery";
264 }
265
SetUpTestSuite()266 static void SetUpTestSuite() {
267 tNFA_STATUS status = NFA_STATUS_OK;
268
269 sIsNfaEnabled = false;
270 sVSCmdStatus = NFA_STATUS_OK;
271
272 NfcAdaptation& theInstance = NfcAdaptation::GetInstance();
273 theInstance.Initialize(); // start GKI, NCI task, NFC task
274
275 {
276 SyncEventGuard guard(sNfaEnableEvent);
277 tHAL_NFC_ENTRY* halFuncEntries = theInstance.GetHalEntryFuncs();
278
279 NFA_Init(halFuncEntries);
280
281 status = NFA_Enable(nfaDeviceManagementCallback, nfaConnectionCallback);
282 ASSERT_EQ(status, NFA_STATUS_OK);
283
284 // wait for NFA command to finish
285 ASSERT_TRUE(sNfaEnableEvent.wait(1000))
286 << "Timeout waiting for NFA command on NFA_Enable";
287 }
288
289 ASSERT_TRUE(sIsNfaEnabled) << "Could not initialize NFC controller";
290 }
291 };
292
293 /*
294 * SetPassiveObserverTech_getCaps:
295 * Verifies GET_CAPS returns get correct value for observe mode capabilities.
296 */
TEST_P(NfcBehaviorChanges,SetPassiveObserverTech_getCaps)297 TEST_P(NfcBehaviorChanges, SetPassiveObserverTech_getCaps) {
298 if (get_vsr_api_level() < 202504) {
299 GTEST_SKIP() << "Skipping test for board API level < 202504";
300 }
301
302 tNFC_STATUS status = nfaGetCaps();
303
304 ASSERT_EQ(status, NFC_STATUS_OK);
305 ASSERT_EQ(getCapsPassiveObserverModeValue(), 0x2);
306 }
307
308 /*
309 * SetPassiveObserverTech_allExceptF:
310 * Verifies observe mode can be enabled for NFC-A, NFC-B, NFC-V, and disable for NFC-F.
311 *
312 * @VsrTest = GMS-VSR-3.2.8-002
313 */
TEST_P(NfcBehaviorChanges,SetPassiveObserverTech_allExceptF)314 TEST_P(NfcBehaviorChanges, SetPassiveObserverTech_allExceptF) {
315 if (get_vsr_api_level() < 202504) {
316 GTEST_SKIP() << "Skipping test for board API level < 202504";
317 }
318
319 tNFC_STATUS status = nfaSetPassiveObserverTech(NCI_ANDROID_PASSIVE_OBSERVE_PARAM_ENABLE_A |
320 NCI_ANDROID_PASSIVE_OBSERVE_PARAM_ENABLE_B |
321 NCI_ANDROID_PASSIVE_OBSERVE_PARAM_ENABLE_V);
322 ASSERT_EQ(status, NFA_STATUS_OK);
323 status = nfaQueryObserveModeState();
324 ASSERT_EQ(status, NFA_STATUS_OK);
325 ASSERT_EQ(sObserveModeState, NCI_ANDROID_PASSIVE_OBSERVE_PARAM_ENABLE_A |
326 NCI_ANDROID_PASSIVE_OBSERVE_PARAM_ENABLE_B |
327 NCI_ANDROID_PASSIVE_OBSERVE_PARAM_ENABLE_V);
328 }
329
330 /*
331 * SetPassiveObserverTech_allOnAndOff:
332 * Verifies observe mode can be enabled and disabled for all technologies.
333 *
334 * @VsrTest = GMS-VSR-3.2.8-002
335 */
TEST_P(NfcBehaviorChanges,SetPassiveObserverTech_allOnAndOff)336 TEST_P(NfcBehaviorChanges, SetPassiveObserverTech_allOnAndOff) {
337 if (get_vsr_api_level() < 202504) {
338 GTEST_SKIP() << "Skipping test for board API level < 202504";
339 }
340
341 tNFC_STATUS status = nfaSetPassiveObserverTech(0x0F);
342 ASSERT_EQ(status, NFA_STATUS_OK);
343 status = nfaQueryObserveModeState();
344 ASSERT_EQ(status, NFA_STATUS_OK);
345 ASSERT_EQ(sObserveModeState, 0x0F);
346
347 status = nfaSetPassiveObserverTech(0x00);
348 ASSERT_EQ(status, NFA_STATUS_OK);
349 status = nfaQueryObserveModeState();
350 ASSERT_EQ(status, NFA_STATUS_OK);
351 ASSERT_EQ(sObserveModeState, 0x00);
352 }
353
354 /*
355 * SetPassiveObserverTech_testThroughput:
356 * Verifies observe mode can be enabled and disabled repeatedly without timing out or erroring.
357 *
358 * @VsrTest = GMS-VSR-3.2.8-002
359 */
TEST_P(NfcBehaviorChanges,SetPassiveObserverTech_testThroughput)360 TEST_P(NfcBehaviorChanges, SetPassiveObserverTech_testThroughput) {
361 if (get_vsr_api_level() < 202504) {
362 GTEST_SKIP() << "Skipping test for board API level < 202504";
363 }
364
365 for (int i = 0; i < 100; ++i) {
366 tNFC_STATUS status = nfaSetPassiveObserverTech(0x0F);
367 ASSERT_EQ(status, NFA_STATUS_OK);
368
369 status = nfaSetPassiveObserverTech(0x00);
370 ASSERT_EQ(status, NFA_STATUS_OK);
371 }
372 }
373
374 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(NfcBehaviorChanges);
375 INSTANTIATE_TEST_SUITE_P(Nfc, NfcBehaviorChanges,
376 testing::ValuesIn(::android::getAidlHalInstanceNames(INfc::descriptor)),
377 ::android::PrintInstanceNameToString
378 );
379
main(int argc,char ** argv)380 int main(int argc, char **argv) {
381 testing::InitGoogleTest(&argc, argv);
382 ABinderProcess_startThreadPool();
383 std::system("/system/bin/svc nfc disable"); /* Turn off NFC service */
384 sleep(5);
385 int status = RUN_ALL_TESTS();
386 LOG(INFO) << "Test result = " << status;
387 std::system("/system/bin/svc nfc enable"); /* Turn on NFC service */
388 sleep(5);
389 return status;
390 }
391