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 import com.android.nfc.NfcDiscoveryParameters; 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 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 final String DRIVER_NAME = "nxp"; 48 49 static final int DEFAULT_LLCP_MIU = 128; 50 static final int DEFAULT_LLCP_RWSIZE = 1; 51 52 static { 53 System.loadLibrary("nfc_jni"); 54 } 55 56 /* Native structure */ 57 private long mNative; 58 59 private final DeviceHostListener mListener; 60 private final Context mContext; 61 NativeNfcManager(Context context, DeviceHostListener listener)62 public NativeNfcManager(Context context, DeviceHostListener listener) { 63 mListener = listener; 64 initializeNativeStructure(); 65 mContext = context; 66 } 67 initializeNativeStructure()68 public native boolean initializeNativeStructure(); 69 doDownload()70 private native boolean doDownload(); 71 doGetLastError()72 public native int doGetLastError(); 73 74 @Override checkFirmware()75 public void checkFirmware() { 76 // Check that the NFC controller firmware is up to date. This 77 // ensures that firmware updates are applied in a timely fashion, 78 // and makes it much less likely that the user will have to wait 79 // for a firmware download when they enable NFC in the settings 80 // app. Firmware download can take some time, so this should be 81 // run in a separate thread. 82 83 // check the timestamp of the firmware file 84 File firmwareFile; 85 int nbRetry = 0; 86 try { 87 firmwareFile = new File(NFC_CONTROLLER_FIRMWARE_FILE_NAME); 88 } catch(NullPointerException npe) { 89 Log.e(TAG,"path to firmware file was null"); 90 return; 91 } 92 93 long modtime = firmwareFile.lastModified(); 94 95 SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE); 96 long prev_fw_modtime = prefs.getLong(PREF_FIRMWARE_MODTIME, FIRMWARE_MODTIME_DEFAULT); 97 Log.d(TAG,"prev modtime: " + prev_fw_modtime); 98 Log.d(TAG,"new modtime: " + modtime); 99 if (prev_fw_modtime == modtime) { 100 return; 101 } 102 103 // FW download. 104 while(nbRetry < 5) { 105 Log.d(TAG,"Perform Download"); 106 if(doDownload()) { 107 Log.d(TAG,"Download Success"); 108 // Now that we've finished updating the firmware, save the new modtime. 109 prefs.edit().putLong(PREF_FIRMWARE_MODTIME, modtime).apply(); 110 break; 111 } else { 112 Log.d(TAG,"Download Failed"); 113 nbRetry++; 114 } 115 } 116 } 117 doInitialize()118 private native boolean doInitialize(); 119 120 @Override initialize()121 public boolean initialize() { 122 return doInitialize(); 123 } 124 doDeinitialize()125 private native boolean doDeinitialize(); 126 127 @Override deinitialize()128 public boolean deinitialize() { 129 return doDeinitialize(); 130 } 131 132 @Override getName()133 public String getName() { 134 return DRIVER_NAME; 135 } 136 137 @Override sendRawFrame(byte[] data)138 public boolean sendRawFrame(byte[] data) 139 { 140 return false; 141 } 142 143 @Override routeAid(byte[] aid, int route)144 public boolean routeAid(byte[] aid, int route) 145 { 146 return false; 147 } 148 149 @Override unrouteAid(byte[] aid)150 public boolean unrouteAid(byte[] aid) 151 { 152 return false; 153 } 154 155 @Override commitRouting()156 public boolean commitRouting() 157 { 158 return false; 159 } 160 doEnableDiscovery(int techMask, boolean enableLowPowerPolling, boolean enableReaderMode, boolean enableP2p, boolean restart)161 private native void doEnableDiscovery(int techMask, 162 boolean enableLowPowerPolling, 163 boolean enableReaderMode, 164 boolean enableP2p, 165 boolean restart); 166 @Override enableDiscovery(NfcDiscoveryParameters params, boolean restart)167 public void enableDiscovery(NfcDiscoveryParameters params, boolean restart) { 168 doEnableDiscovery(params.getTechMask(), params.shouldEnableLowPowerDiscovery(), 169 params.shouldEnableReaderMode(), params.shouldEnableP2p(), restart); 170 } 171 172 @Override disableDiscovery()173 public native void disableDiscovery(); 174 doCreateLlcpConnectionlessSocket(int nSap, String sn)175 private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap, 176 String sn); 177 178 @Override createLlcpConnectionlessSocket(int nSap, String sn)179 public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn) 180 throws LlcpException { 181 LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn); 182 if (socket != null) { 183 return socket; 184 } else { 185 /* Get Error Status */ 186 int error = doGetLastError(); 187 188 Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); 189 190 switch (error) { 191 case ErrorCodes.ERROR_BUFFER_TO_SMALL: 192 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: 193 throw new LlcpException(error); 194 default: 195 throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); 196 } 197 } 198 } 199 doCreateLlcpServiceSocket(int nSap, String sn, int miu, int rw, int linearBufferLength)200 private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu, 201 int rw, int linearBufferLength); 202 @Override createLlcpServerSocket(int nSap, String sn, int miu, int rw, int linearBufferLength)203 public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu, 204 int rw, int linearBufferLength) throws LlcpException { 205 LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength); 206 if (socket != null) { 207 return socket; 208 } else { 209 /* Get Error Status */ 210 int error = doGetLastError(); 211 212 Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); 213 214 switch (error) { 215 case ErrorCodes.ERROR_BUFFER_TO_SMALL: 216 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: 217 throw new LlcpException(error); 218 default: 219 throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); 220 } 221 } 222 } 223 doCreateLlcpSocket(int sap, int miu, int rw, int linearBufferLength)224 private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw, 225 int linearBufferLength); 226 @Override createLlcpSocket(int sap, int miu, int rw, int linearBufferLength)227 public LlcpSocket createLlcpSocket(int sap, int miu, int rw, 228 int linearBufferLength) throws LlcpException { 229 LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength); 230 if (socket != null) { 231 return socket; 232 } else { 233 /* Get Error Status */ 234 int error = doGetLastError(); 235 236 Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); 237 238 switch (error) { 239 case ErrorCodes.ERROR_BUFFER_TO_SMALL: 240 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: 241 throw new LlcpException(error); 242 default: 243 throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); 244 } 245 } 246 } 247 248 @Override doCheckLlcp()249 public native boolean doCheckLlcp(); 250 251 @Override doActivateLlcp()252 public native boolean doActivateLlcp(); 253 doResetTimeouts()254 private native void doResetTimeouts(); 255 256 @Override resetTimeouts()257 public void resetTimeouts() { 258 doResetTimeouts(); 259 } 260 261 @Override doAbort()262 public native void doAbort(); 263 doSetTimeout(int tech, int timeout)264 private native boolean doSetTimeout(int tech, int timeout); 265 @Override setTimeout(int tech, int timeout)266 public boolean setTimeout(int tech, int timeout) { 267 return doSetTimeout(tech, timeout); 268 } 269 doGetTimeout(int tech)270 private native int doGetTimeout(int tech); 271 @Override getTimeout(int tech)272 public int getTimeout(int tech) { 273 return doGetTimeout(tech); 274 } 275 276 277 @Override canMakeReadOnly(int ndefType)278 public boolean canMakeReadOnly(int ndefType) { 279 return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2 || 280 ndefType == Ndef.TYPE_MIFARE_CLASSIC); 281 } 282 283 @Override getMaxTransceiveLength(int technology)284 public int getMaxTransceiveLength(int technology) { 285 switch (technology) { 286 case (TagTechnology.NFC_A): 287 case (TagTechnology.MIFARE_CLASSIC): 288 case (TagTechnology.MIFARE_ULTRALIGHT): 289 return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC 290 case (TagTechnology.NFC_B): 291 return 0; // PN544 does not support transceive of raw NfcB 292 case (TagTechnology.NFC_V): 293 return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC 294 case (TagTechnology.ISO_DEP): 295 /* The maximum length of a normal IsoDep frame consists of: 296 * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes 297 * such a frame is supported. Extended length frames however 298 * are not supported. 299 */ 300 return 261; // Will be automatically split in two frames on the RF layer 301 case (TagTechnology.NFC_F): 302 return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC 303 default: 304 return 0; 305 } 306 307 } 308 doSetP2pInitiatorModes(int modes)309 private native void doSetP2pInitiatorModes(int modes); 310 @Override setP2pInitiatorModes(int modes)311 public void setP2pInitiatorModes(int modes) { 312 doSetP2pInitiatorModes(modes); 313 } 314 doSetP2pTargetModes(int modes)315 private native void doSetP2pTargetModes(int modes); 316 @Override setP2pTargetModes(int modes)317 public void setP2pTargetModes(int modes) { 318 doSetP2pTargetModes(modes); 319 } 320 321 @Override enableScreenOffSuspend()322 public boolean enableScreenOffSuspend() { 323 // Snooze mode not supported on NXP silicon 324 Log.i(TAG, "Snooze mode is not supported on NXP NFCC"); 325 return false; 326 } 327 328 @Override disableScreenOffSuspend()329 public boolean disableScreenOffSuspend() { 330 // Snooze mode not supported on NXP silicon 331 Log.i(TAG, "Snooze mode is not supported on NXP NFCC"); 332 return true; 333 } 334 335 @Override getExtendedLengthApdusSupported()336 public boolean getExtendedLengthApdusSupported() { 337 // Not supported on the PN544 338 return false; 339 } 340 341 @Override getDefaultLlcpMiu()342 public int getDefaultLlcpMiu() { 343 return DEFAULT_LLCP_MIU; 344 } 345 346 @Override getDefaultLlcpRwSize()347 public int getDefaultLlcpRwSize() { 348 return DEFAULT_LLCP_RWSIZE; 349 } 350 doDump()351 private native String doDump(); 352 @Override dump()353 public String dump() { 354 return doDump(); 355 } 356 357 /** 358 * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered) 359 */ notifyNdefMessageListeners(NativeNfcTag tag)360 private void notifyNdefMessageListeners(NativeNfcTag tag) { 361 mListener.onRemoteEndpointDiscovered(tag); 362 } 363 364 /** 365 * Notifies P2P Device detected, to activate LLCP link 366 */ notifyLlcpLinkActivation(NativeP2pDevice device)367 private void notifyLlcpLinkActivation(NativeP2pDevice device) { 368 mListener.onLlcpLinkActivated(device); 369 } 370 371 /** 372 * Notifies P2P Device detected, to activate LLCP link 373 */ notifyLlcpLinkDeactivated(NativeP2pDevice device)374 private void notifyLlcpLinkDeactivated(NativeP2pDevice device) { 375 mListener.onLlcpLinkDeactivated(device); 376 } 377 notifyRfFieldActivated()378 private void notifyRfFieldActivated() { 379 mListener.onRemoteFieldActivated(); 380 } 381 notifyRfFieldDeactivated()382 private void notifyRfFieldDeactivated() { 383 mListener.onRemoteFieldDeactivated(); 384 } 385 } 386