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 boolean sendRawFrame(byte[] data)
    172     {
    173         return false;
    174     }
    175 
    176     @Override
    177     public boolean routeAid(byte[] aid, int route)
    178     {
    179         return false;
    180     }
    181 
    182     @Override
    183     public boolean unrouteAid(byte[] aid)
    184     {
    185        return false;
    186     }
    187 
    188     @Override
    189     public native void enableDiscovery();
    190 
    191     @Override
    192     public native void disableDiscovery();
    193 
    194     @Override
    195     public void enableRoutingToHost()
    196     {
    197 
    198     }
    199 
    200     @Override
    201     public void disableRoutingToHost()
    202     {
    203 
    204     }
    205 
    206     @Override
    207     public native int[] doGetSecureElementList();
    208 
    209     @Override
    210     public native void doSelectSecureElement();
    211 
    212     @Override
    213     public native void doDeselectSecureElement();
    214 
    215 
    216     private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap,
    217             String sn);
    218 
    219     @Override
    220     public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn)
    221             throws LlcpException {
    222         LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn);
    223         if (socket != null) {
    224             return socket;
    225         } else {
    226             /* Get Error Status */
    227             int error = doGetLastError();
    228 
    229             Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
    230 
    231             switch (error) {
    232                 case ErrorCodes.ERROR_BUFFER_TO_SMALL:
    233                 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
    234                     throw new LlcpException(error);
    235                 default:
    236                     throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
    237             }
    238         }
    239     }
    240 
    241     private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu,
    242             int rw, int linearBufferLength);
    243     @Override
    244     public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu,
    245             int rw, int linearBufferLength) throws LlcpException {
    246         LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength);
    247         if (socket != null) {
    248             return socket;
    249         } else {
    250             /* Get Error Status */
    251             int error = doGetLastError();
    252 
    253             Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
    254 
    255             switch (error) {
    256                 case ErrorCodes.ERROR_BUFFER_TO_SMALL:
    257                 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
    258                     throw new LlcpException(error);
    259                 default:
    260                     throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
    261             }
    262         }
    263     }
    264 
    265     private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw,
    266             int linearBufferLength);
    267     @Override
    268     public LlcpSocket createLlcpSocket(int sap, int miu, int rw,
    269             int linearBufferLength) throws LlcpException {
    270         LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength);
    271         if (socket != null) {
    272             return socket;
    273         } else {
    274             /* Get Error Status */
    275             int error = doGetLastError();
    276 
    277             Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
    278 
    279             switch (error) {
    280                 case ErrorCodes.ERROR_BUFFER_TO_SMALL:
    281                 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
    282                     throw new LlcpException(error);
    283                 default:
    284                     throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
    285             }
    286         }
    287     }
    288 
    289     @Override
    290     public native boolean doCheckLlcp();
    291 
    292     @Override
    293     public native boolean doActivateLlcp();
    294 
    295     private native void doResetTimeouts();
    296 
    297     @Override
    298     public void resetTimeouts() {
    299         doResetTimeouts();
    300     }
    301 
    302     @Override
    303     public native void doAbort();
    304 
    305     private native boolean doSetTimeout(int tech, int timeout);
    306     @Override
    307     public boolean setTimeout(int tech, int timeout) {
    308         return doSetTimeout(tech, timeout);
    309     }
    310 
    311     private native int doGetTimeout(int tech);
    312     @Override
    313     public int getTimeout(int tech) {
    314         return doGetTimeout(tech);
    315     }
    316 
    317 
    318     @Override
    319     public boolean canMakeReadOnly(int ndefType) {
    320         return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2 ||
    321                 ndefType == Ndef.TYPE_MIFARE_CLASSIC);
    322     }
    323 
    324     @Override
    325     public int getMaxTransceiveLength(int technology) {
    326         switch (technology) {
    327             case (TagTechnology.NFC_A):
    328             case (TagTechnology.MIFARE_CLASSIC):
    329             case (TagTechnology.MIFARE_ULTRALIGHT):
    330                 return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
    331             case (TagTechnology.NFC_B):
    332                 return 0; // PN544 does not support transceive of raw NfcB
    333             case (TagTechnology.NFC_V):
    334                 return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
    335             case (TagTechnology.ISO_DEP):
    336                 /* The maximum length of a normal IsoDep frame consists of:
    337                  * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes
    338                  * such a frame is supported. Extended length frames however
    339                  * are not supported.
    340                  */
    341                 return 261; // Will be automatically split in two frames on the RF layer
    342             case (TagTechnology.NFC_F):
    343                 return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC
    344             default:
    345                 return 0;
    346         }
    347 
    348     }
    349 
    350     private native void doSetP2pInitiatorModes(int modes);
    351     @Override
    352     public void setP2pInitiatorModes(int modes) {
    353         doSetP2pInitiatorModes(modes);
    354     }
    355 
    356     private native void doSetP2pTargetModes(int modes);
    357     @Override
    358     public void setP2pTargetModes(int modes) {
    359         doSetP2pTargetModes(modes);
    360     }
    361 
    362     private native void doEnableReaderMode(int technologies);
    363     public boolean enableReaderMode(int technologies) {
    364         doEnableReaderMode(technologies);
    365         return true;
    366     }
    367 
    368     private native void doDisableReaderMode();
    369     public boolean disableReaderMode() {
    370         doDisableReaderMode();
    371         return true;
    372     }
    373 
    374     @Override
    375     public boolean getExtendedLengthApdusSupported() {
    376         // Not supported on the PN544
    377         return false;
    378     }
    379 
    380     @Override
    381     public boolean enablePN544Quirks() {
    382         return true;
    383     }
    384 
    385     @Override
    386     public byte[][] getWipeApdus() {
    387         return EE_WIPE_APDUS;
    388     }
    389 
    390     @Override
    391     public int getDefaultLlcpMiu() {
    392         return DEFAULT_LLCP_MIU;
    393     }
    394 
    395     @Override
    396     public int getDefaultLlcpRwSize() {
    397         return DEFAULT_LLCP_RWSIZE;
    398     }
    399 
    400     private native String doDump();
    401     @Override
    402     public String dump() {
    403         return doDump();
    404     }
    405 
    406     /**
    407      * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered)
    408      */
    409     private void notifyNdefMessageListeners(NativeNfcTag tag) {
    410         mListener.onRemoteEndpointDiscovered(tag);
    411     }
    412 
    413     /**
    414      * Notifies transaction
    415      */
    416     private void notifyTargetDeselected() {
    417         mListener.onCardEmulationDeselected();
    418     }
    419 
    420     /**
    421      * Notifies transaction
    422      */
    423     private void notifyTransactionListeners(byte[] aid) {
    424         mListener.onCardEmulationAidSelected(aid);
    425     }
    426 
    427     /**
    428      * Notifies P2P Device detected, to activate LLCP link
    429      */
    430     private void notifyLlcpLinkActivation(NativeP2pDevice device) {
    431         mListener.onLlcpLinkActivated(device);
    432     }
    433 
    434     /**
    435      * Notifies P2P Device detected, to activate LLCP link
    436      */
    437     private void notifyLlcpLinkDeactivated(NativeP2pDevice device) {
    438         mListener.onLlcpLinkDeactivated(device);
    439     }
    440 
    441     private void notifySeFieldActivated() {
    442         mListener.onRemoteFieldActivated();
    443     }
    444 
    445     private void notifySeFieldDeactivated() {
    446         mListener.onRemoteFieldDeactivated();
    447     }
    448 
    449     private void notifySeApduReceived(byte[] apdu) {
    450         mListener.onSeApduReceived(apdu);
    451     }
    452 
    453     private void notifySeEmvCardRemoval() {
    454         mListener.onSeEmvCardRemoval();
    455     }
    456 
    457     private void notifySeMifareAccess(byte[] block) {
    458         mListener.onSeMifareAccess(block);
    459     }
    460 
    461 }
    462