Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enabling CardEmulation on Android ICS with NFC_EXTRAS

I need help with NFC and Android.

After making a lot of research to enable the emulation of a Mifare 4K on Android, I've found that the only patch that exists was made for 2.3.4. Here in StackOverFlow, NFCGuy told us since API 14 of Android it's not neccesary patch the ROM, so we can turn on card emulation using the hidden Nfc_extras package.

I've compiled an APK using NFC_EXTRAS with reflection, and added my signature and package to the nfcee_access.xml.

After I set cardEmulationRoute to ON_WHEN_SCREEN_ON, I get an output in logcat telling me that NFCEE is ON and NFC_CC is ON, but when I get my Nexus S close to a ACR122 it does not detect the Emulated Mifare 4K that 2.3.4 patch makers could get. I can get an unrecognized Smart Card (I suppose that it's the SE acting like a smartcard) but i need to use the emulated Mifare.

Do I need to modify lib-nfc as it was modify in 2.3.4 patch to get that applet working (Mifare Manager)? Or with my app accesing that package should be enought?

I'm downloading the android source to port the 2.3.4 patch to 4.1, but looking at the diff they've posted, there is only a difference with 4.1 on lib-nfc library. (A define commented, used for card emulation in theory)

Maybe it's not necesary to recompile a modified ROM and I'm missing a small step to get the emulated Mifare 4k.

Thanks for your help to all people here in StackOverFlow

Regards

    private void getSecureElement(){
    try{
        //Obtenemos la clase NFCAdapterExtras
        Class nfcExtrasClazz = Class.forName("com.android.nfc_extras.NfcAdapterExtras");

        if (nfcExtrasClazz == null){
            Log.w("EnableCardEmu", "No existe la clase Extras");
            return;
        }

        Log.w("EnableCardEmu", "Existe la clase");

        //Obtenemos el método "get" de dicha clase
        Method getMethod = nfcExtrasClazz.getMethod("get", Class.forName("android.nfc.NfcAdapter"));

        if (getMethod == null) {
            Log.w("EnableCardEmu", "No existe el método");
        } else {
            Log.w("EnableCardEmu", "Existe el método");
            //Obtenemos el manager del componente NFC del dispositivo
            NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this);

            if (adapter == null)
                Log.w("EnableCardEmu", "Adapter es null");
            else {
                //Instancia del SecureElement
                Log.w("EnableCardEmu", "Adapter NO es null");
                nfcExtras = getMethod.invoke(null, adapter);

                Method getEEMethod = nfcExtras.getClass().getMethod("getEmbeddedExecutionEnvironment", 
                        (Class[]) null);
                embebbed = getEEMethod.invoke(nfcExtras , (Object[]) null);
            }
        }
    } catch (InvocationTargetException ee){
        Log.w("EnableCardEmu", ee.getTargetException());
    }
    catch (Exception e){
        Log.w("EnableCardEmu", e.getClass().getName() + " / " + e.getMessage());
        StackTraceElement[] a = e.getStackTrace();
        for (StackTraceElement aa : a){
            Log.w("EnableCardEmu", aa.toString());
        }
    } 
}

    private void deactivateCardEmulation(){
    try{
        Class clss = Class.forName("com.android.nfc_extras.NfcAdapterExtras");
        Class[] cs = clss.getDeclaredClasses();
        /*          
        for (Class cc : cs){
            Log.w("EnableCardEmu", cc.getName();)
        }*/

        //Class route = Class.forName("com.android.nfc_extras.NfcAdapterExtras$CardEmulationRoute");
        Constructor c = cs[0].getConstructor(Integer.TYPE, Class.forName("com.android.nfc_extras.NfcExecutionEnvironment"));
        Object routeOn = c.newInstance(1, null);

        Class cls = nfcExtras.getClass();           
        Method mtd = cls.getMethod("setCardEmulationRoute", cs[0]);
        mtd.invoke(nfcExtras, routeOn);
    } catch (InvocationTargetException ee){
        Log.w("EnableCardEmu", ee.getTargetException());
    } catch (Exception e){
        Log.w("EnableCardEmu", e.getClass().getName() + " / " + e.getMessage());
    }
}

    private void activateCardEmulation(){
    try{

        Class clss = Class.forName("com.android.nfc_extras.NfcAdapterExtras");
        Class[] cs = clss.getDeclaredClasses();
        /*          
        for (Class cc : cs){
            Log.w("EnableCardEmu", cc.getName();)
        }*/

        //Class route = Class.forName("com.android.nfc_extras.NfcAdapterExtras$CardEmulationRoute");
        Constructor c = cs[0].getConstructor(Integer.TYPE, Class.forName("com.android.nfc_extras.NfcExecutionEnvironment"));
        Object routeOn = c.newInstance(2, embebbed);

        Class cls = nfcExtras.getClass();           
        Method mtd = cls.getMethod("setCardEmulationRoute", cs[0]);
        mtd.invoke(nfcExtras, routeOn);
    } catch (InvocationTargetException ee){
        Log.w("EnableCardEmu", ee.getTargetException());
    } catch (Exception e){
        Log.w("EnableCardEmu", e.getClass().getName() + " / " + e.getMessage());
    }
}
like image 916
noni Avatar asked Oct 18 '12 13:10

noni


2 Answers

I think the problem could be in Object routeOn = c.newInstance(2, embebbed). It looks like this object is of the wrong type (I am not an expert on reading reflection code, though).

This is how I do it, without reflection, and it works fine (both an ISO 14443-4A card and a MIFARE Classic card are emulated by the device simultaneously):

Context mContext; // initialize this
NfcAdapterExtras mAdapterExtras =
  NfcAdapterExtras.get(NfcAdapter.getDefaultAdapter(mContext));
NfcExecutionEnvironment mEe = mAdapterExtras.getEmbeddedExecutionEnvironment();
mAdapterExtras.setCardEmulationRoute(
  new CardEmulationRoute(CardEmulationRoute.ROUTE_ON_WHEN_SCREEN_ON, mEe));

No need to modify libnfc-nxp for this.

like image 56
NFC guy Avatar answered Nov 20 '22 19:11

NFC guy


It seems that your code should be properly enabling card emulation mode. I was also attempting the same thing and encountered a similar problem, where I could not detect the phone with my MIFARE compatible RFID reader.

What turned out to be the cause was that the phone I was working with had NFC support but did not have an embedded secure element installed. The secure element resided on the SIM card instead and the built-in NFC support in ICS 4.0.3 was not able to locate and use that secure element.

This same brand/model of phone has an embedded secure element when sold through some cell providers but not through my provider.

I got my first hint that this was the cause when I attempted to do an "open" on my instance of the NfcExecutionEnvironment and the following output showed up in my logcat:

D/NFC JNI (  911): phLibNfc_SE_GetSecureElementList()
D/NFC JNI (  911): 
D/NFC JNI (  911): > Number of Secure Element(s) : 0
E/NFC JNI (  911): phLibNfc_SE_GetSecureElementList(): No SMX detected
like image 35
Patrick Avatar answered Nov 20 '22 17:11

Patrick