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