Search code examples
androidnfcandroid-10.0

MifareClassic#get() throws NPE on Android 10 (but not on Android 8)


I have just migrated from Android 8 to 10, and my NFC test app now starts throwing an NPE whenever reading a Mifare tag. Other tags seem to work (specifically one supporting NfcV, NdefFormatable).

Stack trace:

E/AndroidRuntime( 1277): java.lang.NullPointerException: Attempt to invoke virtual method 'short android.os.Bundle.getShort(java.lang.String)' on a null object reference
E/AndroidRuntime( 1277):    at android.nfc.tech.NfcA.<init>(NfcA.java:76)
E/AndroidRuntime( 1277):    at android.nfc.tech.NfcA.get(NfcA.java:62)
E/AndroidRuntime( 1277):    at android.nfc.tech.MifareClassic.<init>(MifareClassic.java:150)
E/AndroidRuntime( 1277):    at android.nfc.tech.MifareClassic.get(MifareClassic.java:140)
E/AndroidRuntime( 1277):    at myapp.nfc_reader.TagViewer.dumpTagData(TagViewer.java:201)

Upon receiving an NFC intent, the app does this:

Parcelable p = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
Tag tag = (Tag) p;
for (String tech : tag.getTechList()) {
    if (tech.equals(MifareClassic.class.getName())) {
        MifareClassic mifareTag = MifareClassic.get(tag);
        // more code here
    }
}

Apparently Tag has a non-public Bundle member, which is null on Android 10 and causes the NPE. This has worked on Android 8 (LineageOS 15.1) but fails on Android 10 (LineageOS 17.1; the device is a OnePlus One).

Is that a bug in the OS or am I doing something wrong?


Solution

  • Looks like an OS Bug

    This change looks suspect https://review.lineageos.org/c/LineageOS/android_frameworks_base/+/256596/5/core/java/android/nfc/tech/NfcA.java

    First introduced in lineage-17.0 (Android 10 release)

    why the code below has the useless if statement I've no idea that does nothing useful because mSak and mAtqa are reset using the stock Android code straight after the useless if and line 76 is in the useless if

        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);
            }
            extras = tag.getTechExtras(TagTechnology.NFC_A);
            mSak |= extras.getShort(EXTRA_SAK);
            mAtqa = extras.getByteArray(EXTRA_ATQA);
        }
    

    this is not what is in stock Android https://android.googlesource.com/platform/frameworks/base/+/refs/heads/android10-release/core/java/android/nfc/tech/NfcA.java

    [Following edited by another user] This is fixed with this patch. https://review.lineageos.org/c/LineageOS/android_packages_apps_Nfc/+/306229