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