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 boolean sendRawFrame(byte[] data)
172    {
173        return false;
174    }
175
176    @Override
177    public boolean routeAid(byte[] aid, int route)
178    {
179        return false;
180    }
181
182    @Override
183    public boolean unrouteAid(byte[] aid)
184    {
185       return false;
186    }
187
188    @Override
189    public native void enableDiscovery();
190
191    @Override
192    public native void disableDiscovery();
193
194    @Override
195    public void enableRoutingToHost()
196    {
197
198    }
199
200    @Override
201    public void disableRoutingToHost()
202    {
203
204    }
205
206    @Override
207    public native int[] doGetSecureElementList();
208
209    @Override
210    public native void doSelectSecureElement();
211
212    @Override
213    public native void doDeselectSecureElement();
214
215
216    private native NativeLlcpConnectionlessSocket doCreateLlcpConnectionlessSocket(int nSap,
217            String sn);
218
219    @Override
220    public LlcpConnectionlessSocket createLlcpConnectionlessSocket(int nSap, String sn)
221            throws LlcpException {
222        LlcpConnectionlessSocket socket = doCreateLlcpConnectionlessSocket(nSap, sn);
223        if (socket != null) {
224            return socket;
225        } else {
226            /* Get Error Status */
227            int error = doGetLastError();
228
229            Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
230
231            switch (error) {
232                case ErrorCodes.ERROR_BUFFER_TO_SMALL:
233                case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
234                    throw new LlcpException(error);
235                default:
236                    throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
237            }
238        }
239    }
240
241    private native NativeLlcpServiceSocket doCreateLlcpServiceSocket(int nSap, String sn, int miu,
242            int rw, int linearBufferLength);
243    @Override
244    public LlcpServerSocket createLlcpServerSocket(int nSap, String sn, int miu,
245            int rw, int linearBufferLength) throws LlcpException {
246        LlcpServerSocket socket = doCreateLlcpServiceSocket(nSap, sn, miu, rw, linearBufferLength);
247        if (socket != null) {
248            return socket;
249        } else {
250            /* Get Error Status */
251            int error = doGetLastError();
252
253            Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
254
255            switch (error) {
256                case ErrorCodes.ERROR_BUFFER_TO_SMALL:
257                case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
258                    throw new LlcpException(error);
259                default:
260                    throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
261            }
262        }
263    }
264
265    private native NativeLlcpSocket doCreateLlcpSocket(int sap, int miu, int rw,
266            int linearBufferLength);
267    @Override
268    public LlcpSocket createLlcpSocket(int sap, int miu, int rw,
269            int linearBufferLength) throws LlcpException {
270        LlcpSocket socket = doCreateLlcpSocket(sap, miu, rw, linearBufferLength);
271        if (socket != null) {
272            return socket;
273        } else {
274            /* Get Error Status */
275            int error = doGetLastError();
276
277            Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(error));
278
279            switch (error) {
280                case ErrorCodes.ERROR_BUFFER_TO_SMALL:
281                case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
282                    throw new LlcpException(error);
283                default:
284                    throw new LlcpException(ErrorCodes.ERROR_SOCKET_CREATION);
285            }
286        }
287    }
288
289    @Override
290    public native boolean doCheckLlcp();
291
292    @Override
293    public native boolean doActivateLlcp();
294
295    private native void doResetTimeouts();
296
297    @Override
298    public void resetTimeouts() {
299        doResetTimeouts();
300    }
301
302    @Override
303    public native void doAbort();
304
305    private native boolean doSetTimeout(int tech, int timeout);
306    @Override
307    public boolean setTimeout(int tech, int timeout) {
308        return doSetTimeout(tech, timeout);
309    }
310
311    private native int doGetTimeout(int tech);
312    @Override
313    public int getTimeout(int tech) {
314        return doGetTimeout(tech);
315    }
316
317
318    @Override
319    public boolean canMakeReadOnly(int ndefType) {
320        return (ndefType == Ndef.TYPE_1 || ndefType == Ndef.TYPE_2 ||
321                ndefType == Ndef.TYPE_MIFARE_CLASSIC);
322    }
323
324    @Override
325    public int getMaxTransceiveLength(int technology) {
326        switch (technology) {
327            case (TagTechnology.NFC_A):
328            case (TagTechnology.MIFARE_CLASSIC):
329            case (TagTechnology.MIFARE_ULTRALIGHT):
330                return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
331            case (TagTechnology.NFC_B):
332                return 0; // PN544 does not support transceive of raw NfcB
333            case (TagTechnology.NFC_V):
334                return 253; // PN544 RF buffer = 255 bytes, subtract two for CRC
335            case (TagTechnology.ISO_DEP):
336                /* The maximum length of a normal IsoDep frame consists of:
337                 * CLA, INS, P1, P2, LC, LE + 255 payload bytes = 261 bytes
338                 * such a frame is supported. Extended length frames however
339                 * are not supported.
340                 */
341                return 261; // Will be automatically split in two frames on the RF layer
342            case (TagTechnology.NFC_F):
343                return 252; // PN544 RF buffer = 255 bytes, subtract one for SoD, two for CRC
344            default:
345                return 0;
346        }
347
348    }
349
350    private native void doSetP2pInitiatorModes(int modes);
351    @Override
352    public void setP2pInitiatorModes(int modes) {
353        doSetP2pInitiatorModes(modes);
354    }
355
356    private native void doSetP2pTargetModes(int modes);
357    @Override
358    public void setP2pTargetModes(int modes) {
359        doSetP2pTargetModes(modes);
360    }
361
362    private native void doEnableReaderMode(int technologies);
363    public boolean enableReaderMode(int technologies) {
364        doEnableReaderMode(technologies);
365        return true;
366    }
367
368    private native void doDisableReaderMode();
369    public boolean disableReaderMode() {
370        doDisableReaderMode();
371        return true;
372    }
373
374    @Override
375    public boolean getExtendedLengthApdusSupported() {
376        // Not supported on the PN544
377        return false;
378    }
379
380    @Override
381    public boolean enablePN544Quirks() {
382        return true;
383    }
384
385    @Override
386    public byte[][] getWipeApdus() {
387        return EE_WIPE_APDUS;
388    }
389
390    @Override
391    public int getDefaultLlcpMiu() {
392        return DEFAULT_LLCP_MIU;
393    }
394
395    @Override
396    public int getDefaultLlcpRwSize() {
397        return DEFAULT_LLCP_RWSIZE;
398    }
399
400    private native String doDump();
401    @Override
402    public String dump() {
403        return doDump();
404    }
405
406    /**
407     * Notifies Ndef Message (TODO: rename into notifyTargetDiscovered)
408     */
409    private void notifyNdefMessageListeners(NativeNfcTag tag) {
410        mListener.onRemoteEndpointDiscovered(tag);
411    }
412
413    /**
414     * Notifies transaction
415     */
416    private void notifyTargetDeselected() {
417        mListener.onCardEmulationDeselected();
418    }
419
420    /**
421     * Notifies transaction
422     */
423    private void notifyTransactionListeners(byte[] aid) {
424        mListener.onCardEmulationAidSelected(aid);
425    }
426
427    /**
428     * Notifies P2P Device detected, to activate LLCP link
429     */
430    private void notifyLlcpLinkActivation(NativeP2pDevice device) {
431        mListener.onLlcpLinkActivated(device);
432    }
433
434    /**
435     * Notifies P2P Device detected, to activate LLCP link
436     */
437    private void notifyLlcpLinkDeactivated(NativeP2pDevice device) {
438        mListener.onLlcpLinkDeactivated(device);
439    }
440
441    private void notifySeFieldActivated() {
442        mListener.onRemoteFieldActivated();
443    }
444
445    private void notifySeFieldDeactivated() {
446        mListener.onRemoteFieldDeactivated();
447    }
448
449    private void notifySeApduReceived(byte[] apdu) {
450        mListener.onSeApduReceived(apdu);
451    }
452
453    private void notifySeEmvCardRemoval() {
454        mListener.onSeEmvCardRemoval();
455    }
456
457    private void notifySeMifareAccess(byte[] block) {
458        mListener.onSeMifareAccess(block);
459    }
460
461}
462