MifareClassic#get() throws NPE
Expected Behavior
The test app (see below) can read Mifare Classic tags and displays details about it.
Current Behavior
When trying to read a MifareClassic tag, the call to MifareClassic#get()
results in a NullPointerException. This behavior seems consistent for all Mifare Classic tags I have tried.
Logcat: alogcat.2020-11-14-23-47-31+0100.txt
Possible Solution
This Stackoverflow post suggests this behavior was introduced by https://review.lineageos.org/c/LineageOS/android_frameworks_base/+/256596/5/core/java/android/nfc/tech/NfcA.java. Specifically:
public NfcA(Tag tag) throws RemoteException {
super(tag, TagTechnology.NFC_A);
Bundle extras;
mSak = 0;
if(tag.hasTech(TagTechnology.MIFARE_CLASSIC))
{
extras = tag.getTechExtras(TagTechnology.MIFARE_CLASSIC);
mSak = extras.getShort(EXTRA_SAK); // NPE thrown here
}
extras = tag.getTechExtras(TagTechnology.NFC_A);
mSak |= extras.getShort(EXTRA_SAK);
mAtqa = extras.getByteArray(EXTRA_ATQA);
}
The change introduces the if
statement to deal with Mifare Classic tags in a special manner, as well as some logic to merge the data obtained from two sets of tech extras. It assumes that, if a tag reports MifareClassic as a supported tech, it will always come with non-null extras for that technology. Evidently, that is not the case.
I see two options to resolve this:
Option 1: Add a null check, replacing
mSak = extras.getShort(EXTRA_SAK);
(the line where the NPE is thrown) with
if (extras != null)
mSak = extras.getShort(EXTRA_SAK);
—at the expense of whatever fix/functionality the commit in question aimed to introduce will not work under certain circumstances, and we wouldn’t even know (though that could be alleviated by adding a log message).
Option 2: Figure out why under some circumstances Mifare Classic tags come without any extras for that technology, and if it turns out that this is unintended behavior, fix that.
This is an area I am not familiar with, but according to the change, its author (Puneet Mishra) seems associated with NXP, so I’d expect he’d either know or have access to someone who does.
The original author of the test app also has an app-side workaround, which includes catching the exception thrown by MifareClassic#get()
, rewriting the Tag
argument and retrying the call with the tweaked Tag
. It was originally developed for some Xperia model (presumably with the stock OS) but it also works around this bug here. See https://github.com/nadam/nfc-reader/blob/master/src/se/anyro/nfc_reader/TagViewer.java#L261.
Steps to Reproduce
- Get an NFC test app: https://github.com/mvglasow/nfc-reader
- Check out
d7f0f9549
(important—some other branches and later commits may incorporate a workaround that defeats reproduction) - Build and install the app (
gradle build && gradle installDebug
) - Read a MifareClassic tag (tested with a Fréjus Road Tunnel subscription card as well as various hotel room keys, all of which implement MifareClassic)
/device bacon /version lineage-17.1 /date 2020-10-29 /kernel 3.4.113-lineageos-g5f610fb #1 Thu Oct 29 92:28:41 UTC 2020 /baseband DI.3.0.c6-00241-M897AAAAANAZM-1 /mods Magisk, microG
I have read the directions.