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 android.content.Context;
20 import android.nfc.ErrorCodes;
21 import android.nfc.tech.Ndef;
22 import android.nfc.tech.TagTechnology;
23 import android.util.Log;
24 
25 import com.android.nfc.DeviceHost;
26 import com.android.nfc.LlcpException;
27 import com.android.nfc.NfcDiscoveryParameters;
28 
29 import java.io.FileDescriptor;
30 import java.util.Arrays;
31 import java.util.Iterator;
32 import java.util.HashMap;
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     static final String PREF = "NciDeviceHost";
40 
41     static final int DEFAULT_LLCP_MIU = 1980;
42     static final int DEFAULT_LLCP_RWSIZE = 2;
43 
44     static final String DRIVER_NAME = "android-nci";
45 
46     static {
47         System.loadLibrary("nfc_nci_jni");
48     }
49 
50     /* Native structure */
51     private long mNative;
52 
53     private int mIsoDepMaxTransceiveLength;
54     private final DeviceHostListener mListener;
55     private final Context mContext;
56 
57     private final Object mLock = new Object();
58     private final HashMap<Integer, byte[]> mT3tIdentifiers = new HashMap<Integer, byte[]>();
59 
NativeNfcManager(Context context, DeviceHostListener listener)60     public NativeNfcManager(Context context, DeviceHostListener listener) {
61         mListener = listener;
62         initializeNativeStructure();
63         mContext = context;
64     }
65 
initializeNativeStructure()66     public native boolean initializeNativeStructure();
67 
doDownload()68     private native boolean doDownload();
69 
doGetLastError()70     public native int doGetLastError();
71 
72     @Override
checkFirmware()73     public boolean checkFirmware() {
74         return doDownload();
75     }
76 
doInitialize()77     private native boolean doInitialize();
78 
getIsoDepMaxTransceiveLength()79     private native int getIsoDepMaxTransceiveLength();
80 
81     @Override
initialize()82     public boolean initialize() {
83         boolean ret = doInitialize();
84         mIsoDepMaxTransceiveLength = getIsoDepMaxTransceiveLength();
85         return ret;
86     }
87 
doEnableDtaMode()88     private native void doEnableDtaMode();
89 
90     @Override
enableDtaMode()91     public void enableDtaMode() {
92         doEnableDtaMode();
93     }
94 
doDisableDtaMode()95     private native void doDisableDtaMode();
96 
97     @Override
disableDtaMode()98     public void disableDtaMode() {
99         Log.d(TAG,"disableDtaMode : entry");
100         doDisableDtaMode();
101     }
102 
doFactoryReset()103     private native void doFactoryReset();
104 
105     @Override
factoryReset()106     public void factoryReset() {
107         doFactoryReset();
108     }
109 
doShutdown()110     private native void doShutdown();
111 
112     @Override
shutdown()113     public void shutdown() {
114         doShutdown();
115     }
116 
doDeinitialize()117     private native boolean doDeinitialize();
118 
119     @Override
deinitialize()120     public boolean deinitialize() {
121         return doDeinitialize();
122     }
123 
124     @Override
getName()125     public String getName() {
126         return DRIVER_NAME;
127     }
128 
129     @Override
sendRawFrame(byte[] data)130     public native boolean sendRawFrame(byte[] data);
131 
132     @Override
routeAid(byte[] aid, int route, int aidInfo)133     public native boolean routeAid(byte[] aid, int route, int aidInfo);
134 
135     @Override
unrouteAid(byte[] aid)136     public native boolean unrouteAid(byte[] aid);
137 
138     @Override
commitRouting()139     public native boolean commitRouting();
140 
doRegisterT3tIdentifier(byte[] t3tIdentifier)141     public native int doRegisterT3tIdentifier(byte[] t3tIdentifier);
142 
143     @Override
registerT3tIdentifier(byte[] t3tIdentifier)144     public void registerT3tIdentifier(byte[] t3tIdentifier) {
145         synchronized (mLock) {
146             int handle = doRegisterT3tIdentifier(t3tIdentifier);
147             if (handle != 0xffff) {
148                 mT3tIdentifiers.put(Integer.valueOf(handle), t3tIdentifier);
149             }
150         }
151     }
152 
doDeregisterT3tIdentifier(int handle)153     public native void doDeregisterT3tIdentifier(int handle);
154 
155     @Override
deregisterT3tIdentifier(byte[] t3tIdentifier)156     public void deregisterT3tIdentifier(byte[] t3tIdentifier) {
157         synchronized (mLock) {
158             Iterator<Integer> it = mT3tIdentifiers.keySet().iterator();
159             while (it.hasNext()) {
160                 int handle = it.next().intValue();
161                 byte[] value = mT3tIdentifiers.get(handle);
162                 if (Arrays.equals(value, t3tIdentifier)) {
163                     doDeregisterT3tIdentifier(handle);
164                     mT3tIdentifiers.remove(handle);
165                     break;
166                 }
167             }
168         }
169     }
170 
171     @Override
clearT3tIdentifiersCache()172     public void clearT3tIdentifiersCache() {
173         synchronized (mLock) {
174             mT3tIdentifiers.clear();
175         }
176     }
177 
178     @Override
getLfT3tMax()179     public native int getLfT3tMax();
180 
181     @Override
doSetScreenState(int screen_state_mask)182     public native void doSetScreenState(int screen_state_mask);
183 
184     @Override
getNciVersion()185     public native int getNciVersion();
186 
doEnableDiscovery(int techMask, boolean enableLowPowerPolling, boolean enableReaderMode, boolean enableHostRouting, boolean enableP2p, boolean restart)187     private native void doEnableDiscovery(int techMask,
188                                           boolean enableLowPowerPolling,
189                                           boolean enableReaderMode,
190                                           boolean enableHostRouting,
191                                           boolean enableP2p,
192                                           boolean restart);
193     @Override
enableDiscovery(NfcDiscoveryParameters params, boolean restart)194     public void enableDiscovery(NfcDiscoveryParameters params, boolean restart) {
195         doEnableDiscovery(params.getTechMask(), params.shouldEnableLowPowerDiscovery(),
196                 params.shouldEnableReaderMode(), params.shouldEnableHostRouting(),
197                 params.shouldEnableP2p(), restart);
198     }
199 
200     @Override
disableDiscovery()201     public native void disableDiscovery();
202 
doCreateLlcpConnectionlessSocket(int nSap, String sn)203     private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap,
204             String sn);
205 
206     @Override
createLlcpConnectionlessSocket(int nSap, String sn)207     public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn)
208             throws LlcpException {
209         LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn);
210         if (socket != null) {
211             return socket;
212         } else {
213             /* Get Error Status */
214             int error = doGetLastError();
215 
216             Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
217 
218             switch (error) {
219                 case ErrorCodes.ERROR_BUFFER_TO_SMALL:
220                 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
221                     throw new LlcpException(error);
222                 default:
223                     throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
224             }
225         }
226     }
227 
doCreateLlcpServiceSocket(int nSap, String sn, int miu, int rw, int linearBufferLength)228     private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu,
229             int rw, int linearBufferLength);
230     @Override
createLlcpServerSocket(int nSap, String sn, int miu, int rw, int linearBufferLength)231     public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu,
232             int rw, int linearBufferLength) throws LlcpException {
233         LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength);
234         if (socket != null) {
235             return socket;
236         } else {
237             /* Get Error Status */
238             int error = doGetLastError();
239 
240             Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
241 
242             switch (error) {
243                 case ErrorCodes.ERROR_BUFFER_TO_SMALL:
244                 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
245                     throw new LlcpException(error);
246                 default:
247                     throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
248             }
249         }
250     }
251 
doCreateLlcpSocket(int sap, int miu, int rw, int linearBufferLength)252     private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw,
253             int linearBufferLength);
254     @Override
createLlcpSocket(int sap, int miu, int rw, int linearBufferLength)255     public LlcpSocket createLlcpSocket(int sap, int miu, int rw,
256             int linearBufferLength) throws LlcpException {
257         LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength);
258         if (socket != null) {
259             return socket;
260         } else {
261             /* Get Error Status */
262             int error = doGetLastError();
263 
264             Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
265 
266             switch (error) {
267                 case ErrorCodes.ERROR_BUFFER_TO_SMALL:
268                 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
269                     throw new LlcpException(error);
270                 default:
271                     throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
272             }
273         }
274     }
275 
276     @Override
doCheckLlcp()277     public native boolean doCheckLlcp();
278 
279     @Override
doActivateLlcp()280     public native boolean doActivateLlcp();
281 
doResetTimeouts()282     private native void doResetTimeouts();
283 
284     @Override
resetTimeouts()285     public void resetTimeouts() {
286         doResetTimeouts();
287     }
288 
289     @Override
doAbort(String msg)290     public native void doAbort(String msg);
291 
doSetTimeout(int tech, int timeout)292     private native boolean doSetTimeout(int tech, int timeout);
293     @Override
setTimeout(int tech, int timeout)294     public boolean setTimeout(int tech, int timeout) {
295         return doSetTimeout(tech, timeout);
296     }
297 
doGetTimeout(int tech)298     private native int doGetTimeout(int tech);
299     @Override
getTimeout(int tech)300     public int getTimeout(int tech) {
301         return doGetTimeout(tech);
302     }
303 
304 
305     @Override
canMakeReadOnly(int ndefType)306     public boolean canMakeReadOnly(int ndefType) {
307         return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2);
308     }
309 
310     @Override
getMaxTransceiveLength(int technology)311     public int getMaxTransceiveLength(int technology) {
312         switch (technology) {
313             case (TagTechnology.NFC_A):
314             case (TagTechnology.MIFARE_CLASSIC):
315             case (TagTechnology.MIFARE_ULTRALIGHT):
316                 return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
317             case (TagTechnology.NFC_B):
318                 /////////////////////////////////////////////////////////////////
319                 // Broadcom: Since BCM2079x supports this, set NfcB max size.
320                 //return 0; // PN544 does not support transceive of raw NfcB
321                 return 253; // PN544 does not support transceive of raw NfcB
322             case (TagTechnology.NFC_V):
323                 return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
324             case (TagTechnology.ISO_DEP):
325                 return mIsoDepMaxTransceiveLength;
326             case (TagTechnology.NFC_F):
327                 return 255;
328             default:
329                 return 0;
330         }
331 
332     }
333 
getAidTableSize()334     public native int getAidTableSize();
335 
doSetP2pInitiatorModes(int modes)336     private native void doSetP2pInitiatorModes(int modes);
337     @Override
setP2pInitiatorModes(int modes)338     public void setP2pInitiatorModes(int modes) {
339         doSetP2pInitiatorModes(modes);
340     }
341 
doSetP2pTargetModes(int modes)342     private native void doSetP2pTargetModes(int modes);
343     @Override
setP2pTargetModes(int modes)344     public void setP2pTargetModes(int modes) {
345         doSetP2pTargetModes(modes);
346     }
347 
348     @Override
getExtendedLengthApdusSupported()349     public boolean getExtendedLengthApdusSupported() {
350         /* 261 is the default size if extended length frames aren't supported */
351         if (getMaxTransceiveLength(TagTechnology.ISO_DEP) > 261)
352             return true;
353         return false;
354     }
355 
356     @Override
getDefaultLlcpMiu()357     public int getDefaultLlcpMiu() {
358         return DEFAULT_LLCP_MIU;
359     }
360 
361     @Override
getDefaultLlcpRwSize()362     public int getDefaultLlcpRwSize() {
363         return DEFAULT_LLCP_RWSIZE;
364     }
365 
doDump(FileDescriptor fd)366     private native void doDump(FileDescriptor fd);
367     @Override
dump(FileDescriptor fd)368     public void dump(FileDescriptor fd) {
369         doDump(fd);
370     }
371 
doEnableScreenOffSuspend()372     private native void doEnableScreenOffSuspend();
373     @Override
enableScreenOffSuspend()374     public boolean enableScreenOffSuspend() {
375         doEnableScreenOffSuspend();
376         return true;
377     }
378 
doDisableScreenOffSuspend()379     private native void doDisableScreenOffSuspend();
380     @Override
disableScreenOffSuspend()381     public boolean disableScreenOffSuspend() {
382         doDisableScreenOffSuspend();
383         return true;
384     }
385 
doSetNfcSecure(boolean enable)386     private native boolean doSetNfcSecure(boolean enable);
387     @Override
setNfcSecure(boolean enable)388     public boolean setNfcSecure(boolean enable) {
389         return doSetNfcSecure(enable);
390     }
391 
392     /**
393      * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered)
394      */
notifyNdefMessageListeners(NativeNfcTag tag)395     private void notifyNdefMessageListeners(NativeNfcTag tag) {
396         mListener.onRemoteEndpointDiscovered(tag);
397     }
398 
399     /**
400      * Notifies P2P Device detected, to activate LLCP link
401      */
notifyLlcpLinkActivation(NativeP2pDevice device)402     private void notifyLlcpLinkActivation(NativeP2pDevice device) {
403         mListener.onLlcpLinkActivated(device);
404     }
405 
406     /**
407      * Notifies P2P Device detected, to activate LLCP link
408      */
notifyLlcpLinkDeactivated(NativeP2pDevice device)409     private void notifyLlcpLinkDeactivated(NativeP2pDevice device) {
410         mListener.onLlcpLinkDeactivated(device);
411     }
412 
413     /**
414      * Notifies first packet received from remote LLCP
415      */
notifyLlcpLinkFirstPacketReceived(NativeP2pDevice device)416     private void notifyLlcpLinkFirstPacketReceived(NativeP2pDevice device) {
417         mListener.onLlcpFirstPacketReceived(device);
418     }
419 
notifyHostEmuActivated(int technology)420     private void notifyHostEmuActivated(int technology) {
421         mListener.onHostCardEmulationActivated(technology);
422     }
423 
notifyHostEmuData(int technology, byte[] data)424     private void notifyHostEmuData(int technology, byte[] data) {
425         mListener.onHostCardEmulationData(technology, data);
426     }
427 
notifyHostEmuDeactivated(int technology)428     private void notifyHostEmuDeactivated(int technology) {
429         mListener.onHostCardEmulationDeactivated(technology);
430     }
431 
notifyRfFieldActivated()432     private void notifyRfFieldActivated() {
433         mListener.onRemoteFieldActivated();
434     }
435 
notifyRfFieldDeactivated()436     private void notifyRfFieldDeactivated() {
437         mListener.onRemoteFieldDeactivated();
438     }
439 
notifyTransactionListeners(byte[] aid, byte[] data, String evtSrc)440     private void notifyTransactionListeners(byte[] aid, byte[] data, String evtSrc) {
441         mListener.onNfcTransactionEvent(aid, data, evtSrc);
442     }
443 
notifyEeUpdated()444     private void notifyEeUpdated() {
445         mListener.onEeUpdated();
446     }
447 }
448