• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
31 import java.io.File;
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 
39     private static final String NFC_CONTROLLER_FIRMWARE_FILE_NAME = "/vendor/firmware/libpn544_fw.so";
40 
41     static final String PREF = "NxpDeviceHost";
42 
43     private static final String PREF_FIRMWARE_MODTIME = "firmware_modtime";
44     private static final long FIRMWARE_MODTIME_DEFAULT = -1;
45 
46     static final String DRIVER_NAME = "nxp";
47 
48     static final int DEFAULT_LLCP_MIU = 128;
49     static final int DEFAULT_LLCP_RWSIZE = 1;
50 
51     //TODO: dont hardcode this
52     private static final byte[][] EE_WIPE_APDUS = {
53         {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
54         {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00,
55                 (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x20, (byte)0x10, (byte)0x00},
56         {(byte)0x80, (byte)0xe2, (byte)0x01, (byte)0x03, (byte)0x00},
57         {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
58         {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00,
59                 (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x30, (byte)0x30, (byte)0x00},
60         {(byte)0x80, (byte)0xb4, (byte)0x00, (byte)0x00, (byte)0x00},
61         {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
62     };
63 
64 
65     static {
66         System.loadLibrary("nfc_jni");
67     }
68 
69     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
70     public static final String INTERNAL_TARGET_DESELECTED_ACTION = "com.android.nfc.action.INTERNAL_TARGET_DESELECTED";
71 
72     /* Native structure */
73     private int mNative;
74 
75     private final DeviceHostListener mListener;
76     private final Context mContext;
77 
NativeNfcManager(Context context, DeviceHostListener listener)78     public NativeNfcManager(Context context, DeviceHostListener listener) {
79         mListener = listener;
80         initializeNativeStructure();
81         mContext = context;
82     }
83 
initializeNativeStructure()84     public native boolean initializeNativeStructure();
85 
doDownload()86     private native boolean doDownload();
87 
doGetLastError()88     public native int doGetLastError();
89 
90     @Override
checkFirmware()91     public void checkFirmware() {
92         // Check that the NFC controller firmware is up to date.  This
93         // ensures that firmware updates are applied in a timely fashion,
94         // and makes it much less likely that the user will have to wait
95         // for a firmware download when they enable NFC in the settings
96         // app.  Firmware download can take some time, so this should be
97         // run in a separate thread.
98 
99         // check the timestamp of the firmware file
100         File firmwareFile;
101         int nbRetry = 0;
102         try {
103             firmwareFile = new File(NFC_CONTROLLER_FIRMWARE_FILE_NAME);
104         } catch(NullPointerException npe) {
105             Log.e(TAG,"path to firmware file was null");
106             return;
107         }
108 
109         long modtime = firmwareFile.lastModified();
110 
111         SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
112         long prev_fw_modtime = prefs.getLong(PREF_FIRMWARE_MODTIME, FIRMWARE_MODTIME_DEFAULT);
113         Log.d(TAG,"prev modtime: " + prev_fw_modtime);
114         Log.d(TAG,"new modtime: " + modtime);
115         if (prev_fw_modtime == modtime) {
116             return;
117         }
118 
119         // FW download.
120         while(nbRetry < 5) {
121             Log.d(TAG,"Perform Download");
122             if(doDownload()) {
123                 Log.d(TAG,"Download Success");
124                 // Now that we've finished updating the firmware, save the new modtime.
125                 prefs.edit().putLong(PREF_FIRMWARE_MODTIME, modtime).apply();
126                 break;
127             } else {
128                 Log.d(TAG,"Download Failed");
129                 nbRetry++;
130             }
131         }
132     }
133 
doInitialize()134     private native boolean doInitialize();
135 
136     @Override
initialize()137     public boolean initialize() {
138         SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
139         SharedPreferences.Editor editor = prefs.edit();
140 
141         if (prefs.getBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false)) {
142             try {
143                 Thread.sleep (12000);
144                 editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false);
145                 editor.apply();
146             } catch (InterruptedException e) { }
147         }
148 
149         return doInitialize();
150     }
151 
doDeinitialize()152     private native boolean doDeinitialize();
153 
154     @Override
deinitialize()155     public boolean deinitialize() {
156         SharedPreferences prefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
157         SharedPreferences.Editor editor = prefs.edit();
158 
159         editor.putBoolean(NativeNfcSecureElement.PREF_SE_WIRED, false);
160         editor.apply();
161 
162         return doDeinitialize();
163     }
164 
165     @Override
getName()166     public String getName() {
167         return DRIVER_NAME;
168     }
169 
170     @Override
enableDiscovery()171     public native void enableDiscovery();
172 
173     @Override
disableDiscovery()174     public native void disableDiscovery();
175 
176     @Override
doGetSecureElementList()177     public native int[] doGetSecureElementList();
178 
179     @Override
doSelectSecureElement()180     public native void doSelectSecureElement();
181 
182     @Override
doDeselectSecureElement()183     public native void doDeselectSecureElement();
184 
185 
doCreateLlcpConnectionlessSocket(int nSap, String sn)186     private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap,
187             String sn);
188 
189     @Override
createLlcpConnectionlessSocket(int nSap, String sn)190     public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn)
191             throws LlcpException {
192         LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn);
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 
doCreateLlcpServiceSocket(int nSap, String sn, int miu, int rw, int linearBufferLength)211     private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu,
212             int rw, int linearBufferLength);
213     @Override
createLlcpServerSocket(int nSap, String sn, int miu, int rw, int linearBufferLength)214     public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu,
215             int rw, int linearBufferLength) throws LlcpException {
216         LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, 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 
doCreateLlcpSocket(int sap, int miu, int rw, int linearBufferLength)235     private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw,
236             int linearBufferLength);
237     @Override
createLlcpSocket(int sap, int miu, int rw, int linearBufferLength)238     public LlcpSocket createLlcpSocket(int sap, int miu, int rw,
239             int linearBufferLength) throws LlcpException {
240         LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength);
241         if (socket != null) {
242             return socket;
243         } else {
244             /* Get Error Status */
245             int error = doGetLastError();
246 
247             Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
248 
249             switch (error) {
250                 case ErrorCodes.ERROR_BUFFER_TO_SMALL:
251                 case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
252                     throw new LlcpException(error);
253                 default:
254                     throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
255             }
256         }
257     }
258 
259     @Override
doCheckLlcp()260     public native boolean doCheckLlcp();
261 
262     @Override
doActivateLlcp()263     public native boolean doActivateLlcp();
264 
doResetTimeouts()265     private native void doResetTimeouts();
266 
267     @Override
resetTimeouts()268     public void resetTimeouts() {
269         doResetTimeouts();
270     }
271 
272     @Override
doAbort()273     public native void doAbort();
274 
doSetTimeout(int tech, int timeout)275     private native boolean doSetTimeout(int tech, int timeout);
276     @Override
setTimeout(int tech, int timeout)277     public boolean setTimeout(int tech, int timeout) {
278         return doSetTimeout(tech, timeout);
279     }
280 
doGetTimeout(int tech)281     private native int doGetTimeout(int tech);
282     @Override
getTimeout(int tech)283     public int getTimeout(int tech) {
284         return doGetTimeout(tech);
285     }
286 
287 
288     @Override
canMakeReadOnly(int ndefType)289     public boolean canMakeReadOnly(int ndefType) {
290         return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2 ||
291                 ndefType == Ndef.TYPE_MIFARE_CLASSIC);
292     }
293 
294     @Override
getMaxTransceiveLength(int technology)295     public int getMaxTransceiveLength(int technology) {
296         switch (technology) {
297             case (TagTechnology.NFC_A):
298             case (TagTechnology.MIFARE_CLASSIC):
299             case (TagTechnology.MIFARE_ULTRALIGHT):
300                 return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
301             case (TagTechnology.NFC_B):
302                 return 0; // PN544 does not support transceive of raw NfcB
303             case (TagTechnology.NFC_V):
304                 return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
305             case (TagTechnology.ISO_DEP):
306                 /* The maximum length of a normal IsoDep frame consists of:
307                  * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes
308                  * such a frame is supported. Extended length frames however
309                  * are not supported.
310                  */
311                 return 261; // Will be automatically split in two frames on the RF layer
312             case (TagTechnology.NFC_F):
313                 return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC
314             default:
315                 return 0;
316         }
317 
318     }
319 
doSetP2pInitiatorModes(int modes)320     private native void doSetP2pInitiatorModes(int modes);
321     @Override
setP2pInitiatorModes(int modes)322     public void setP2pInitiatorModes(int modes) {
323         doSetP2pInitiatorModes(modes);
324     }
325 
doSetP2pTargetModes(int modes)326     private native void doSetP2pTargetModes(int modes);
327     @Override
setP2pTargetModes(int modes)328     public void setP2pTargetModes(int modes) {
329         doSetP2pTargetModes(modes);
330     }
331 
332     @Override
getExtendedLengthApdusSupported()333     public boolean getExtendedLengthApdusSupported() {
334         // Not supported on the PN544
335         return false;
336     }
337 
338     @Override
enablePN544Quirks()339     public boolean enablePN544Quirks() {
340         return true;
341     }
342 
343     @Override
getWipeApdus()344     public byte[][] getWipeApdus() {
345         return EE_WIPE_APDUS;
346     }
347 
348     @Override
getDefaultLlcpMiu()349     public int getDefaultLlcpMiu() {
350         return DEFAULT_LLCP_MIU;
351     }
352 
353     @Override
getDefaultLlcpRwSize()354     public int getDefaultLlcpRwSize() {
355         return DEFAULT_LLCP_RWSIZE;
356     }
357 
doDump()358     private native String doDump();
359     @Override
dump()360     public String dump() {
361         return doDump();
362     }
363 
364     /**
365      * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered)
366      */
notifyNdefMessageListeners(NativeNfcTag tag)367     private void notifyNdefMessageListeners(NativeNfcTag tag) {
368         mListener.onRemoteEndpointDiscovered(tag);
369     }
370 
371     /**
372      * Notifies transaction
373      */
notifyTargetDeselected()374     private void notifyTargetDeselected() {
375         mListener.onCardEmulationDeselected();
376     }
377 
378     /**
379      * Notifies transaction
380      */
notifyTransactionListeners(byte[] aid)381     private void notifyTransactionListeners(byte[] aid) {
382         mListener.onCardEmulationAidSelected(aid);
383     }
384 
385     /**
386      * Notifies P2P Device detected, to activate LLCP link
387      */
notifyLlcpLinkActivation(NativeP2pDevice device)388     private void notifyLlcpLinkActivation(NativeP2pDevice device) {
389         mListener.onLlcpLinkActivated(device);
390     }
391 
392     /**
393      * Notifies P2P Device detected, to activate LLCP link
394      */
notifyLlcpLinkDeactivated(NativeP2pDevice device)395     private void notifyLlcpLinkDeactivated(NativeP2pDevice device) {
396         mListener.onLlcpLinkDeactivated(device);
397     }
398 
notifySeFieldActivated()399     private void notifySeFieldActivated() {
400         mListener.onRemoteFieldActivated();
401     }
402 
notifySeFieldDeactivated()403     private void notifySeFieldDeactivated() {
404         mListener.onRemoteFieldDeactivated();
405     }
406 
notifySeApduReceived(byte[] apdu)407     private void notifySeApduReceived(byte[] apdu) {
408         mListener.onSeApduReceived(apdu);
409     }
410 
notifySeEmvCardRemoval()411     private void notifySeEmvCardRemoval() {
412         mListener.onSeEmvCardRemoval();
413     }
414 
notifySeMifareAccess(byte[] block)415     private void notifySeMifareAccess(byte[] block) {
416         mListener.onSeMifareAccess(block);
417     }
418 
419 }
420