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 62 public NativeNfcManager(Context context, DeviceHostListener listener) { 63 mListener = listener; 64 initializeNativeStructure(); 65 mContext = context; 66 } 67 68 public native boolean initializeNativeStructure(); 69 70 private native boolean doDownload(); 71 72 public native int doGetLastError(); 73 74 @Override 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 118 private native boolean doInitialize(); 119 120 @Override 121 public boolean initialize() { 122 return doInitialize(); 123 } 124 125 private native boolean doDeinitialize(); 126 127 @Override 128 public boolean deinitialize() { 129 return doDeinitialize(); 130 } 131 132 @Override 133 public String getName() { 134 return DRIVER_NAME; 135 } 136 137 @Override 138 public boolean sendRawFrame(byte[] data) { 139 return false; 140 } 141 142 @Override 143 public boolean routeAid(byte[] aid, int route) { 144 return false; 145 } 146 147 @Override 148 public boolean unrouteAid(byte[] aid) { 149 return false; 150 } 151 152 @Override 153 public boolean commitRouting() { 154 return false; 155 } 156 157 @Override 158 public void registerT3tIdentifier(byte[] t3tIdentifier) { 159 return; 160 } 161 162 @Override 163 public void deregisterT3tIdentifier(byte[] t3tIdentifier) { 164 return; 165 } 166 167 @Override 168 public void clearT3tIdentifiersCache() { 169 return; 170 } 171 172 @Override 173 public int getLfT3tMax() { 174 return 0; 175 } 176 177 private native void doEnableDiscovery(int techMask, 178 boolean enableLowPowerPolling, 179 boolean enableReaderMode, 180 boolean enableP2p, 181 boolean restart); 182 @Override 183 public void enableDiscovery(NfcDiscoveryParameters params, boolean restart) { 184 doEnableDiscovery(params.getTechMask(), params.shouldEnableLowPowerDiscovery(), 185 params.shouldEnableReaderMode(), params.shouldEnableP2p(), restart); 186 } 187 188 @Override 189 public native void disableDiscovery(); 190 191 private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap, 192 String sn); 193 194 @Override 195 public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn) 196 throws LlcpException { 197 LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn); 198 if (socket != null) { 199 return socket; 200 } else { 201 /* Get Error Status */ 202 int error = doGetLastError(); 203 204 Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); 205 206 switch (error) { 207 case ErrorCodes.ERROR_BUFFER_TO_SMALL: 208 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: 209 throw new LlcpException(error); 210 default: 211 throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); 212 } 213 } 214 } 215 216 private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu, 217 int rw, int linearBufferLength); 218 @Override 219 public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu, 220 int rw, int linearBufferLength) throws LlcpException { 221 LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength); 222 if (socket != null) { 223 return socket; 224 } else { 225 /* Get Error Status */ 226 int error = doGetLastError(); 227 228 Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); 229 230 switch (error) { 231 case ErrorCodes.ERROR_BUFFER_TO_SMALL: 232 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: 233 throw new LlcpException(error); 234 default: 235 throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); 236 } 237 } 238 } 239 240 private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw, 241 int linearBufferLength); 242 @Override 243 public LlcpSocket createLlcpSocket(int sap, int miu, int rw, 244 int linearBufferLength) throws LlcpException { 245 LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength); 246 if (socket != null) { 247 return socket; 248 } else { 249 /* Get Error Status */ 250 int error = doGetLastError(); 251 252 Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error)); 253 254 switch (error) { 255 case ErrorCodes.ERROR_BUFFER_TO_SMALL: 256 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES: 257 throw new LlcpException(error); 258 default: 259 throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION); 260 } 261 } 262 } 263 264 @Override 265 public native boolean doCheckLlcp(); 266 267 @Override 268 public native boolean doActivateLlcp(); 269 270 private native void doResetTimeouts(); 271 272 @Override 273 public void resetTimeouts() { 274 doResetTimeouts(); 275 } 276 277 @Override 278 public native void doAbort(); 279 280 private native boolean doSetTimeout(int tech, int timeout); 281 @Override 282 public boolean setTimeout(int tech, int timeout) { 283 return doSetTimeout(tech, timeout); 284 } 285 286 private native int doGetTimeout(int tech); 287 @Override 288 public int getTimeout(int tech) { 289 return doGetTimeout(tech); 290 } 291 292 293 @Override 294 public boolean canMakeReadOnly(int ndefType) { 295 return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2 || 296 ndefType == Ndef.TYPE_MIFARE_CLASSIC); 297 } 298 299 @Override 300 public int getMaxTransceiveLength(int technology) { 301 switch (technology) { 302 case (TagTechnology.NFC_A): 303 case (TagTechnology.MIFARE_CLASSIC): 304 case (TagTechnology.MIFARE_ULTRALIGHT): 305 return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC 306 case (TagTechnology.NFC_B): 307 return 0; // PN544 does not support transceive of raw NfcB 308 case (TagTechnology.NFC_V): 309 return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC 310 case (TagTechnology.ISO_DEP): 311 /* The maximum length of a normal IsoDep frame consists of: 312 * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes 313 * such a frame is supported. Extended length frames however 314 * are not supported. 315 */ 316 return 261; // Will be automatically split in two frames on the RF layer 317 case (TagTechnology.NFC_F): 318 return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC 319 default: 320 return 0; 321 } 322 323 } 324 325 private native void doSetP2pInitiatorModes(int modes); 326 @Override 327 public void setP2pInitiatorModes(int modes) { 328 doSetP2pInitiatorModes(modes); 329 } 330 331 private native void doSetP2pTargetModes(int modes); 332 @Override 333 public void setP2pTargetModes(int modes) { 334 doSetP2pTargetModes(modes); 335 } 336 337 @Override 338 public boolean enableScreenOffSuspend() { 339 // Snooze mode not supported on NXP silicon 340 Log.i(TAG, "Snooze mode is not supported on NXP NFCC"); 341 return false; 342 } 343 344 @Override 345 public boolean disableScreenOffSuspend() { 346 // Snooze mode not supported on NXP silicon 347 Log.i(TAG, "Snooze mode is not supported on NXP NFCC"); 348 return true; 349 } 350 351 @Override 352 public boolean getExtendedLengthApdusSupported() { 353 // Not supported on the PN544 354 return false; 355 } 356 357 @Override 358 public int getDefaultLlcpMiu() { 359 return DEFAULT_LLCP_MIU; 360 } 361 362 @Override 363 public int getDefaultLlcpRwSize() { 364 return DEFAULT_LLCP_RWSIZE; 365 } 366 367 private native String doDump(); 368 @Override 369 public String dump() { 370 return doDump(); 371 } 372 373 /** 374 * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered) 375 */ 376 private void notifyNdefMessageListeners(NativeNfcTag tag) { 377 mListener.onRemoteEndpointDiscovered(tag); 378 } 379 380 /** 381 * Notifies P2P Device detected, to activate LLCP link 382 */ 383 private void notifyLlcpLinkActivation(NativeP2pDevice device) { 384 mListener.onLlcpLinkActivated(device); 385 } 386 387 /** 388 * Notifies P2P Device detected, to activate LLCP link 389 */ 390 private void notifyLlcpLinkDeactivated(NativeP2pDevice device) { 391 mListener.onLlcpLinkDeactivated(device); 392 } 393 394 private void notifyHostEmuActivated(int technology) { 395 mListener.onHostCardEmulationActivated(technology); 396 } 397 398 private void notifyHostEmuData(int technology, byte[] data) { 399 mListener.onHostCardEmulationData(technology, data); 400 } 401 402 private void notifyHostEmuDeactivated(int technology) { 403 mListener.onHostCardEmulationDeactivated(technology); 404 } 405 406 private void notifyRfFieldActivated() { 407 mListener.onRemoteFieldActivated(); 408 } 409 410 private void notifyRfFieldDeactivated() { 411 mListener.onRemoteFieldDeactivated(); 412 } 413 } 414