1# Copyright (C) 2024 The Android Open Source Project 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14# 15# Licensed under the Apache License, Version 2.0 (the "License"); 16# you may not use this file except in compliance with the License. 17# You may obtain a copy of the License at 18# 19# http://www.apache.org/licenses/LICENSE-2.0 20# 21# Unless required by applicable law or agreed to in writing, software 22# distributed under the License is distributed on an "AS IS" BASIS, 23# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 24# See the License for the specific language governing permissions and 25# limitations under the License. 26 27# Lint as: python3 28"""CTS Tests that verify NFC HCE features. 29 30These tests require one phone and one PN532 board. The phone acts as a card emulator, and the PN532 31acts as an NFC reader. The devices should be placed back to back. 32""" 33 34from http.client import HTTPSConnection 35import json 36import logging 37import ssl 38import sys 39import time 40 41from android.platform.test.annotations import CddTest 42from android.platform.test.annotations import ApiTest 43from mobly import asserts 44from mobly import base_test 45from mobly import test_runner 46from mobly import utils 47from mobly.controllers import android_device 48from mobly.controllers.android_device_lib import adb 49 50 51_LOG = logging.getLogger(__name__) 52logging.basicConfig(level=logging.INFO) 53try: 54 import pn532 55 from pn532.nfcutils import ( 56 parse_protocol_params, 57 create_select_apdu, 58 poll_and_transact, 59 poll_and_observe_frames, 60 get_apdus, 61 POLLING_FRAME_ALL_TEST_CASES, 62 POLLING_FRAMES_TYPE_A_SPECIAL, 63 POLLING_FRAMES_TYPE_B_SPECIAL, 64 POLLING_FRAMES_TYPE_F_SPECIAL, 65 POLLING_FRAMES_TYPE_A_LONG, 66 POLLING_FRAMES_TYPE_B_LONG, 67 POLLING_FRAME_ON, 68 POLLING_FRAME_OFF, 69 get_frame_test_stats, 70 TimedWrapper, 71 ns_to_ms, 72 ns_to_us, 73 us_to_ms, 74 ) 75except ImportError as e: 76 _LOG.warning(f"Cannot import PN532 library due to {e}") 77 78# Timeout to give the NFC service time to perform async actions such as 79# discover tags. 80_NFC_TIMEOUT_SEC = 10 81_NFC_TECH_A_POLLING_ON = (0x1 #NfcAdapter.FLAG_READER_NFC_A 82 | 0x10 #NfcAdapter.FLAG_READER_NFC_BARCODE 83 | 0x80 #NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK 84 ) 85_NFC_TECH_A_POLLING_OFF = (0x10 #NfcAdapter.FLAG_READER_NFC_BARCODE 86 | 0x80 #NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK 87 ) 88_NFC_TECH_A_LISTEN_ON = 0x1 #NfcAdapter.FLAG_LISTEN_NFC_PASSIVE_A 89_NFC_TECH_F_LISTEN_ON = 0x4 #NfcAdapter.FLAG_LISTEN_NFC_PASSIVE_F 90_NFC_LISTEN_OFF = 0x0 #NfcAdapter.FLAG_LISTEN_DISABLE 91_SERVICE_PACKAGE = "com.android.nfc.service" 92_ACCESS_SERVICE = _SERVICE_PACKAGE + ".AccessService" 93_OFFHOST_SERVICE = _SERVICE_PACKAGE + ".OffHostService" 94_LARGE_NUM_AIDS_SERVICE = _SERVICE_PACKAGE + ".LargeNumAidsService" 95_PAYMENT_SERVICE_1 = _SERVICE_PACKAGE + ".PaymentService1" 96_PAYMENT_SERVICE_2 = _SERVICE_PACKAGE + ".PaymentService2" 97_PAYMENT_SERVICE_DYNAMIC_AIDS = _SERVICE_PACKAGE + ".PaymentServiceDynamicAids" 98_PREFIX_ACCESS_SERVICE = _SERVICE_PACKAGE + ".PrefixAccessService" 99_PREFIX_PAYMENT_SERVICE_1 = _SERVICE_PACKAGE + ".PrefixPaymentService1" 100_PREFIX_TRANSPORT_SERVICE_2 = _SERVICE_PACKAGE + ".PrefixTransportService2" 101_SCREEN_OFF_PAYMENT_SERVICE = _SERVICE_PACKAGE + ".ScreenOffPaymentService" 102_SCREEN_ON_ONLY_OFF_HOST_SERVICE = _SERVICE_PACKAGE + ".ScreenOnOnlyOffHostService" 103_THROUGHPUT_SERVICE = _SERVICE_PACKAGE + ".ThroughputService" 104_TRANSPORT_SERVICE_1 = _SERVICE_PACKAGE + ".TransportService1" 105_TRANSPORT_SERVICE_2 = _SERVICE_PACKAGE + ".TransportService2" 106_POLLING_LOOP_SERVICE_1 = _SERVICE_PACKAGE + ".PollingLoopService" 107_POLLING_LOOP_SERVICE_2 = _SERVICE_PACKAGE + ".PollingLoopService2" 108 109_NUM_POLLING_LOOPS = 50 110_FAILED_TAG_MSG = "Reader did not detect tag, transaction not attempted." 111_FAILED_TRANSACTION_MSG = "Transaction failed, check device logs for more information." 112 113_FRAME_EVENT_TIMEOUT_SEC = 1 114_POLLING_FRAME_TIMESTAMP_TOLERANCE_MS = 5 115_POLLING_FRAME_TIMESTAMP_EXCEED_COUNT_TOLERANCE_ = 3 116_FAILED_MISSING_POLLING_FRAMES_MSG = "Device did not receive all polling frames" 117_FAILED_TIMESTAMP_TOLERANCE_EXCEEDED_MSG = "Polling frame timestamp tolerance exceeded" 118_FAILED_VENDOR_GAIN_VALUE_DROPPED_ON_POWER_INCREASE = """ 119Polling frame vendor specific gain value dropped on power increase 120""" 121_FAILED_FRAME_TYPE_INVALID = "Polling frame type is invalid" 122_FAILED_FRAME_DATA_INVALID = "Polling frame data is invalid" 123 124 125 126class CtsNfcHceMultiDeviceTestCases(base_test.BaseTestClass): 127 128 def _set_up_emulator(self, *args, start_emulator_fun=None, service_list=[], 129 expected_service=None, is_payment=False, preferred_service=None, 130 payment_default_service=None, should_disable_services_on_destroy=True): 131 """ 132 Sets up emulator device for multidevice tests. 133 :param args: arguments for start_emulator_fun, if any 134 :param start_emulator_fun: fun 135 Custom function to start the emulator activity. If not present, 136 startSimpleEmulatorActivity will be used. 137 :param service_list: list 138 List of services to set up. Only used if a custom function is not called. 139 :param expected_service: String 140 Class name of the service expected to handle the APDUs. 141 :param is_payment: bool 142 Whether test is setting up payment services. If so, this function will register 143 this app as the default wallet. 144 :param preferred_service: String 145 Service to set as preferred service, if any. 146 :param payment_default_service: String 147 For payment tests only: the default payment service that is expected to handle APDUs. 148 :param should_disable_services_on_destroy: bool 149 Whether to disable services on destroy (set to False for reboot tests). 150 151 :return: 152 """ 153 role_held_handler = self.emulator.nfc_emulator.asyncWaitForRoleHeld( 154 'RoleHeld') 155 if start_emulator_fun is not None: 156 start_emulator_fun(*args) 157 else: 158 if preferred_service is None: 159 self.emulator.nfc_emulator.startSimpleEmulatorActivity( 160 service_list, expected_service, is_payment, 161 should_disable_services_on_destroy) 162 else: 163 self.emulator.nfc_emulator.startSimpleEmulatorActivityWithPreferredService( 164 service_list, expected_service, preferred_service, is_payment) 165 166 if is_payment: 167 role_held_handler.waitAndGet('RoleHeld', _NFC_TIMEOUT_SEC) 168 if payment_default_service is None: 169 raise Exception("Must define payment_default_service for payment tests.") 170 self.emulator.nfc_emulator.waitForService(payment_default_service) 171 172 def _set_up_reader_and_assert_transaction(self, expected_service=None): 173 """ 174 Sets up reader, and asserts successful APDU transaction 175 :param expected_service: string 176 Class name of the service expected to handle the APDUs on the emulator device. 177 :return: 178 """ 179 if expected_service is None: 180 raise Exception('expected_service must be defined.') 181 command_apdus, response_apdus = get_apdus(self.emulator.nfc_emulator, expected_service) 182 tag_detected, transacted = poll_and_transact(self.pn532, command_apdus, response_apdus) 183 asserts.assert_true(tag_detected, _FAILED_TAG_MSG) 184 asserts.assert_true(transacted, _FAILED_TRANSACTION_MSG) 185 186 def _is_cuttlefish_device(self, ad: android_device.AndroidDevice) -> bool: 187 product_name = ad.adb.getprop("ro.product.name") 188 return "cf_x86" in product_name 189 190 def _reboot(self, ad: android_device.AndroidDevice): 191 ad.reboot() 192 ad.nfc_emulator.turnScreenOn() 193 ad.nfc_emulator.pressMenu() 194 195 def _get_casimir_id_for_device(self): 196 host = "localhost" 197 conn = HTTPSConnection(host, 1443, context=ssl._create_unverified_context()) 198 path = '/devices' 199 headers = {'Content-type': 'application/json'} 200 conn.request("GET", path, {}, headers) 201 response = conn.getresponse() 202 json_obj = json.loads(response.read()) 203 first_device = json_obj[0] 204 return first_device["device_id"] 205 206 def setup_class(self): 207 """ 208 Sets up class by registering an emulator device, enabling NFC, and loading snippets. 209 210 If a PN532 serial path is found, it uses this to configure the device. Otherwise, set up a 211 second phone as a reader device. 212 """ 213 self.pn532 = None 214 215 # This tracks the error message for a setup failure. 216 # It is set to None only if the entire setup_class runs successfully. 217 self._setup_failure_reason = 'Failed to find Android device(s).' 218 219 # Indicates if the setup failure should block (FAIL) or not block (SKIP) test cases. 220 # Blocking failures indicate that something unexpectedly went wrong during test setup, 221 # and the user should have it fixed. 222 # Non-blocking failures indicate that the device(s) did not meet the test requirements, 223 # and the test does not need to be run. 224 self._setup_failure_should_block_tests = True 225 226 try: 227 devices = self.register_controller(android_device)[:1] 228 self.emulator = devices[0] 229 230 self._setup_failure_reason = ( 231 'Cannot load emulator snippet. Is NfcEmulatorTestApp.apk ' 232 'installed on the emulator?' 233 ) 234 self.emulator.load_snippet( 235 'nfc_emulator', 'com.android.nfc.emulator' 236 ) 237 self.emulator.debug_tag = 'emulator' 238 try: 239 self.emulator.adb.shell(['svc', 'nfc', 'enable']) 240 except adb.AdbError: 241 _LOG.info("Could not enable nfc through adb.") 242 self.emulator.nfc_emulator.setNfcState(True) 243 if ( 244 hasattr(self.emulator, 'dimensions') 245 and 'pn532_serial_path' in self.emulator.dimensions 246 ): 247 pn532_serial_path = self.emulator.dimensions["pn532_serial_path"] 248 else: 249 pn532_serial_path = self.user_params.get("pn532_serial_path", "") 250 251 casimir_id = None 252 if self._is_cuttlefish_device(self.emulator): 253 self._setup_failure_reason = ('Failed to set up casimir connection for Cuttlefish ' 254 'device') 255 casimir_id = self._get_casimir_id_for_device() 256 257 if casimir_id is not None and len(casimir_id) > 0: 258 self._setup_failure_reason = 'Failed to connect to casimir' 259 _LOG.info("casimir_id = " + casimir_id) 260 self.pn532 = pn532.Casimir(casimir_id) 261 else: 262 self._setup_failure_reason = 'Failed to connect to PN532 board.' 263 self.pn532 = pn532.PN532(pn532_serial_path) 264 self.pn532.mute() 265 266 except Exception as e: 267 _LOG.warning('setup_class failed with error %s', e) 268 return 269 self._setup_failure_reason = None 270 271 def setup_test(self): 272 """ 273 Turns emulator screen on and unlocks between tests as some tests will turn the screen off. 274 """ 275 if self._setup_failure_should_block_tests: 276 asserts.assert_true( 277 self._setup_failure_reason is None, self._setup_failure_reason 278 ) 279 else: 280 asserts.skip_if( 281 self._setup_failure_reason is not None, self._setup_failure_reason 282 ) 283 284 self.emulator.nfc_emulator.logInfo("*** TEST START: " + self.current_test_info.name + 285 " ***") 286 self.emulator.nfc_emulator.turnScreenOn() 287 self.emulator.nfc_emulator.pressMenu() 288 289 def on_fail(self, record): 290 if self.user_params.get('take_bug_report_on_fail', False): 291 test_name = record.test_name 292 if hasattr(self, 'emulator') and hasattr(self.emulator, 'nfc_emulator'): 293 self.emulator.take_bug_report( 294 test_name=self.emulator.debug_tag + "_" + test_name, 295 destination=self.current_test_info.output_path, 296 ) 297 298 @CddTest(requirements = ["7.4.4/C-2-2", "7.4.4/C-1-2"]) 299 def test_single_non_payment_service(self): 300 """Tests successful APDU exchange between non-payment service and 301 reader. 302 303 Test Steps: 304 1. Start emulator activity and set up non-payment HCE Service. 305 2. Set callback handler on emulator for when a TestPass event is 306 received. 307 3. Set up PN532, which should trigger APDU exchange. 308 309 Verifies: 310 1. Verifies a successful APDU exchange. 311 """ 312 self._set_up_emulator( 313 service_list=[_TRANSPORT_SERVICE_1], 314 expected_service=_TRANSPORT_SERVICE_1 315 ) 316 317 self._set_up_reader_and_assert_transaction(expected_service=_TRANSPORT_SERVICE_1) 318 319 @CddTest(requirements = ["7.4.4/C-2-2", "7.4.4/C-1-2", "9.1/C-0-1"]) 320 def test_single_payment_service(self): 321 """Tests successful APDU exchange between payment service and 322 reader. 323 324 Test Steps: 325 1. Set callback handler on emulator for when the instrumentation app is 326 set to default wallet app. 327 2. Start emulator activity and wait for the app to hold the wallet role. 328 3. Start PN532 reader, which should trigger APDU exchange between 329 reader and emulator. 330 331 Verifies: 332 1. Verifies emulator device sets the instrumentation emulator app to the 333 default wallet app. 334 2. Verifies a successful APDU exchange. 335 """ 336 self._set_up_emulator( 337 service_list=[_PAYMENT_SERVICE_1], 338 expected_service=_PAYMENT_SERVICE_1, 339 is_payment=True, 340 payment_default_service=_PAYMENT_SERVICE_1 341 ) 342 343 self._set_up_reader_and_assert_transaction(expected_service=_PAYMENT_SERVICE_1) 344 345 @CddTest(requirements = ["7.4.4/C-2-2", "7.4.4/C-1-2", "9.1/C-0-1"]) 346 def test_single_payment_service_after_reboot(self): 347 """Tests successful APDU exchange between payment service and 348 reader after a reboot. 349 350 Test Steps: 351 1. Set callback handler on emulator for when the instrumentation app is 352 set to default wallet app. 353 2. Reboot the emulator device. 354 3. Start emulator activity and wait for the app to hold the wallet role. 355 4. Start PN532 reader, which should trigger APDU exchange between 356 reader and emulator. 357 358 Verifies: 359 1. Verifies emulator device sets the instrumentation emulator app to the 360 default wallet app. 361 2. Verifies a successful APDU exchange after reboot. 362 """ 363 # Set the role before rebooting and ensure it remains enabled after 364 # reboot to ensure that the NFC stack binds to it at bootup. 365 self._set_up_emulator( 366 service_list=[_PAYMENT_SERVICE_1], 367 expected_service=_PAYMENT_SERVICE_1, 368 is_payment=True, # Set the role holder before reboot. 369 payment_default_service=_PAYMENT_SERVICE_1, 370 should_disable_services_on_destroy=False # Don't disable services on shutdown. 371 ) 372 self._reboot(self.emulator) 373 # Setup the payment service activity to handle the transaction after 374 # reboot. 375 self._set_up_emulator( 376 service_list=[_PAYMENT_SERVICE_1], 377 expected_service=_PAYMENT_SERVICE_1, 378 is_payment=False, # Don't set the role to ensure that state is persisted across reboot. 379 payment_default_service=_PAYMENT_SERVICE_1 380 ) 381 self._set_up_reader_and_assert_transaction(expected_service=_PAYMENT_SERVICE_1) 382 383 384 @CddTest(requirements = ["7.4.4/C-2-2", "7.4.4/C-1-2", "9.1/C-0-1"]) 385 def test_single_payment_service_with_background_app(self): 386 """Tests successful APDU exchange between payment service and 387 reader. 388 389 Test Steps: 390 1. Start emulator activity and wait for the app to hold the wallet role. 391 2. Set callback handler on emulator for when a TestPass event is 392 received. 393 3. Move emulator activity to the background by sending a Home key event. 394 4. Start PN532, which should trigger APDU exchange with the emulator. 395 396 Verifies: 397 1. Verifies emulator device sets the instrumentation emulator app to the 398 default wallet app. 399 2. Verifies a successful APDU exchange. 400 """ 401 self._set_up_emulator( 402 service_list=[_PAYMENT_SERVICE_1], 403 expected_service=_PAYMENT_SERVICE_1, 404 is_payment=True, 405 payment_default_service=_PAYMENT_SERVICE_1 406 ) 407 408 self.emulator.nfc_emulator.pressHome() 409 410 self._set_up_reader_and_assert_transaction(expected_service=_PAYMENT_SERVICE_1) 411 412 def test_single_payment_service_crashes(self): 413 """Tests successful APDU exchange between payment service and 414 reader. 415 416 Test Steps: 417 1. Set callback handler on emulator for when the instrumentation app is 418 set to default wallet app. 419 2. Start emulator activity and wait for the role to be set. 420 2. Set callback handler on emulator for when a TestPass event is 421 received. 422 3. Start PN532, which should trigger APDU exchange with the emulator. 423 424 Verifies: 425 1. Verifies emulator device sets the instrumentation emulator app to the 426 default wallet app. 427 2. Verifies a successful APDU exchange. 428 """ 429 self._set_up_emulator( 430 service_list=[_PAYMENT_SERVICE_1], 431 expected_service=_PAYMENT_SERVICE_1, 432 is_payment=True, 433 payment_default_service=_PAYMENT_SERVICE_1 434 ) 435 436 ps = (self.emulator.adb.shell(["ps", "|", "grep", "com.android.nfc.emulator.payment"]) 437 .decode("utf-8")) 438 pid = ps.split()[1] 439 try: 440 self.emulator.adb.shell(["kill", "-9", pid]) 441 except adb.AdbError: 442 _LOG.info(f"Could not kill pid {pid} through adb.") 443 self.emulator.nfc_emulator.killProcess(pid) 444 445 self._set_up_reader_and_assert_transaction(expected_service=_PAYMENT_SERVICE_1) 446 447 @CddTest(requirements = ["7.4.4/C-2-2", "7.4.4/C-1-2", "9.1/C-0-1"]) 448 def test_dual_payment_service(self): 449 """Tests successful APDU exchange between a payment service and 450 reader when two payment services are set up on the emulator. 451 452 Test Steps: 453 1. Start emulator activity and wait for the role to be set. 454 2. Set callback handler on emulator for when a TestPass event is 455 received. 456 3. Start reader activity, which should trigger APDU exchange between 457 reader and emulator. 458 459 Verifies: 460 1. Verifies a successful APDU exchange. 461 """ 462 self._set_up_emulator( 463 service_list=[_PAYMENT_SERVICE_1,_PAYMENT_SERVICE_2], 464 expected_service=_PAYMENT_SERVICE_1, 465 is_payment=True, 466 payment_default_service=_PAYMENT_SERVICE_1 467 ) 468 469 self._set_up_reader_and_assert_transaction(expected_service=_PAYMENT_SERVICE_1) 470 471 @CddTest(requirements = ["7.4.4/C-2-2", "7.4.4/C-1-2", "9.1/C-0-1"]) 472 def test_foreground_payment_emulator(self): 473 """Tests successful APDU exchange between non-default payment service and 474 reader when the foreground app sets a preference for the non-default 475 service. 476 477 Test Steps: 478 1. Start emulator activity and wait for the role to be set. 479 2. Set callback handler on emulator for when a TestPass event is 480 received. 481 3. Start reader activity, which should trigger APDU exchange between 482 reader and emulator. 483 484 Verifies: 485 1. Verifies a successful APDU exchange. 486 """ 487 self._set_up_emulator( 488 service_list=[_PAYMENT_SERVICE_1, _PAYMENT_SERVICE_2], 489 preferred_service=_PAYMENT_SERVICE_2, 490 expected_service=_PAYMENT_SERVICE_2, 491 is_payment=True, 492 payment_default_service=_PAYMENT_SERVICE_2 493 ) 494 495 self._set_up_reader_and_assert_transaction(expected_service=_PAYMENT_SERVICE_2) 496 497 @CddTest(requirements = ["7.4.4/C-2-2", "7.4.4/C-1-2"]) 498 def test_dynamic_aid_emulator(self): 499 """Tests successful APDU exchange between payment service and reader 500 when the payment service has registered dynamic AIDs. 501 502 Test Steps: 503 1. Start emulator activity and wait for the role to be set. 504 2. Set callback handler on emulator for when a TestPass event is 505 received. 506 3. Start reader activity, which should trigger APDU exchange between 507 reader and emulator. 508 509 Verifies: 510 1. Verifies a successful APDU exchange. 511 """ 512 self._set_up_emulator( 513 start_emulator_fun=self.emulator.nfc_emulator.startDynamicAidEmulatorActivity, 514 payment_default_service=_PAYMENT_SERVICE_DYNAMIC_AIDS 515 ) 516 517 self._set_up_reader_and_assert_transaction(expected_service=_PAYMENT_SERVICE_DYNAMIC_AIDS) 518 519 @CddTest(requirements = ["7.4.4/C-2-2", "7.4.4/C-1-2", "9.1/C-0-1"]) 520 def test_payment_prefix_emulator(self): 521 """Tests successful APDU exchange between payment service and reader 522 when the payment service has statically registered prefix AIDs. 523 524 Test Steps: 525 1. Start emulator activity and wait for the role to be set. 526 2. Set callback handler on emulator for when a TestPass event is 527 received. 528 3. Start reader activity, which should trigger APDU exchange between 529 reader and emulator. 530 531 Verifies: 532 1. Verifies a successful APDU exchange. 533 """ 534 asserts.skip_if(not self.emulator.nfc_emulator.isAidPrefixRegistrationSupported(), 535 "Prefix registration is not supported on device") 536 self._set_up_emulator( 537 start_emulator_fun=self.emulator.nfc_emulator.startPrefixPaymentEmulatorActivity, 538 payment_default_service=_PREFIX_PAYMENT_SERVICE_1, 539 is_payment=True 540 ) 541 542 self._set_up_reader_and_assert_transaction(expected_service=_PREFIX_PAYMENT_SERVICE_1) 543 544 @CddTest(requirements = ["7.4.4/C-2-2", "7.4.4/C-1-2", "9.1/C-0-1"]) 545 def test_prefix_payment_emulator_2(self): 546 """Tests successful APDU exchange between payment service and reader 547 when the payment service has statically registered prefix AIDs. 548 Identical to the test above, except PrefixPaymentService2 is set up 549 first in the emulator activity. 550 551 Test Steps: 552 1. Start emulator activity and wait for the role to be set. 553 2. Set callback handler on emulator for when a TestPass event is 554 received. 555 3. Start reader activity, which should trigger APDU exchange between 556 reader and emulator. 557 558 Verifies: 559 1. Verifies a successful APDU exchange. 560 """ 561 asserts.skip_if(not self.emulator.nfc_emulator.isAidPrefixRegistrationSupported(), 562 "Prefix registration is not supported on device") 563 self._set_up_emulator( 564 start_emulator_fun=self.emulator.nfc_emulator.startPrefixPaymentEmulator2Activity, 565 payment_default_service=_PREFIX_PAYMENT_SERVICE_1, 566 is_payment=True 567 ) 568 569 self._set_up_reader_and_assert_transaction(expected_service=_PREFIX_PAYMENT_SERVICE_1) 570 571 @CddTest(requirements = ["7.4.4/C-2-2", "7.4.4/C-1-2"]) 572 def test_other_prefix(self): 573 """Tests successful APDU exchange when the emulator dynamically 574 registers prefix AIDs for a non-payment service. 575 576 Test steps: 577 1. Start emulator activity. 578 2. Set callback handler on emulator for when ApduSuccess event is 579 received. 580 3. Start reader activity, which should trigger APDU exchange between 581 reader and emulator. 582 583 Verifies: 584 1. Verifies successful APDU sequence exchange. 585 586 """ 587 asserts.skip_if(not self.emulator.nfc_emulator.isAidPrefixRegistrationSupported(), 588 "Prefix registration is not supported on device") 589 self._set_up_emulator( 590 start_emulator_fun=self.emulator.nfc_emulator.startDualNonPaymentPrefixEmulatorActivity) 591 592 self._set_up_reader_and_assert_transaction(expected_service=_PREFIX_ACCESS_SERVICE) 593 594 @CddTest(requirements = ["7.4.4/C-2-2", "7.4.4/C-1-2"]) 595 def test_offhost_service(self): 596 """Tests successful APDU exchange between offhost service and reader. 597 598 Test Steps: 599 1. Start emulator activity. 600 2. Set callback handler for when reader TestPass event is received. 601 3. Start reader activity, which should trigger APDU exchange between 602 reader and emulator. 603 604 Verifies: 605 1. Verifies a successful APDU exchange. 606 """ 607 self._set_up_emulator( 608 False, start_emulator_fun=self.emulator.nfc_emulator.startOffHostEmulatorActivity) 609 610 self._set_up_reader_and_assert_transaction(expected_service=_OFFHOST_SERVICE) 611 612 @CddTest(requirements = ["7.4.4/C-2-2", "7.4.4/C-1-2"]) 613 def test_on_and_offhost_service(self): 614 """Tests successful APDU exchange between when reader selects both an on-host and off-host 615 service. 616 617 Test Steps: 618 1. Start emulator activity. 619 2. Set callback handler for when reader TestPass event is received. 620 3. Start reader activity, which should trigger APDU exchange between 621 reader and emulator. 622 623 Verifies: 624 1. Verifies a successful APDU exchange. 625 """ 626 self._set_up_emulator( 627 start_emulator_fun=self.emulator.nfc_emulator.startOnAndOffHostEmulatorActivity) 628 629 self._set_up_reader_and_assert_transaction(expected_service=_TRANSPORT_SERVICE_1) 630 631 @CddTest(requirements = ["7.4.4/C-2-2", "7.4.4/C-1-2"]) 632 def test_dual_non_payment(self): 633 """Tests successful APDU exchange between transport service and reader 634 when two non-payment services are enabled. 635 636 Test Steps: 637 1. Start emulator activity which sets up TransportService2 and 638 AccessService. 639 2. Start PN532, which should trigger APDU exchange between 640 reader and emulator. 641 642 Verifies: 643 1. Verifies a successful APDU exchange. 644 """ 645 self._set_up_emulator( 646 service_list=[_TRANSPORT_SERVICE_2, _ACCESS_SERVICE], 647 expected_service=_TRANSPORT_SERVICE_2, 648 is_payment=False 649 ) 650 651 self._set_up_reader_and_assert_transaction(expected_service = _TRANSPORT_SERVICE_2) 652 653 @CddTest(requirements = ["7.4.4/C-2-2", "7.4.4/C-1-2"]) 654 def test_foreground_non_payment(self): 655 """Tests successful APDU exchange between non-payment service and 656 reader when the foreground app sets a preference for the 657 non-default service. 658 659 Test Steps: 660 1. Start emulator activity which sets up TransportService1 and 661 TransportService2 662 2. Start PN532, which should trigger APDU exchange between 663 reader and non-default service. 664 665 Verifies: 666 1. Verifies a successful APDU exchange. 667 """ 668 self._set_up_emulator( 669 service_list=[_TRANSPORT_SERVICE_1, _TRANSPORT_SERVICE_2], 670 preferred_service=_TRANSPORT_SERVICE_2, 671 expected_service=_TRANSPORT_SERVICE_2, 672 is_payment=False 673 ) 674 675 self._set_up_reader_and_assert_transaction( 676 expected_service=_TRANSPORT_SERVICE_2) 677 678 @CddTest(requirements = ["7.4.4/C-2-2", "7.4.4/C-1-2"]) 679 def test_throughput(self): 680 """Tests that APDU sequence exchange occurs with under 60ms per APDU. 681 682 Test Steps: 683 1. Start emulator activity. 684 2. Set callback handler on emulator for when a TestPass event is 685 received. 686 3. Start reader activity, which should trigger APDU exchange between 687 reader and non-default service. 688 689 Verifies: 690 1. Verifies a successful APDU exchange between the emulator and the 691 transport service with the duration averaging under 60 ms per single 692 exchange. 693 """ 694 asserts.skip_if("_cf_x86_" in self.emulator.adb.getprop("ro.product.name"), 695 "Skipping throughput test on Cuttlefish") 696 self.emulator.nfc_emulator.startThroughputEmulatorActivity() 697 test_pass_handler = self.emulator.nfc_emulator.asyncWaitForTestPass( 698 'ApduUnderThreshold') 699 command_apdus, response_apdus = get_apdus(self.emulator.nfc_emulator, 700 _THROUGHPUT_SERVICE) 701 poll_and_transact(self.pn532, command_apdus, response_apdus) 702 703 test_pass_handler.waitAndGet('ApduUnderThreshold', _NFC_TIMEOUT_SEC) 704 705 @CddTest(requirements = ["7.4.4/C-2-2", "7.4.4/C-1-2"]) 706 def test_tap_50_times(self): 707 """Tests that 50 consecutive APDU exchanges are successful. 708 709 Test Steps: 710 1. Start emulator activity. 711 2. Perform the following sequence 50 times: 712 a. Set callback handler on emulator for when a TestPass event is 713 received. 714 b. Start PN532. 715 c. Wait for successful APDU exchange. 716 d. Close reader activity. 717 718 Verifies: 719 1. Verifies 50 successful APDU exchanges. 720 """ 721 self._set_up_emulator( 722 service_list=[_TRANSPORT_SERVICE_1], 723 expected_service=_TRANSPORT_SERVICE_1 724 ) 725 726 command_apdus, response_apdus = get_apdus(self.emulator.nfc_emulator, 727 _TRANSPORT_SERVICE_1) 728 for i in range(50): 729 tag_detected, transacted = poll_and_transact(self.pn532, command_apdus, 730 response_apdus) 731 asserts.assert_true( 732 tag_detected, _FAILED_TAG_MSG 733 ) 734 asserts.assert_true(transacted, _FAILED_TRANSACTION_MSG) 735 736 @CddTest(requirements = ["7.4.4/C-2-2", "7.4.4/C-1-2"]) 737 def test_large_num_aids(self): 738 """Tests that a long APDU sequence (256 commands/responses) is 739 successfully exchanged. 740 741 Test Steps: 742 1. Start emulator activity. 743 2. Set callback handler on emulator for when a TestPass event is 744 received. 745 3. Start reader activity. 746 4. Wait for successful APDU exchange. 747 748 Verifies: 749 1. Verifies successful APDU exchange. 750 """ 751 self._set_up_emulator( 752 start_emulator_fun=self.emulator.nfc_emulator.startLargeNumAidsEmulatorActivity 753 ) 754 755 self._set_up_reader_and_assert_transaction(expected_service=_LARGE_NUM_AIDS_SERVICE) 756 757 @CddTest(requirements = ["7.4.4/C-2-2", "7.4.4/C-1-2"]) 758 def test_screen_off_payment(self): 759 """Tests that APDU exchange occurs when device screen is off. 760 761 Test Steps: 762 1. Start emulator activity and wait for the role to be set. 763 2. Turn emulator screen off. 764 3. Start PN532, which should trigger successful APDU exchange. 765 766 Verifies: 767 1. Verifies default wallet app is set. 768 2. Verifies screen is turned off on the emulator. 769 3. Verifies successful APDU exchange with emulator screen off. 770 """ 771 self._set_up_emulator( 772 start_emulator_fun=self.emulator.nfc_emulator.startScreenOffPaymentEmulatorActivity, 773 payment_default_service=_SCREEN_OFF_PAYMENT_SERVICE, 774 is_payment=True 775 ) 776 777 screen_off_handler = self.emulator.nfc_emulator.asyncWaitForScreenOff( 778 'ScreenOff') 779 self.emulator.nfc_emulator.turnScreenOff() 780 screen_off_handler.waitAndGet('ScreenOff', _NFC_TIMEOUT_SEC) 781 782 self._set_up_reader_and_assert_transaction(expected_service=_SCREEN_OFF_PAYMENT_SERVICE) 783 784 @CddTest(requirements = ["7.4.4/C-2-2", "7.4.4/C-1-2"]) 785 def test_conflicting_non_payment(self): 786 """ This test registers two non-payment services with conflicting AIDs, 787 selects a service to use, and ensures the selected service exchanges 788 an APDU sequence with the reader. 789 790 Test Steps: 791 1. Start emulator. 792 2. Start PN532 reader, which should trigger a popup screen of NFC services to select from. 793 3. Select a service on the emulator device from the list of services. 794 4. Set a callback handler on the emulator for a successful APDU 795 exchange. 796 6. Set up reader for transaction, which should trigger the APDU 797 exchange with the selected service. 798 799 Verifies: 800 1. Verifies APDU exchange is successful between the reader and the 801 selected service. 802 """ 803 self._set_up_emulator(service_list=[_TRANSPORT_SERVICE_1,_TRANSPORT_SERVICE_2], 804 expected_service=_TRANSPORT_SERVICE_2, is_payment=False) 805 command_apdus, response_apdus = get_apdus(self.emulator.nfc_emulator, _TRANSPORT_SERVICE_2) 806 poll_and_transact(self.pn532, command_apdus[:1], response_apdus[:1]) 807 808 self.emulator.nfc_emulator.selectItem() 809 810 tag_detected, transacted = poll_and_transact(self.pn532, command_apdus, response_apdus) 811 asserts.assert_true( 812 tag_detected, _FAILED_TAG_MSG 813 ) 814 asserts.assert_true(transacted, _FAILED_TRANSACTION_MSG) 815 816 817 @CddTest(requirements = ["7.4.4/C-2-2", "7.4.4/C-1-2"]) 818 819 @ApiTest( 820 apis = { 821 "android.nfc.cardemulation.CardEmulation.NfcEventCallback#onAidConflictOccurred" 822 }) 823 def test_conflicting_non_payment_prefix(self): 824 """ This test registers two non-payment services with conflicting 825 prefix AIDs, selects a service to use, and ensures the selected 826 service exchanges an APDU sequence with the reader. 827 828 Test Steps: 829 1. Start emulator. 830 2. Start PN532. 831 3. Select a service on the emulator device from the list of services. 832 4. Disable polling on the reader. 833 5. Re-enable polling on the reader, which should trigger the APDU 834 exchange with the selected service. 835 836 Verifies: 837 1. Verifies APDU exchange is successful between the reader and the 838 selected service. 839 """ 840 asserts.skip_if(not self.emulator.nfc_emulator.isAidPrefixRegistrationSupported(), 841 "Prefix registration is not supported on device") 842 self._set_up_emulator( 843 start_emulator_fun= 844 self.emulator.nfc_emulator.startConflictingNonPaymentPrefixEmulatorActivity, 845 is_payment=False 846 ) 847 command_apdus, response_apdus = get_apdus(self.emulator.nfc_emulator, 848 _PREFIX_TRANSPORT_SERVICE_2) 849 test_pass_handler = self.emulator.nfc_emulator.asyncWaitForTestPass( 850 'ApduSuccess' 851 ) 852 poll_and_transact(self.pn532, command_apdus[:1], response_apdus[:1]) 853 854 self.emulator.nfc_emulator.selectItem() 855 tag_detected, transacted = poll_and_transact(self.pn532, command_apdus, response_apdus) 856 asserts.assert_true(tag_detected, _FAILED_TAG_MSG) 857 asserts.assert_true(transacted, _FAILED_TRANSACTION_MSG) 858 859 test_pass_handler.waitAndGet('ApduSuccess', _NFC_TIMEOUT_SEC) 860 861 #@CddTest(requirements = {"TODO"}) 862 @ApiTest( 863 apis = { 864 "android.nfc.cardemulation.CardEmulation.NfcEventCallback#onPreferredServiceChanged", 865 "android.nfc.cardemulation.CardEmulation.NfcEventCallback#onRemoteFieldChanged" 866 }) 867 def test_event_listener(self): 868 """ This test registers an event listener with the emulator and ensures 869 that the event listener receives callbacks when the field status changes and 870 when the preferred service changes. 871 872 Test Steps: 873 1. Start the emulator. 874 2. Start PN532. 875 3. Select a routed AID on the emulator. 876 877 Verifies: 878 1. Verifies that the event listener receives callbacks when the field 879 status changes and when the preferred service changes. 880 """ 881 self._set_up_emulator( 882 start_emulator_fun=self.emulator.nfc_emulator.startEventListenerActivity, 883 is_payment=False 884 ) 885 test_pass_handler = self.emulator.nfc_emulator.asyncWaitForTestPass( 886 "EventListenerSuccess" 887 ) 888 889 command_apdus, response_apdus = get_apdus(self.emulator.nfc_emulator, 890 _TRANSPORT_SERVICE_1) 891 tag_detected, transacted = poll_and_transact(self.pn532, command_apdus, response_apdus) 892 asserts.assert_true(tag_detected, _FAILED_TAG_MSG) 893 asserts.assert_true(transacted, _FAILED_TRANSACTION_MSG) 894 test_pass_handler.waitAndGet("EventListenerSuccess", _NFC_TIMEOUT_SEC) 895 896 897 @CddTest(requirements = ["7.4.4/C-2-2", "7.4.4/C-1-2"]) 898 def test_protocol_params(self): 899 """ Tests that the Nfc-A and ISO-DEP protocol parameters are being 900 set correctly. 901 902 Test Steps: 903 1. Start emulator. 904 2. Start PN532. 905 4. Wait for success event to be sent. 906 907 Verifies: 908 1. Verifies Nfc-A and ISO-DEP protocol parameters are set correctly. 909 """ 910 success = False 911 self._set_up_emulator( 912 service_list=[], 913 expected_service="" 914 ) 915 916 for i in range(_NUM_POLLING_LOOPS): 917 tag = self.pn532.poll_a() 918 msg = None 919 if tag is not None: 920 success, msg = parse_protocol_params(tag.sel_res, tag.ats) 921 self.pn532.mute() 922 break 923 self.pn532.mute() 924 asserts.assert_true(success, msg if msg is not None else _FAILED_TAG_MSG) 925 926 927 @CddTest(requirements = ["7.4.4/C-2-2", "7.4.4/C-1-2"]) 928 def test_screen_on_only_off_host_service(self): 929 """ 930 Test Steps: 931 1. Start emulator. 932 2. Turn screen off. 933 3. Start PN532, and ensure expected APDU exchange occurs. 934 4. Turn screen off. 935 5. Start PN532, and ensure expected APDU exchange occurs. 936 937 938 Verifies: 939 1. Verifies correct APDU response when screen is off. 940 2. Verifies correct APDU response between reader and off-host service 941 when screen is on. 942 """ 943 #Tests APDU exchange with screen off. 944 self._set_up_emulator( 945 start_emulator_fun=self.emulator.nfc_emulator.startScreenOnOnlyOffHostEmulatorActivity 946 ) 947 self.emulator.nfc_emulator.turnScreenOff() 948 screen_off_handler = self.emulator.nfc_emulator.asyncWaitForScreenOff( 949 'ScreenOff') 950 screen_off_handler.waitAndGet('ScreenOff', _NFC_TIMEOUT_SEC) 951 952 self._set_up_reader_and_assert_transaction( 953 expected_service=_SCREEN_ON_ONLY_OFF_HOST_SERVICE) 954 955 self.pn532.mute() 956 957 #Tests APDU exchange with screen on. 958 screen_on_handler = self.emulator.nfc_emulator.asyncWaitForScreenOn( 959 'ScreenOn') 960 self.emulator.nfc_emulator.pressMenu() 961 screen_on_handler.waitAndGet('ScreenOn', _NFC_TIMEOUT_SEC) 962 963 self._set_up_reader_and_assert_transaction(expected_service= 964 _SCREEN_ON_ONLY_OFF_HOST_SERVICE) 965 966 def test_single_payment_service_toggle_nfc_off_on(self): 967 """Tests successful APDU exchange between payment service and 968 reader. 969 970 Test Steps: 971 1. Start emulator activity and wait for the role to be set. 972 2. Toggle NFC off and back on the emulator. 973 3. Set callback handler on emulator for when a TestPass event is 974 received. 975 4. Start reader activity, which should trigger APDU exchange between 976 reader and emulator. 977 978 Verifies: 979 1. Verifies emulator device sets the instrumentation emulator app to the 980 default wallet app. 981 2. Verifies a successful APDU exchange after toggling NFC off and on. 982 """ 983 # Wait for instrumentation app to hold onto wallet role before starting 984 # reader 985 self._set_up_emulator( 986 service_list=[_PAYMENT_SERVICE_1], 987 expected_service=_PAYMENT_SERVICE_1, 988 is_payment=True, 989 payment_default_service=_PAYMENT_SERVICE_1 990 ) 991 992 self.emulator.nfc_emulator.setNfcState(False) 993 self.emulator.nfc_emulator.setNfcState(True) 994 995 self._set_up_reader_and_assert_transaction(expected_service=_PAYMENT_SERVICE_1) 996 997 @CddTest(requirements = ["7.4.4/C-1-13"]) 998 def test_polling_frame_timestamp(self): 999 """Tests that PollingFrame object timestamp values are reported correctly 1000 and do not deviate from host measurements 1001 1002 Test Steps: 1003 1. Toggle NFC reader field OFF 1004 2. Start emulator activity 1005 3. Perform a polling loop, wait for field OFF event. 1006 4. Collect polling frames. Iterate over matching polling loop frame 1007 and device time measurements. Calculate elapsed time for each and verify 1008 that the host-device difference does not exceed the delay threshold. 1009 1010 Verifies: 1011 1. Verifies that timestamp values are reported properly 1012 for each tested frame type. 1013 2. Verifies that the difference between matching host and device 1014 timestamps does not exceed _POLLING_FRAME_TIMESTAMP_TOLERANCE_MS. 1015 """ 1016 asserts.skip_if(not self.emulator.nfc_emulator.isObserveModeSupported(), 1017 "Skipping polling frame timestamp test, observe mode not supported") 1018 1019 # 1. Mute the field before starting the emulator 1020 # in order to be able to trigger ON event when the test starts 1021 self.pn532.mute() 1022 1023 # 2. Start emulator activity 1024 self._set_up_emulator( 1025 start_emulator_fun=self.emulator.nfc_emulator.startPollingFrameEmulatorActivity 1026 ) 1027 1028 timed_pn532 = TimedWrapper(self.pn532) 1029 testcases = [ 1030 POLLING_FRAME_ON, 1031 *POLLING_FRAMES_TYPE_A_SPECIAL, 1032 *POLLING_FRAMES_TYPE_A_SPECIAL, 1033 *POLLING_FRAMES_TYPE_A_LONG, 1034 *POLLING_FRAMES_TYPE_A_LONG, 1035 *POLLING_FRAMES_TYPE_B_SPECIAL, 1036 *POLLING_FRAMES_TYPE_B_SPECIAL, 1037 *POLLING_FRAMES_TYPE_B_LONG, 1038 *POLLING_FRAMES_TYPE_B_LONG, 1039 *POLLING_FRAMES_TYPE_F_SPECIAL, 1040 *POLLING_FRAMES_TYPE_F_SPECIAL, 1041 POLLING_FRAME_OFF, 1042 ] 1043 # 3. Transmit polling frames 1044 frames = poll_and_observe_frames( 1045 pn532=timed_pn532, 1046 emulator=self.emulator.nfc_emulator, 1047 testcases=testcases, 1048 restore_original_frame_ordering=True 1049 ) 1050 timings = timed_pn532.timings 1051 1052 # Pre-format data for error if one happens 1053 frame_stats = get_frame_test_stats( 1054 frames=frames, 1055 testcases=testcases, 1056 timestamps=[ns_to_us(timestamp) for (_, timestamp) in timings] 1057 ) 1058 1059 # Check that there are as many polling loop events as frames sent 1060 asserts.assert_equal( 1061 len(testcases), len(frames), 1062 _FAILED_MISSING_POLLING_FRAMES_MSG, 1063 frame_stats 1064 ) 1065 1066 # For each event, calculate the amount of time elapsed since the previous one 1067 # Subtract the resulting host/device time delta values 1068 # Verify that the difference does not exceed the threshold 1069 previous_timestamp_device = None 1070 first_timestamp_start, first_timestamp_end = timings[0] 1071 first_timestamp = (first_timestamp_start + first_timestamp_end) / 2 1072 first_timestamp_error = (first_timestamp_end - first_timestamp_start)/ 2 1073 first_timestamp_device = frames[0].timestamp 1074 1075 num_exceeding_threshold = 0 1076 for idx, (frame, timing, testcase) in enumerate(zip(frames, timings, testcases)): 1077 timestamp_host_start, timestamp_host_end = timing 1078 timestamp_host = (timestamp_host_start + timestamp_host_end) / 2 1079 timestamp_error = (timestamp_host_end - timestamp_host_start) / 2 1080 timestamp_device = frame.timestamp 1081 1082 _LOG.debug( 1083 f"{testcase.data.upper():32}" + \ 1084 f" ({testcase.configuration.type}" + \ 1085 f", {'+' if testcase.configuration.crc else '-'}" + \ 1086 f", {testcase.configuration.bits})" + \ 1087 f" -> {frame.data.hex().upper():32} ({frame.type})" 1088 ) 1089 1090 pre_previous_timestamp_device = previous_timestamp_device 1091 previous_timestamp_device = timestamp_device 1092 1093 # Skip cases when timestamp value wraps 1094 # as there's no way to establish the delta 1095 # and re-establish the baselines 1096 if (timestamp_device - first_timestamp_device) < 0: 1097 _LOG.warning( 1098 "Timestamp value wrapped" + \ 1099 f" from {pre_previous_timestamp_device}" + \ 1100 f" to {previous_timestamp_device} for frame {frame};" + \ 1101 " Skipping comparison..." 1102 ) 1103 first_timestamp_device = timestamp_device 1104 first_timestamp = timestamp_host 1105 first_timestamp_error = timestamp_error 1106 continue 1107 1108 device_host_difference = us_to_ms(timestamp_device - first_timestamp_device) - \ 1109 ns_to_ms(timestamp_host - first_timestamp) 1110 total_error = ns_to_ms(timestamp_error + first_timestamp_error) 1111 if abs(device_host_difference) > _POLLING_FRAME_TIMESTAMP_TOLERANCE_MS + total_error: 1112 debug_info = { 1113 "index": idx, 1114 "frame_sent": testcase.format_for_error(timestamp=ns_to_us(timestamp_host)), 1115 "frame_received": frame.to_dict(), 1116 "difference": device_host_difference, 1117 "time_device": us_to_ms(timestamp_device - first_timestamp_device), 1118 "time_host": ns_to_ms(timestamp_host - first_timestamp), 1119 "total_error": total_error, 1120 } 1121 num_exceeding_threshold = num_exceeding_threshold + 1 1122 _LOG.warning(f"Polling frame timestamp tolerance exceeded: {debug_info}") 1123 asserts.assert_less(num_exceeding_threshold, 1124 _POLLING_FRAME_TIMESTAMP_EXCEED_COUNT_TOLERANCE_) 1125 1126 @CddTest(requirements = ["7.4.4/C-1-13"]) 1127 def test_polling_frame_vendor_specific_gain(self): 1128 """Tests that PollingFrame object vendorSpecificGain value 1129 changes when overall NFC reader output power changes 1130 1131 Test Steps: 1132 1. Toggle NFC reader field OFF 1133 2. Start emulator activity 1134 3. For each power level (0-100% with 20% step), send polling loop 1135 consisting of normally encountered polling frames 1136 4. For each result, calculate average vendorSpecificGain per NFC mode 1137 compare those values against the previous power step, and assert that 1138 they are equal or bigger than the previous one 1139 1140 Verifies: 1141 1. Verifies that vendorSpecificGain value increases or stays the same 1142 when PN532 output power increases. 1143 """ 1144 asserts.skip_if(not self.emulator.nfc_emulator.isObserveModeSupported(), 1145 "Skipping polling frame gain test, observe mode not supported") 1146 1147 self.pn532.mute() 1148 emulator = self.emulator.nfc_emulator 1149 1150 self._set_up_emulator( 1151 start_emulator_fun=emulator.startPollingFrameEmulatorActivity 1152 ) 1153 1154 # Loop two times so that HostEmulationManager releases all frames 1155 testcases = [ 1156 POLLING_FRAME_ON, 1157 *POLLING_FRAMES_TYPE_A_SPECIAL, 1158 *POLLING_FRAMES_TYPE_B_SPECIAL, 1159 *POLLING_FRAMES_TYPE_F_SPECIAL, 1160 POLLING_FRAME_OFF 1161 ] * 2 1162 1163 # 6 steps; 0%, 20%, 40%, 60%, 80%, 100% 1164 power_levels = [0, 1, 2, 3, 4, 5] 1165 polling_frame_types = ("A", "B", "F") 1166 1167 results_for_power_level = {} 1168 1169 for power_level in power_levels: 1170 # Warning for 0% might appear, 1171 # as it's possible for no events to be produced 1172 frames = poll_and_observe_frames( 1173 testcases=testcases, 1174 pn532=self.pn532, 1175 emulator=emulator, 1176 # Scale from 0 to 100% 1177 power_level = power_level * 20, 1178 ignore_field_off_event_timeout=power_level == 0 1179 ) 1180 1181 frames_for_type = { 1182 type_: [ 1183 f.vendor_specific_gain for f in frames if f.type == type_ 1184 ] for type_ in polling_frame_types 1185 } 1186 results_for_power_level[power_level] = { 1187 # If no frames for type, assume gain is negative -1 1188 type_: (sum(frames) / len(frames)) if len(frames) else -1 1189 for type_, frames in frames_for_type.items() 1190 } 1191 1192 _LOG.debug(f"Polling frame gain results {results_for_power_level}") 1193 1194 issues = [] 1195 for power_level in power_levels: 1196 # No value to compare to 1197 if power_level == 0: 1198 continue 1199 1200 for type_ in polling_frame_types: 1201 previous_gain = results_for_power_level[power_level - 1][type_] 1202 current_gain = results_for_power_level[power_level][type_] 1203 if current_gain >= previous_gain: 1204 continue 1205 sample = { 1206 "type": type_, 1207 "power_level": power_level * 20, 1208 "previous_gain": previous_gain, 1209 "current_gain": current_gain, 1210 } 1211 _LOG.warning( 1212 f"Reported gain level dropped" + \ 1213 f" between power steps {sample}" 1214 ) 1215 issues.append(sample) 1216 1217 # Allow up to 2 reported gain decreases out of (5 * 3) = 15 test samples 1218 # Theoretically, this could happen 1219 # due to automatic power/gain/load management feature of chipsets 1220 asserts.assert_true( 1221 len(issues) <= 2, 1222 _FAILED_VENDOR_GAIN_VALUE_DROPPED_ON_POWER_INCREASE, 1223 ) 1224 1225 @CddTest(requirements = ["7.4.4/C-1-13"]) 1226 def test_polling_frame_type(self): 1227 """Tests that PollingFrame object 'type' value is set correctly 1228 1229 Test Steps: 1230 1. Toggle NFC reader field OFF 1231 2. Start emulator activity 1232 3. Perform a polling loop, wait for field OFF event. 1233 4. Collect polling frames. Iterate over sent and received frame pairs, 1234 verify that polling frame type matches. 1235 1236 Verifies: 1237 1. Verifies that PollingFrame.type value is set correctly 1238 """ 1239 asserts.skip_if(not self.emulator.nfc_emulator.isObserveModeSupported(), 1240 "Skipping polling frame type test, observe mode not supported") 1241 self.pn532.mute() 1242 emulator = self.emulator.nfc_emulator 1243 1244 self._set_up_emulator( 1245 start_emulator_fun=emulator.startPollingFrameEmulatorActivity 1246 ) 1247 1248 testcases = POLLING_FRAME_ALL_TEST_CASES 1249 1250 # 3. Transmit polling frames 1251 frames = poll_and_observe_frames( 1252 pn532=self.pn532, 1253 emulator=self.emulator.nfc_emulator, 1254 testcases=testcases, 1255 restore_original_frame_ordering=True, 1256 ) 1257 1258 # Check that there are as many polling loop events as frames sent 1259 asserts.assert_equal( 1260 len(testcases), len(frames), 1261 _FAILED_MISSING_POLLING_FRAMES_MSG, 1262 get_frame_test_stats(frames=frames, testcases=testcases) 1263 ) 1264 1265 issues = [ 1266 { 1267 "index": idx, 1268 "expected": testcase.success_types, 1269 "received": frame.type, 1270 "data": frame.data.hex(), 1271 } for idx, (testcase, frame) in enumerate(zip(testcases, frames)) 1272 if frame.type not in testcase.success_types 1273 ] 1274 1275 asserts.assert_equal(len(issues), 0, _FAILED_FRAME_TYPE_INVALID, issues) 1276 1277 @CddTest(requirements = ["7.4.4/C-1-13"]) 1278 def test_polling_frame_data(self): 1279 """Tests that PollingFrame object 'data' value is set correctly 1280 1281 Test Steps: 1282 1. Toggle NFC reader field OFF 1283 2. Start emulator activity 1284 3. Perform a polling loop, wait for field OFF event. 1285 4. Collect polling frames. Iterate over sent and received frame pairs, 1286 verify that polling frame type matches. 1287 1288 Verifies: 1289 1. Verifies that PollingFrame.data value is set correctly 1290 """ 1291 asserts.skip_if(not self.emulator.nfc_emulator.isObserveModeSupported(), 1292 "Skipping polling frame data test, observe mode not supported") 1293 self.pn532.mute() 1294 emulator = self.emulator.nfc_emulator 1295 1296 self._set_up_emulator( 1297 start_emulator_fun=emulator.startPollingFrameEmulatorActivity 1298 ) 1299 1300 testcases = POLLING_FRAME_ALL_TEST_CASES 1301 1302 # 3. Transmit polling frames 1303 frames = poll_and_observe_frames( 1304 pn532=self.pn532, 1305 emulator=self.emulator.nfc_emulator, 1306 testcases=testcases, 1307 restore_original_frame_ordering=True, 1308 ) 1309 1310 # Check that there are as many polling loop events as frames sent 1311 asserts.assert_equal( 1312 len(testcases), len(frames), 1313 _FAILED_MISSING_POLLING_FRAMES_MSG, 1314 get_frame_test_stats(frames=frames, testcases=testcases) 1315 ) 1316 1317 issues = [ 1318 { 1319 "index": idx, 1320 "expected": testcase.expected_data, 1321 "received": frame.data.hex() 1322 } for idx, (testcase, frame) in enumerate(zip(testcases, frames)) 1323 if frame.data.hex() not in testcase.expected_data 1324 ] 1325 1326 for testcase, frame in zip(testcases, frames): 1327 if frame.data.hex() not in testcase.warning_data: 1328 continue 1329 _LOG.warning( 1330 f"Polling frame data variation '{frame.data.hex()}'" + \ 1331 f" is accepted but not correct {testcase.success_data}" 1332 ) 1333 1334 asserts.assert_equal(len(issues), 0, _FAILED_FRAME_DATA_INVALID, issues) 1335 1336 def teardown_test(self): 1337 if hasattr(self, 'emulator') and hasattr(self.emulator, 'nfc_emulator'): 1338 self.emulator.nfc_emulator.closeActivity() 1339 self.emulator.nfc_emulator.logInfo( 1340 "*** TEST END: " + self.current_test_info.name + " ***") 1341 if hasattr(self, 'pn532'): 1342 self.pn532.reset_buffers() 1343 self.pn532.mute() 1344 if hasattr(self, 'emulator'): 1345 param_list = [[self.emulator]] 1346 utils.concurrent_exec(lambda d: d.services.create_output_excerpts_all( 1347 self.current_test_info), 1348 param_list=param_list, 1349 raise_on_exception=True) 1350 1351 #@CddTest(requirements = {"7.4.4/C-2-2", "7.4.4/C-1-2"}) 1352 def test_single_non_payment_service_with_listen_tech_disabled(self): 1353 """Tests successful APDU exchange between non-payment service and 1354 reader does not proceed when Type-a listen tech is disabled. 1355 1356 Test Steps: 1357 1. Start emulator activity and set up non-payment HCE Service. 1358 2. Set listen tech to disabled on the emulator. 1359 3. Start PN532 and verify transaction does not proceed. 1360 5. Set listen tech to Type-A on the emulator. 1361 6. Start PN532 and verify APDU exchange between reader and emulator. 1362 1363 Verifies: 1364 1. Verifies that no APDU exchange occurs when the listen tech is disabled. 1365 2. Verifies a successful APDU exchange after re-enabling. 1366 """ 1367 self._set_up_emulator(service_list=[_TRANSPORT_SERVICE_1], 1368 expected_service=_TRANSPORT_SERVICE_1, is_payment=False) 1369 self.emulator.nfc_emulator.setListenTech(_NFC_LISTEN_OFF) 1370 1371 test_pass_handler = self.emulator.nfc_emulator.asyncWaitForTestPass( 1372 'ApduSuccess') 1373 1374 command_apdus, response_apdus = get_apdus(self.emulator.nfc_emulator, _TRANSPORT_SERVICE_1) 1375 tag_detected, transacted = poll_and_transact(self.pn532, command_apdus[:1], 1376 response_apdus[:1]) 1377 asserts.assert_false(tag_detected, "Tag is detected unexpectedly!") 1378 asserts.assert_false(transacted, "Transaction is completed unexpectedly!") 1379 1380 # Set listen on 1381 self.emulator.nfc_emulator.setListenTech(_NFC_TECH_A_LISTEN_ON) 1382 tag_detected, transacted = poll_and_transact(self.pn532, command_apdus[:1], 1383 response_apdus[:1]) 1384 asserts.assert_true(tag_detected, _FAILED_TAG_MSG) 1385 asserts.assert_true(transacted, _FAILED_TRANSACTION_MSG) 1386 1387 1388 #@CddTest(requirements = {"7.4.4/C-2-2", "7.4.4/C-1-2"}) 1389 def test_single_non_payment_service_with_listen_tech_poll_tech_mismatch(self): 1390 """Tests successful APDU exchange between non-payment service and 1391 reader does not proceed when emulator listen tech mismatches reader poll tech. 1392 1393 Test Steps: 1394 1. Start emulator activity and set up non-payment HCE Service. 1395 2. Set listen tech to Type-F on the emulator. 1396 3. Start PN532 and verify transaction does not proceed. 1397 4. Set listen tech to Type-A on the emulator. 1398 6. Start PN532 and verify APDU exchange between reader and emulator. 1399 1400 Verifies: 1401 1. Verifies that no APDU exchange occurs when the listen tech mismatches with poll tech. 1402 2. Verifies a successful APDU exchange when no longer mismatched. 1403 """ 1404 self._set_up_emulator(service_list=[_TRANSPORT_SERVICE_1], 1405 expected_service=_TRANSPORT_SERVICE_1, is_payment=False) 1406 # Set listen to Type-F 1407 self.emulator.nfc_emulator.setListenTech(_NFC_TECH_F_LISTEN_ON) 1408 1409 command_apdus, response_apdus = get_apdus(self.emulator.nfc_emulator, _TRANSPORT_SERVICE_1) 1410 tag_detected, transacted = poll_and_transact(self.pn532, command_apdus[:1], 1411 response_apdus[:1]) 1412 asserts.assert_false(tag_detected, "Tag is detected unexpectedly!") 1413 asserts.assert_false(transacted, "Transaction is completed unexpectedly!") 1414 1415 # Set listen to Type-A 1416 self.emulator.nfc_emulator.setListenTech(_NFC_TECH_A_LISTEN_ON) 1417 tag_detected, transacted = poll_and_transact(self.pn532, command_apdus[:1], response_apdus[:1]) 1418 asserts.assert_true(tag_detected, _FAILED_TAG_MSG) 1419 asserts.assert_true(transacted, _FAILED_TRANSACTION_MSG) 1420 1421if __name__ == '__main__': 1422 # Take test args 1423 if '--' in sys.argv: 1424 index = sys.argv.index('--') 1425 sys.argv = sys.argv[:1] + sys.argv[index + 1:] 1426 test_runner.main() 1427