NativeNfcManager.java revision 525c260303268a83da4c3413b953d13c9084e834
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
17package com.android.nfc.dhimpl;
18
19import com.android.nfc.DeviceHost;
20import com.android.nfc.LlcpException;
21
22import android.annotation.SdkConstant;
23import android.annotation.SdkConstant.SdkConstantType;
24import android.content.Context;
25import android.content.SharedPreferences;
26import android.nfc.ErrorCodes;
27import android.nfc.tech.Ndef;
28import android.nfc.tech.TagTechnology;
29import android.util.Log;
30
31import java.io.File;
32
33/**
34 * Native interface to the NFC Manager functions
35 */
36public 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
78    public NativeNfcManager(Context context, DeviceHostListener listener) {
79        mListener = listener;
80        initializeNativeStructure();
81        mContext = context;
82    }
83
84    public native boolean initializeNativeStructure();
85
86    private native boolean doDownload();
87
88    public native int doGetLastError();
89
90    @Override
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
134    private native boolean doInitialize();
135
136    @Override
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
152    private native boolean doDeinitialize();
153
154    @Override
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
166    public String getName() {
167        return DRIVER_NAME;
168    }
169
170    @Override
171    public native void enableDiscovery();
172
173    @Override
174    public native void disableDiscovery();
175
176    @Override
177    public native int[] doGetSecureElementList();
178
179    @Override
180    public native void doSelectSecureElement();
181
182    @Override
183    public native void doDeselectSecureElement();
184
185
186    private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap,
187            String sn);
188
189    @Override
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
211    private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu,
212            int rw, int linearBufferLength);
213    @Override
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
235    private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw,
236            int linearBufferLength);
237    @Override
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
260    public native boolean doCheckLlcp();
261
262    @Override
263    public native boolean doActivateLlcp();
264
265    private native void doResetTimeouts();
266
267    @Override
268    public void resetTimeouts() {
269        doResetTimeouts();
270    }
271
272    @Override
273    public native void doAbort();
274
275    private native boolean doSetTimeout(int tech, int timeout);
276    @Override
277    public boolean setTimeout(int tech, int timeout) {
278        return doSetTimeout(tech, timeout);
279    }
280
281    private native int doGetTimeout(int tech);
282    @Override
283    public int getTimeout(int tech) {
284        return doGetTimeout(tech);
285    }
286
287
288    @Override
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
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
320    private native void doSetP2pInitiatorModes(int modes);
321    @Override
322    public void setP2pInitiatorModes(int modes) {
323        doSetP2pInitiatorModes(modes);
324    }
325
326    private native void doSetP2pTargetModes(int modes);
327    @Override
328    public void setP2pTargetModes(int modes) {
329        doSetP2pTargetModes(modes);
330    }
331
332    @Override
333    public boolean getExtendedLengthApdusSupported() {
334        // Not supported on the PN544
335        return false;
336    }
337
338    @Override
339    public boolean enablePN544Quirks() {
340        return true;
341    }
342
343    @Override
344    public byte[][] getWipeApdus() {
345        return EE_WIPE_APDUS;
346    }
347
348    @Override
349    public int getDefaultLlcpMiu() {
350        return DEFAULT_LLCP_MIU;
351    }
352
353    @Override
354    public int getDefaultLlcpRwSize() {
355        return DEFAULT_LLCP_RWSIZE;
356    }
357
358    private native String doDump();
359    @Override
360    public String dump() {
361        return doDump();
362    }
363
364    /**
365     * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered)
366     */
367    private void notifyNdefMessageListeners(NativeNfcTag tag) {
368        mListener.onRemoteEndpointDiscovered(tag);
369    }
370
371    /**
372     * Notifies transaction
373     */
374    private void notifyTargetDeselected() {
375        mListener.onCardEmulationDeselected();
376    }
377
378    /**
379     * Notifies transaction
380     */
381    private void notifyTransactionListeners(byte[] aid) {
382        mListener.onCardEmulationAidSelected(aid);
383    }
384
385    /**
386     * Notifies P2P Device detected, to activate LLCP link
387     */
388    private void notifyLlcpLinkActivation(NativeP2pDevice device) {
389        mListener.onLlcpLinkActivated(device);
390    }
391
392    /**
393     * Notifies P2P Device detected, to activate LLCP link
394     */
395    private void notifyLlcpLinkDeactivated(NativeP2pDevice device) {
396        mListener.onLlcpLinkDeactivated(device);
397    }
398
399    private void notifySeFieldActivated() {
400        mListener.onRemoteFieldActivated();
401    }
402
403    private void notifySeFieldDeactivated() {
404        mListener.onRemoteFieldDeactivated();
405    }
406
407    private void notifySeApduReceived(byte[] apdu) {
408        mListener.onSeApduReceived(apdu);
409    }
410
411    private void notifySeEmvCardRemoval() {
412        mListener.onSeEmvCardRemoval();
413    }
414
415    private void notifySeMifareAccess(byte[] block) {
416        mListener.onSeMifareAccess(block);
417    }
418
419}
420