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.nxp; 18 19 import com.android.nfc.DeviceHost; 20 import com.android.nfc.LlcpException; 21 import com.android.nfc.NfcService; 22 23 import android.annotation.SdkConstant; 24 import android.annotation.SdkConstant.SdkConstantType; 25 import android.content.Context; 26 import android.content.SharedPreferences; 27 import android.nfc.ErrorCodes; 28 import android.nfc.tech.Ndef; 29 import android.nfc.tech.TagTechnology; 30 import android.util.Log; 31 32 import java.io.File; 33 34 /** 35 * Native interface to the NFC Manager functions 36 */ 37 public class NativeNfcManager implements DeviceHost { 38 private static final String TAG = "NativeNfcManager"; 39 40 private static final String NFC_CONTROLLER_FIRMWARE_FILE_NAME = "/vendor/firmware/libpn544_fw.so"; 41 42 private static final String PREF = "NxpDeviceHost"; 43 44 private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime"; 45 private static final long FIRMWARE_MODTIME_DEFAULT = -1; 46 47 static { 48 System.loadLibrary("nfc_jni"); 49 } 50 51 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) 52 public static final String INTERNAL_TARGET_DESELECTED_ACTION = "com.android.nfc.action.INTERNAL_TARGET_DESELECTED"; 53 54 /* Native structure */ 55 private int mNative; 56 57 private final DeviceHostListener mListener; 58 private final Context mContext; 59 60 public NativeNfcManager(Context context, DeviceHostListener listener) { 61 mListener = listener; 62 initializeNativeStructure(); 63 mContext = context; 64 } 65 66 public native boolean initializeNativeStructure(); 67 68 private native boolean doDownload(); 69 70 @Override 71 public void checkFirmware() { 72 // Check that the NFC controller firmware is up to date. This 73 // ensures that firmware updates are applied in a timely fashion, 74 // and makes it much less likely that the user will have to wait 75 // for a firmware download when they enable NFC in the settings 76 // app. Firmware download can take some time, so this should be 77 // run in a separate thread. 78 79 // check the timestamp of the firmware file 80 File firmwareFile; 81 int nbRetry = 0; 82 try { 83 firmwareFile = new File(NFC_CONTROLLER_FIRMWARE_FILE_NAME); 84 } catch(NullPointerException npe) { 85 Log.e(TAG,"path to firmware file was null"); 86 return; 87 } 88 89 long modtime = firmwareFile.lastModified(); 90 91 SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); 92 long prev_fw_modtime = prefs.getLong(PREF_FIRMWARE_MODTIME, FIRMWARE_MODTIME_DEFAULT); 93 Log.d(TAG,"prev modtime: " + prev_fw_modtime); 94 Log.d(TAG,"new modtime: " + modtime); 95 if (prev_fw_modtime == modtime) { 96 return; 97 } 98 99 // FW download. 100 while(nbRetry < 5) { 101 Log.d(TAG,"Perform Download"); 102 if(doDownload()) { 103 Log.d(TAG,"Download Success"); 104 // Now that we've finished updating the firmware, save the new modtime. 105 prefs.edit().putLong(PREF_FIRMWARE_MODTIME, modtime).apply(); 106 break; 107 } else { 108 Log.d(TAG,"Download Failed"); 109 nbRetry++; 110 } 111 } 112 } 113 114 @Override 115 public native boolean initialize(); 116 117 @Override 118 public native boolean deinitialize(); 119 120 @Override 121 public native void enableDiscovery(); 122 123 @Override 124 public native void disableDiscovery(); 125 126 @Override 127 public native int[] doGetSecureElementList(); 128 129 @Override 130 public native void doSelectSecureElement(); 131 132 @Override 133 public native void doDeselectSecureElement(); 134 135 @Override 136 public native int doGetLastError(); 137 138 private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap); 139 140 private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu, 141 int rw, int linearBufferLength); 142 @Override 143 public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu, 144 int rw, int linearBufferLength) throws LlcpException { 145 LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength); 146 if (socket != null) { 147 return socket; 148 } else { 149 /* Get Error Status */ 150 int error = doGetLastError(); 151 152 Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); 153 154 switch (error) { 155 case ErrorCodes.ERROR_BUFFER_TO_SMALL: 156 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: 157 throw new LlcpException(error); 158 default: 159 throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); 160 } 161 } 162 } 163 164 private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw, 165 int linearBufferLength); 166 @Override 167 public LlcpSocket createLlcpSocket(int sap, int miu, int rw, 168 int linearBufferLength) throws LlcpException { 169 LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength); 170 if (socket != null) { 171 return socket; 172 } else { 173 /* Get Error Status */ 174 int error = doGetLastError(); 175 176 Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); 177 178 switch (error) { 179 case ErrorCodes.ERROR_BUFFER_TO_SMALL: 180 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: 181 throw new LlcpException(error); 182 default: 183 throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); 184 } 185 } 186 } 187 188 @Override 189 public native boolean doCheckLlcp(); 190 191 @Override 192 public native boolean doActivateLlcp(); 193 194 private native void doResetTimeouts(); 195 196 @Override 197 public void resetTimeouts() { 198 doResetTimeouts(); 199 } 200 201 public native void doAbort(); 202 203 private native boolean doSetTimeout(int tech, int timeout); 204 @Override 205 public boolean setTimeout(int tech, int timeout) { 206 return doSetTimeout(tech, timeout); 207 } 208 209 private native int doGetTimeout(int tech); 210 @Override 211 public int getTimeout(int tech) { 212 return doGetTimeout(tech); 213 } 214 215 216 @Override 217 public boolean canMakeReadOnly(int ndefType) { 218 return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2); 219 } 220 221 @Override 222 public int getMaxTransceiveLength(int technology) { 223 switch (technology) { 224 case (TagTechnology.NFC_A): 225 case (TagTechnology.MIFARE_CLASSIC): 226 case (TagTechnology.MIFARE_ULTRALIGHT): 227 return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC 228 case (TagTechnology.NFC_B): 229 return 0; // PN544 does not support transceive of raw NfcB 230 case (TagTechnology.NFC_V): 231 return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC 232 case (TagTechnology.ISO_DEP): 233 /* The maximum length of a normal IsoDep frame consists of: 234 * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes 235 * such a frame is supported. Extended length frames however 236 * are not supported. 237 */ 238 return 261; // Will be automatically split in two frames on the RF layer 239 case (TagTechnology.NFC_F): 240 return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC 241 default: 242 return 0; 243 } 244 245 } 246 247 private native String doDump(); 248 @Override 249 public String dump() { 250 return doDump(); 251 } 252 253 /** 254 * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered) 255 */ 256 private void notifyNdefMessageListeners(NativeNfcTag tag) { 257 mListener.onRemoteEndpointDiscovered(tag); 258 } 259 260 /** 261 * Notifies transaction 262 */ 263 private void notifyTargetDeselected() { 264 mListener.onCardEmulationDeselected(); 265 } 266 267 /** 268 * Notifies transaction 269 */ 270 private void notifyTransactionListeners(byte[] aid) { 271 mListener.onCardEmulationAidSelected(aid); 272 } 273 274 /** 275 * Notifies P2P Device detected, to activate LLCP link 276 */ 277 private void notifyLlcpLinkActivation(NativeP2pDevice device) { 278 mListener.onLlcpLinkActivated(device); 279 } 280 281 /** 282 * Notifies P2P Device detected, to activate LLCP link 283 */ 284 private void notifyLlcpLinkDeactivated(NativeP2pDevice device) { 285 mListener.onLlcpLinkDeactivated(device); 286 } 287 288 private void notifySeFieldActivated() { 289 mListener.onRemoteFieldActivated(); 290 } 291 292 private void notifySeFieldDeactivated() { 293 mListener.onRemoteFieldDeactivated(); 294 } 295 296 private void notifySeApduReceived(byte[] apdu) { 297 mListener.onSeApduReceived(apdu); 298 } 299 300 private void notifySeEmvCardRemoval() { 301 mListener.onSeEmvCardRemoval(); 302 } 303 304 private void notifySeMifareAccess(byte[] block) { 305 mListener.onSeMifareAccess(block); 306 } 307 } 308