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 static com.android.nfc.NfcStatsLog.NFC_PROPRIETARY_CAPABILITIES_REPORTED__PASSIVE_OBSERVE_MODE__MODE_UNKNOWN; 20 import static com.android.nfc.NfcStatsLog.NFC_PROPRIETARY_CAPABILITIES_REPORTED__PASSIVE_OBSERVE_MODE__SUPPORT_WITHOUT_RF_DEACTIVATION; 21 import static com.android.nfc.NfcStatsLog.NFC_PROPRIETARY_CAPABILITIES_REPORTED__PASSIVE_OBSERVE_MODE__SUPPORT_WITH_RF_DEACTIVATION; 22 23 import android.content.Context; 24 import android.nfc.cardemulation.PollingFrame; 25 import android.nfc.tech.Ndef; 26 import android.nfc.tech.TagTechnology; 27 import android.os.Bundle; 28 import android.os.Trace; 29 import android.util.Log; 30 31 import com.android.nfc.DeviceHost; 32 import com.android.nfc.NfcDiscoveryParameters; 33 import com.android.nfc.NfcService; 34 import com.android.nfc.NfcStatsLog; 35 import com.android.nfc.NfcVendorNciResponse; 36 import com.android.nfc.NfcProprietaryCaps; 37 import java.io.FileDescriptor; 38 import java.nio.ByteBuffer; 39 import java.nio.ByteOrder; 40 import java.util.ArrayList; 41 import java.util.Arrays; 42 import java.util.HashMap; 43 import java.util.Iterator; 44 45 /** Native interface to the NFC Manager functions */ 46 public class NativeNfcManager implements DeviceHost { 47 private static final String TAG = "NativeNfcManager"; 48 static final String PREF = "NciDeviceHost"; 49 50 static final String DRIVER_NAME = "android-nci"; 51 52 /* Native structure */ 53 private long mNative; 54 55 private int mIsoDepMaxTransceiveLength; 56 private final DeviceHostListener mListener; 57 private final Context mContext; 58 59 private final Object mLock = new Object(); 60 private final HashMap<Integer, byte[]> mT3tIdentifiers = new HashMap<Integer, byte[]>(); 61 private NfcProprietaryCaps mProprietaryCaps = null; 62 private static final int MIN_POLLING_FRAME_TLV_SIZE = 5; 63 private static final int TAG_FIELD_CHANGE = 0; 64 private static final int TAG_NFC_A = 1; 65 private static final int TAG_NFC_B = 2; 66 private static final int TAG_NFC_F = 3; 67 private static final int TAG_NFC_UNKNOWN = 7; 68 private static final int NCI_HEADER_MIN_LEN = 3; 69 private static final int NCI_GID_INDEX = 0; 70 private static final int NCI_OID_INDEX = 1; 71 private static final int OP_CODE_INDEX = 3; 72 loadLibrary()73 private void loadLibrary() { 74 System.loadLibrary("nfc_nci_jni"); 75 } 76 NativeNfcManager(Context context, DeviceHostListener listener)77 public NativeNfcManager(Context context, DeviceHostListener listener) { 78 mListener = listener; 79 loadLibrary(); 80 initializeNativeStructure(); 81 mContext = context; 82 } 83 initializeNativeStructure()84 public native boolean initializeNativeStructure(); 85 doDownload()86 private native boolean doDownload(); 87 88 @Override checkFirmware()89 public boolean checkFirmware() { 90 return doDownload(); 91 } 92 doInitialize()93 private native boolean doInitialize(); 94 getIsoDepMaxTransceiveLength()95 private native int getIsoDepMaxTransceiveLength(); 96 97 @Override initialize()98 public boolean initialize() { 99 boolean ret = doInitialize(); 100 if (mContext.getResources().getBoolean( 101 com.android.nfc.R.bool.nfc_proprietary_getcaps_supported)) { 102 mProprietaryCaps = NfcProprietaryCaps.createFromByteArray(getProprietaryCaps()); 103 Log.i(TAG, "mProprietaryCaps: " + mProprietaryCaps); 104 logProprietaryCaps(mProprietaryCaps); 105 } 106 mIsoDepMaxTransceiveLength = getIsoDepMaxTransceiveLength(); 107 return ret; 108 } 109 doEnableDtaMode()110 private native void doEnableDtaMode(); 111 112 @Override enableDtaMode()113 public void enableDtaMode() { 114 doEnableDtaMode(); 115 } 116 doDisableDtaMode()117 private native void doDisableDtaMode(); 118 119 @Override disableDtaMode()120 public void disableDtaMode() { 121 Log.d(TAG, "disableDtaMode : entry"); 122 doDisableDtaMode(); 123 } 124 doFactoryReset()125 private native void doFactoryReset(); 126 127 @Override factoryReset()128 public void factoryReset() { 129 doFactoryReset(); 130 } 131 doSetPowerSavingMode(boolean flag)132 private native boolean doSetPowerSavingMode(boolean flag); 133 134 @Override setPowerSavingMode(boolean flag)135 public boolean setPowerSavingMode(boolean flag) { 136 return doSetPowerSavingMode(flag); 137 } 138 doShutdown()139 private native void doShutdown(); 140 141 @Override shutdown()142 public void shutdown() { 143 doShutdown(); 144 } 145 doDeinitialize()146 private native boolean doDeinitialize(); 147 148 @Override deinitialize()149 public boolean deinitialize() { 150 return doDeinitialize(); 151 } 152 153 @Override getName()154 public String getName() { 155 return DRIVER_NAME; 156 } 157 158 @Override sendRawFrame(byte[] data)159 public native boolean sendRawFrame(byte[] data); 160 161 @Override routeAid(byte[] aid, int route, int aidInfo, int power)162 public native boolean routeAid(byte[] aid, int route, int aidInfo, int power); 163 164 @Override unrouteAid(byte[] aid)165 public native boolean unrouteAid(byte[] aid); 166 167 @Override commitRouting()168 public native boolean commitRouting(); 169 doRegisterT3tIdentifier(byte[] t3tIdentifier)170 public native int doRegisterT3tIdentifier(byte[] t3tIdentifier); 171 172 @Override isObserveModeSupported()173 public boolean isObserveModeSupported() { 174 if (!android.nfc.Flags.nfcObserveMode()) { 175 return false; 176 } 177 // Check if the device overlay and HAL capabilities indicate that observe 178 // mode is supported. 179 if (!mContext.getResources().getBoolean( 180 com.android.nfc.R.bool.nfc_observe_mode_supported)) { 181 return false; 182 } 183 if (mContext.getResources().getBoolean( 184 com.android.nfc.R.bool.nfc_proprietary_getcaps_supported)) { 185 return isObserveModeSupportedCaps(mProprietaryCaps); 186 } 187 return true; 188 } 189 190 @Override setObserveMode(boolean enabled)191 public native boolean setObserveMode(boolean enabled); 192 193 @Override isObserveModeEnabled()194 public native boolean isObserveModeEnabled(); 195 196 @Override registerT3tIdentifier(byte[] t3tIdentifier)197 public void registerT3tIdentifier(byte[] t3tIdentifier) { 198 synchronized (mLock) { 199 int handle = doRegisterT3tIdentifier(t3tIdentifier); 200 if (handle != 0xffff) { 201 mT3tIdentifiers.put(Integer.valueOf(handle), t3tIdentifier); 202 } 203 } 204 } 205 doDeregisterT3tIdentifier(int handle)206 public native void doDeregisterT3tIdentifier(int handle); 207 208 @Override deregisterT3tIdentifier(byte[] t3tIdentifier)209 public void deregisterT3tIdentifier(byte[] t3tIdentifier) { 210 synchronized (mLock) { 211 Iterator<Integer> it = mT3tIdentifiers.keySet().iterator(); 212 while (it.hasNext()) { 213 int handle = it.next().intValue(); 214 byte[] value = mT3tIdentifiers.get(handle); 215 if (Arrays.equals(value, t3tIdentifier)) { 216 doDeregisterT3tIdentifier(handle); 217 mT3tIdentifiers.remove(handle); 218 break; 219 } 220 } 221 } 222 } 223 224 @Override clearT3tIdentifiersCache()225 public void clearT3tIdentifiersCache() { 226 synchronized (mLock) { 227 mT3tIdentifiers.clear(); 228 } 229 } 230 231 @Override getLfT3tMax()232 public native int getLfT3tMax(); 233 234 @Override doSetScreenState(int screen_state_mask, boolean alwaysPoll)235 public native void doSetScreenState(int screen_state_mask, boolean alwaysPoll); 236 237 @Override getNciVersion()238 public native int getNciVersion(); 239 doEnableDiscovery( int techMask, boolean enableLowPowerPolling, boolean enableReaderMode, boolean enableHostRouting, boolean restart)240 private native void doEnableDiscovery( 241 int techMask, 242 boolean enableLowPowerPolling, 243 boolean enableReaderMode, 244 boolean enableHostRouting, 245 boolean restart); 246 247 @Override enableDiscovery(NfcDiscoveryParameters params, boolean restart)248 public void enableDiscovery(NfcDiscoveryParameters params, boolean restart) { 249 doEnableDiscovery( 250 params.getTechMask(), 251 params.shouldEnableLowPowerDiscovery(), 252 params.shouldEnableReaderMode(), 253 params.shouldEnableHostRouting(), 254 restart); 255 } 256 257 @Override disableDiscovery()258 public native void disableDiscovery(); 259 doResetTimeouts()260 private native void doResetTimeouts(); 261 262 @Override resetTimeouts()263 public void resetTimeouts() { 264 doResetTimeouts(); 265 } 266 267 @Override doAbort(String msg)268 public native void doAbort(String msg); 269 doSetTimeout(int tech, int timeout)270 private native boolean doSetTimeout(int tech, int timeout); 271 272 @Override setTimeout(int tech, int timeout)273 public boolean setTimeout(int tech, int timeout) { 274 return doSetTimeout(tech, timeout); 275 } 276 doGetTimeout(int tech)277 private native int doGetTimeout(int tech); 278 279 @Override getTimeout(int tech)280 public int getTimeout(int tech) { 281 return doGetTimeout(tech); 282 } 283 284 @Override canMakeReadOnly(int ndefType)285 public boolean canMakeReadOnly(int ndefType) { 286 return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2); 287 } 288 289 @Override getMaxTransceiveLength(int technology)290 public int getMaxTransceiveLength(int technology) { 291 switch (technology) { 292 case (TagTechnology.NFC_A): 293 case (TagTechnology.MIFARE_CLASSIC): 294 case (TagTechnology.MIFARE_ULTRALIGHT): 295 return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC 296 case (TagTechnology.NFC_B): 297 ///////////////////////////////////////////////////////////////// 298 // Broadcom: Since BCM2079x supports this, set NfcB max size. 299 // return 0; // PN544 does not support transceive of raw NfcB 300 return 253; // PN544 does not support transceive of raw NfcB 301 case (TagTechnology.NFC_V): 302 return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC 303 case (TagTechnology.ISO_DEP): 304 return mIsoDepMaxTransceiveLength; 305 case (TagTechnology.NFC_F): 306 return 255; 307 default: 308 return 0; 309 } 310 } 311 getAidTableSize()312 public native int getAidTableSize(); 313 314 @Override getExtendedLengthApdusSupported()315 public boolean getExtendedLengthApdusSupported() { 316 /* 261 is the default size if extended length frames aren't supported */ 317 if (getMaxTransceiveLength(TagTechnology.ISO_DEP) > 261) return true; 318 return false; 319 } 320 doDump(FileDescriptor fd)321 private native void doDump(FileDescriptor fd); 322 323 @Override dump(FileDescriptor fd)324 public void dump(FileDescriptor fd) { 325 doDump(fd); 326 } 327 doSetNfcSecure(boolean enable)328 private native boolean doSetNfcSecure(boolean enable); 329 330 @Override setNfcSecure(boolean enable)331 public boolean setNfcSecure(boolean enable) { 332 return doSetNfcSecure(enable); 333 } 334 doStartStopPolling(boolean start)335 private native void doStartStopPolling(boolean start); 336 337 @Override startStopPolling(boolean start)338 public void startStopPolling(boolean start) { 339 doStartStopPolling(start); 340 } 341 doSetNfceePowerAndLinkCtrl(boolean enable)342 private native void doSetNfceePowerAndLinkCtrl(boolean enable); 343 344 @Override setNfceePowerAndLinkCtrl(boolean enable)345 public void setNfceePowerAndLinkCtrl(boolean enable) { 346 doSetNfceePowerAndLinkCtrl(enable); 347 } 348 349 @Override getRoutingTable()350 public native byte[] getRoutingTable(); 351 352 @Override getMaxRoutingTableSize()353 public native int getMaxRoutingTableSize(); 354 isMultiTag()355 public native boolean isMultiTag(); 356 nativeSendRawVendorCmd( int mt, int gid, int oid, byte[] payload)357 private native NfcVendorNciResponse nativeSendRawVendorCmd( 358 int mt, int gid, int oid, byte[] payload); 359 360 @Override sendRawVendorCmd(int mt, int gid, int oid, byte[] payload)361 public NfcVendorNciResponse sendRawVendorCmd(int mt, int gid, int oid, byte[] payload) { 362 NfcVendorNciResponse res= nativeSendRawVendorCmd(mt, gid, oid, payload); 363 return res; 364 } 365 366 /** Notifies Ndef Message (TODO: rename into notifyTargetDiscovered) */ notifyNdefMessageListeners(NativeNfcTag tag)367 private void notifyNdefMessageListeners(NativeNfcTag tag) { 368 mListener.onRemoteEndpointDiscovered(tag); 369 } 370 notifyHostEmuActivated(int technology)371 private void notifyHostEmuActivated(int technology) { 372 mListener.onHostCardEmulationActivated(technology); 373 } 374 notifyHostEmuData(int technology, byte[] data)375 private void notifyHostEmuData(int technology, byte[] data) { 376 mListener.onHostCardEmulationData(technology, data); 377 } 378 notifyHostEmuDeactivated(int technology)379 private void notifyHostEmuDeactivated(int technology) { 380 mListener.onHostCardEmulationDeactivated(technology); 381 } 382 notifyRfFieldActivated()383 private void notifyRfFieldActivated() { 384 mListener.onRemoteFieldActivated(); 385 } 386 notifyRfFieldDeactivated()387 private void notifyRfFieldDeactivated() { 388 mListener.onRemoteFieldDeactivated(); 389 } 390 notifyTransactionListeners(byte[] aid, byte[] data, String evtSrc)391 private void notifyTransactionListeners(byte[] aid, byte[] data, String evtSrc) { 392 mListener.onNfcTransactionEvent(aid, data, evtSrc); 393 } 394 notifyEeUpdated()395 private void notifyEeUpdated() { 396 mListener.onEeUpdated(); 397 } 398 notifyHwErrorReported()399 private void notifyHwErrorReported() { 400 mListener.onHwErrorReported(); 401 } 402 notifyPollingLoopFrame(int data_len, byte[] p_data)403 public void notifyPollingLoopFrame(int data_len, byte[] p_data) { 404 if (data_len < MIN_POLLING_FRAME_TLV_SIZE) { 405 return; 406 } 407 Trace.beginSection("notifyPollingLoopFrame"); 408 final int header_len = 4; 409 int pos = header_len; 410 final int TLV_header_len = 3; 411 final int TLV_type_offset = 0; 412 final int TLV_len_offset = 2; 413 final int TLV_timestamp_offset = 3; 414 final int TLV_gain_offset = 7; 415 final int TLV_data_offset = 8; 416 ArrayList<PollingFrame> frames = new ArrayList<PollingFrame>(); 417 while (pos + TLV_len_offset < data_len) { 418 @PollingFrame.PollingFrameType int frameType; 419 Bundle frame = new Bundle(); 420 int type = p_data[pos + TLV_type_offset]; 421 int length = p_data[pos + TLV_len_offset]; 422 if (TLV_len_offset + length < TLV_gain_offset ) { 423 Log.e(TAG, "Length (" + length + ") is less than a polling frame, dropping."); 424 break; 425 } 426 if (pos + TLV_header_len + length > data_len) { 427 // Frame is bigger than buffer. 428 Log.e(TAG, "Polling frame data ("+ pos + ", " + length 429 + ") is longer than buffer data length (" + data_len + ")."); 430 break; 431 } 432 switch (type) { 433 case TAG_FIELD_CHANGE: 434 frameType = p_data[pos + TLV_data_offset] != 0x00 435 ? PollingFrame.POLLING_LOOP_TYPE_ON 436 : PollingFrame.POLLING_LOOP_TYPE_OFF; 437 break; 438 case TAG_NFC_A: 439 frameType = PollingFrame.POLLING_LOOP_TYPE_A; 440 break; 441 case TAG_NFC_B: 442 frameType = PollingFrame.POLLING_LOOP_TYPE_B; 443 break; 444 case TAG_NFC_F: 445 frameType = PollingFrame.POLLING_LOOP_TYPE_F; 446 break; 447 case TAG_NFC_UNKNOWN: 448 frameType = PollingFrame.POLLING_LOOP_TYPE_UNKNOWN; 449 break; 450 default: 451 Log.e(TAG, "Unknown polling loop tag type."); 452 return; 453 } 454 byte[] frameData = null; 455 if (pos + TLV_header_len + length <= data_len) { 456 frameData = Arrays.copyOfRange(p_data, pos + TLV_data_offset, 457 pos + TLV_header_len + length); 458 } 459 int gain = -1; 460 if (pos + TLV_gain_offset <= data_len) { 461 gain = Byte.toUnsignedInt(p_data[pos + TLV_gain_offset]); 462 if (gain == 0XFF) { 463 gain = -1; 464 } 465 } 466 long timestamp = 0; 467 if (pos + TLV_timestamp_offset + 3 < data_len) { 468 timestamp = Integer.toUnsignedLong(ByteBuffer.wrap(p_data, 469 pos + TLV_timestamp_offset, 4).order(ByteOrder.BIG_ENDIAN).getInt()); 470 } 471 pos += (TLV_header_len + length); 472 frames.add(new PollingFrame(frameType, frameData, gain, timestamp, false)); 473 } 474 mListener.onPollingLoopDetected(frames); 475 Trace.endSection(); 476 } 477 notifyWlcStopped(int wpt_end_condition)478 private void notifyWlcStopped(int wpt_end_condition) { 479 mListener.onWlcStopped(wpt_end_condition); 480 } notifyVendorSpecificEvent(int event, int dataLen, byte[] pData)481 private void notifyVendorSpecificEvent(int event, int dataLen, byte[] pData) { 482 if (pData.length < NCI_HEADER_MIN_LEN || dataLen != pData.length) { 483 Log.e(TAG, "Invalid data"); 484 return; 485 } 486 if (android.nfc.Flags.nfcVendorCmd()) { 487 mListener.onVendorSpecificEvent(pData[NCI_GID_INDEX], pData[NCI_OID_INDEX], 488 Arrays.copyOfRange(pData, OP_CODE_INDEX, pData.length)); 489 } 490 } 491 492 @Override setDiscoveryTech(int pollTech, int listenTech)493 public native void setDiscoveryTech(int pollTech, int listenTech); 494 495 @Override resetDiscoveryTech()496 public native void resetDiscoveryTech(); 497 498 @Override clearRoutingEntry(int clearFlags)499 public native void clearRoutingEntry(int clearFlags); 500 501 @Override setIsoDepProtocolRoute(int route)502 public native void setIsoDepProtocolRoute(int route); 503 504 @Override setTechnologyABRoute(int route)505 public native void setTechnologyABRoute(int route); 506 getProprietaryCaps()507 private native byte[] getProprietaryCaps(); 508 509 @Override enableVendorNciNotifications(boolean enabled)510 public native void enableVendorNciNotifications(boolean enabled); 511 notifyCommandTimeout()512 private void notifyCommandTimeout() { 513 NfcService.getInstance().storeNativeCrashLogs(); 514 } 515 516 /** wrappers for values */ 517 private static final int CAPS_OBSERVE_MODE_UNKNOWN = 518 NFC_PROPRIETARY_CAPABILITIES_REPORTED__PASSIVE_OBSERVE_MODE__MODE_UNKNOWN; 519 private static final int CAPS_OBSERVE_MODE_SUPPORT_WITH_RF_DEACTIVATION = 520 NFC_PROPRIETARY_CAPABILITIES_REPORTED__PASSIVE_OBSERVE_MODE__SUPPORT_WITH_RF_DEACTIVATION; 521 private static final int CAPS_OBSERVE_MODE_SUPPORT_WITHOUT_RF_DEACTIVATION = 522 NFC_PROPRIETARY_CAPABILITIES_REPORTED__PASSIVE_OBSERVE_MODE__SUPPORT_WITHOUT_RF_DEACTIVATION; 523 private static final int CAPS_OBSERVE_MODE_NOT_SUPPORTED = 524 NfcStatsLog.NFC_PROPRIETARY_CAPABILITIES_REPORTED__PASSIVE_OBSERVE_MODE__NOT_SUPPORTED; 525 isObserveModeSupportedCaps(NfcProprietaryCaps proprietaryCaps)526 private static boolean isObserveModeSupportedCaps(NfcProprietaryCaps proprietaryCaps) { 527 return proprietaryCaps.getPassiveObserveMode() 528 != NfcProprietaryCaps.PassiveObserveMode.NOT_SUPPORTED; 529 } 530 logProprietaryCaps(NfcProprietaryCaps proprietaryCaps)531 private static void logProprietaryCaps(NfcProprietaryCaps proprietaryCaps) { 532 int observeModeStatsd = CAPS_OBSERVE_MODE_UNKNOWN; 533 534 NfcProprietaryCaps.PassiveObserveMode mode = proprietaryCaps.getPassiveObserveMode(); 535 536 if (mode == NfcProprietaryCaps.PassiveObserveMode.SUPPORT_WITH_RF_DEACTIVATION) { 537 observeModeStatsd = CAPS_OBSERVE_MODE_SUPPORT_WITH_RF_DEACTIVATION; 538 } else if (mode == NfcProprietaryCaps.PassiveObserveMode.SUPPORT_WITHOUT_RF_DEACTIVATION) { 539 observeModeStatsd = CAPS_OBSERVE_MODE_SUPPORT_WITHOUT_RF_DEACTIVATION; 540 } else if (mode == NfcProprietaryCaps.PassiveObserveMode.NOT_SUPPORTED) { 541 observeModeStatsd = CAPS_OBSERVE_MODE_NOT_SUPPORTED; 542 } 543 544 NfcStatsLog.write(NfcStatsLog.NFC_PROPRIETARY_CAPABILITIES_REPORTED, 545 observeModeStatsd, 546 proprietaryCaps.isPollingFrameNotificationSupported(), 547 proprietaryCaps.isPowerSavingModeSupported(), 548 proprietaryCaps.isAutotransactPollingLoopFilterSupported()); 549 } 550 } 551