Home | History | Annotate | Download | only in dhimpl
      1 /*
      2  * Copyright (C) 2010 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 package com.android.nfc.dhimpl;
     18 
     19 import com.android.nfc.DeviceHost;
     20 import com.android.nfc.LlcpException;
     21 
     22 import android.annotation.SdkConstant;
     23 import android.annotation.SdkConstant.SdkConstantType;
     24 import android.content.Context;
     25 import android.content.SharedPreferences;
     26 import android.nfc.ErrorCodes;
     27 import android.nfc.tech.Ndef;
     28 import android.nfc.tech.TagTechnology;
     29 import android.util.Log;
     30 
     31 import java.io.File;
     32 
     33 /**
     34  * Native interface to the NFC Manager functions
     35  */
     36 public class NativeNfcManager implements DeviceHost {
     37     private static final String TAG = "NativeNfcManager";
     38 
     39     private static final String NFC_CONTROLLER_FIRMWARE_FILE_NAME = "/vendor/firmware/libpn544_fw.so";
     40 
     41     static final String PREF = "NxpDeviceHost";
     42 
     43     private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime";
     44     private static final long FIRMWARE_MODTIME_DEFAULT = -1;
     45 
     46     static final String DRIVER_NAME = "nxp";
     47 
     48     static final int DEFAULT_LLCP_MIU = 128;
     49     static final int DEFAULT_LLCP_RWSIZE = 1;
     50 
     51     //TODO: dont hardcode this
     52     private static final byte[][] EE_WIPE_APDUS = {
     53         {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
     54         {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00,
     55                 (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x20, (byte)0x10, (byte)0x00},
     56         {(byte)0x80, (byte)0xe2, (byte)0x01, (byte)0x03, (byte)0x00},
     57         {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
     58         {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00,
     59                 (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x30, (byte)0x30, (byte)0x00},
     60         {(byte)0x80, (byte)0xb4, (byte)0x00, (byte)0x00, (byte)0x00},
     61         {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
     62     };
     63 
     64 
     65     static {
     66         System.loadLibrary("nfc_jni");
     67     }
     68 
     69     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     70     public static final String INTERNAL_TARGET_DESELECTED_ACTION = "com.android.nfc.action.INTERNAL_TARGET_DESELECTED";
     71 
     72     /* Native structure */
     73     private int mNative;
     74 
     75     private final DeviceHostListener mListener;
     76     private final Context mContext;
     77 
     78     public NativeNfcManager(Context context, DeviceHostListener listener) {
     79         mListener = listener;
     80         initializeNativeStructure();
     81         mContext = context;
     82     }
     83 
     84     public native boolean initializeNativeStructure();
     85 
     86     private native boolean doDownload();
     87 
     88     public native int doGetLastError();
     89 
     90     @Override
     91     public void checkFirmware() {
     92         // Check that the NFC controller firmware is up to date.  This
     93         // ensures that firmware updates are applied in a timely fashion,
     94         // and makes it much less likely that the user will have to wait
     95         // for a firmware download when they enable NFC in the settings
     96         // app.  Firmware download can take some time, so this should be
     97         // run in a separate thread.
     98 
     99         // check the timestamp of the firmware file
    100         File firmwareFile;
    101         int nbRetry = 0;
    102         try {
    103             firmwareFile = new File(NFC_CONTROLLER_FIRMWARE_FILE_NAME);
    104         } catch(NullPointerException npe) {
    105             Log.e(TAG,"path to firmware file was null");
    106             return;
    107         }
    108 
    109         long modtime = firmwareFile.lastModified();
    110 
    111         SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
    112         long prev_fw_modtime = prefs.getLong(PREF_FIRMWARE_MODTIME, FIRMWARE_MODTIME_DEFAULT);
    113         Log.d(TAG,"prev modtime: " + prev_fw_modtime);
    114         Log.d(TAG,"new modtime: " + modtime);
    115         if (prev_fw_modtime == modtime) {
    116             return;
    117         }
    118 
    119         // FW download.
    120         while(nbRetry < 5) {
    121             Log.d(TAG,"Perform Download");
    122             if(doDownload()) {
    123                 Log.d(TAG,"Download Success");
    124                 // Now that we've finished updating the firmware, save the new modtime.
    125                 prefs.edit().putLong(PREF_FIRMWARE_MODTIME, modtime).apply();
    126                 break;
    127             } else {
    128                 Log.d(TAG,"Download Failed");
    129                 nbRetry++;
    130             }
    131         }
    132     }
    133 
    134     private native boolean doInitialize();
    135 
    136     @Override
    137     public boolean initialize() {
    138         SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
    139         SharedPreferences.Editor editor = prefs.edit();
    140 
    141         if (prefs.getBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false)) {
    142             try {
    143                 Thread.sleep (12000);
    144                 editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false);
    145                 editor.apply();
    146             } catch (InterruptedException e) { }
    147         }
    148 
    149         return doInitialize();
    150     }
    151 
    152     private native boolean doDeinitialize();
    153 
    154     @Override
    155     public boolean deinitialize() {
    156         SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
    157         SharedPreferences.Editor editor = prefs.edit();
    158 
    159         editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false);
    160         editor.apply();
    161 
    162         return doDeinitialize();
    163     }
    164 
    165     @Override
    166     public String getName() {
    167         return DRIVER_NAME;
    168     }
    169 
    170     @Override
    171     public native void enableDiscovery();
    172 
    173     @Override
    174     public native void disableDiscovery();
    175 
    176     @Override
    177     public native int[] doGetSecureElementList();
    178 
    179     @Override
    180     public native void doSelectSecureElement();
    181 
    182     @Override
    183     public native void doDeselectSecureElement();
    184 
    185 
    186     private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap,
    187             String sn);
    188 
    189     @Override
    190     public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn)
    191             throws LlcpException {
    192         LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn);
    193         if (socket != null) {
    194             return socket;
    195         } else {
    196             /* Get Error Status */
    197             int error = doGetLastError();
    198 
    199             Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
    200 
    201             switch (error) {
    202                 case ErrorCodes.ERROR_BUFFER_TO_SMALL:
    203                 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
    204                     throw new LlcpException(error);
    205                 default:
    206                     throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
    207             }
    208         }
    209     }
    210 
    211     private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu,
    212             int rw, int linearBufferLength);
    213     @Override
    214     public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu,
    215             int rw, int linearBufferLength) throws LlcpException {
    216         LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength);
    217         if (socket != null) {
    218             return socket;
    219         } else {
    220             /* Get Error Status */
    221             int error = doGetLastError();
    222 
    223             Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
    224 
    225             switch (error) {
    226                 case ErrorCodes.ERROR_BUFFER_TO_SMALL:
    227                 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
    228                     throw new LlcpException(error);
    229                 default:
    230                     throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
    231             }
    232         }
    233     }
    234 
    235     private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw,
    236             int linearBufferLength);
    237     @Override
    238     public LlcpSocket createLlcpSocket(int sap, int miu, int rw,
    239             int linearBufferLength) throws LlcpException {
    240         LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength);
    241         if (socket != null) {
    242             return socket;
    243         } else {
    244             /* Get Error Status */
    245             int error = doGetLastError();
    246 
    247             Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
    248 
    249             switch (error) {
    250                 case ErrorCodes.ERROR_BUFFER_TO_SMALL:
    251                 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
    252                     throw new LlcpException(error);
    253                 default:
    254                     throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
    255             }
    256         }
    257     }
    258 
    259     @Override
    260     public native boolean doCheckLlcp();
    261 
    262     @Override
    263     public native boolean doActivateLlcp();
    264 
    265     private native void doResetTimeouts();
    266 
    267     @Override
    268     public void resetTimeouts() {
    269         doResetTimeouts();
    270     }
    271 
    272     @Override
    273     public native void doAbort();
    274 
    275     private native boolean doSetTimeout(int tech, int timeout);
    276     @Override
    277     public boolean setTimeout(int tech, int timeout) {
    278         return doSetTimeout(tech, timeout);
    279     }
    280 
    281     private native int doGetTimeout(int tech);
    282     @Override
    283     public int getTimeout(int tech) {
    284         return doGetTimeout(tech);
    285     }
    286 
    287 
    288     @Override
    289     public boolean canMakeReadOnly(int ndefType) {
    290         return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2 ||
    291                 ndefType == Ndef.TYPE_MIFARE_CLASSIC);
    292     }
    293 
    294     @Override
    295     public int getMaxTransceiveLength(int technology) {
    296         switch (technology) {
    297             case (TagTechnology.NFC_A):
    298             case (TagTechnology.MIFARE_CLASSIC):
    299             case (TagTechnology.MIFARE_ULTRALIGHT):
    300                 return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
    301             case (TagTechnology.NFC_B):
    302                 return 0; // PN544 does not support transceive of raw NfcB
    303             case (TagTechnology.NFC_V):
    304                 return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
    305             case (TagTechnology.ISO_DEP):
    306                 /* The maximum length of a normal IsoDep frame consists of:
    307                  * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes
    308                  * such a frame is supported. Extended length frames however
    309                  * are not supported.
    310                  */
    311                 return 261; // Will be automatically split in two frames on the RF layer
    312             case (TagTechnology.NFC_F):
    313                 return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC
    314             default:
    315                 return 0;
    316         }
    317 
    318     }
    319 
    320     private native void doSetP2pInitiatorModes(int modes);
    321     @Override
    322     public void setP2pInitiatorModes(int modes) {
    323         doSetP2pInitiatorModes(modes);
    324     }
    325 
    326     private native void doSetP2pTargetModes(int modes);
    327     @Override
    328     public void setP2pTargetModes(int modes) {
    329         doSetP2pTargetModes(modes);
    330     }
    331 
    332     @Override
    333     public boolean getExtendedLengthApdusSupported() {
    334         // Not supported on the PN544
    335         return false;
    336     }
    337 
    338     @Override
    339     public boolean enablePN544Quirks() {
    340         return true;
    341     }
    342 
    343     @Override
    344     public byte[][] getWipeApdus() {
    345         return EE_WIPE_APDUS;
    346     }
    347 
    348     @Override
    349     public int getDefaultLlcpMiu() {
    350         return DEFAULT_LLCP_MIU;
    351     }
    352 
    353     @Override
    354     public int getDefaultLlcpRwSize() {
    355         return DEFAULT_LLCP_RWSIZE;
    356     }
    357 
    358     private native String doDump();
    359     @Override
    360     public String dump() {
    361         return doDump();
    362     }
    363 
    364     /**
    365      * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered)
    366      */
    367     private void notifyNdefMessageListeners(NativeNfcTag tag) {
    368         mListener.onRemoteEndpointDiscovered(tag);
    369     }
    370 
    371     /**
    372      * Notifies transaction
    373      */
    374     private void notifyTargetDeselected() {
    375         mListener.onCardEmulationDeselected();
    376     }
    377 
    378     /**
    379      * Notifies transaction
    380      */
    381     private void notifyTransactionListeners(byte[] aid) {
    382         mListener.onCardEmulationAidSelected(aid);
    383     }
    384 
    385     /**
    386      * Notifies P2P Device detected, to activate LLCP link
    387      */
    388     private void notifyLlcpLinkActivation(NativeP2pDevice device) {
    389         mListener.onLlcpLinkActivated(device);
    390     }
    391 
    392     /**
    393      * Notifies P2P Device detected, to activate LLCP link
    394      */
    395     private void notifyLlcpLinkDeactivated(NativeP2pDevice device) {
    396         mListener.onLlcpLinkDeactivated(device);
    397     }
    398 
    399     private void notifySeFieldActivated() {
    400         mListener.onRemoteFieldActivated();
    401     }
    402 
    403     private void notifySeFieldDeactivated() {
    404         mListener.onRemoteFieldDeactivated();
    405     }
    406 
    407     private void notifySeApduReceived(byte[] apdu) {
    408         mListener.onSeApduReceived(apdu);
    409     }
    410 
    411     private void notifySeEmvCardRemoval() {
    412         mListener.onSeEmvCardRemoval();
    413     }
    414 
    415     private void notifySeMifareAccess(byte[] block) {
    416         mListener.onSeMifareAccess(block);
    417     }
    418 
    419 }
    420