NfcService.java revision 70bbea61637e3f9eb7202efd243b9d2f9516a06a
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;
18
19import com.android.internal.nfc.LlcpServiceSocket;
20import com.android.internal.nfc.LlcpSocket;
21import com.android.nfc.DeviceHost.DeviceHostListener;
22import com.android.nfc.DeviceHost.NfcDepEndpoint;
23import com.android.nfc.DeviceHost.TagEndpoint;
24import com.android.nfc.nxp.NativeLlcpConnectionlessSocket;
25import com.android.nfc.nxp.NativeLlcpServiceSocket;
26import com.android.nfc.nxp.NativeLlcpSocket;
27import com.android.nfc.nxp.NativeNfcManager;
28import com.android.nfc.nxp.NativeNfcSecureElement;
29import com.android.nfc3.R;
30
31import android.app.Application;
32import android.app.KeyguardManager;
33import android.app.PendingIntent;
34import android.app.StatusBarManager;
35import android.content.BroadcastReceiver;
36import android.content.ComponentName;
37import android.content.Context;
38import android.content.Intent;
39import android.content.IntentFilter;
40import android.content.SharedPreferences;
41import android.content.pm.PackageManager;
42import android.media.AudioManager;
43import android.media.SoundPool;
44import android.net.Uri;
45import android.nfc.ErrorCodes;
46import android.nfc.FormatException;
47import android.nfc.ILlcpConnectionlessSocket;
48import android.nfc.ILlcpServiceSocket;
49import android.nfc.ILlcpSocket;
50import android.nfc.INdefPushCallback;
51import android.nfc.INfcAdapter;
52import android.nfc.INfcAdapterExtras;
53import android.nfc.INfcTag;
54import android.nfc.IP2pInitiator;
55import android.nfc.IP2pTarget;
56import android.nfc.LlcpPacket;
57import android.nfc.NdefMessage;
58import android.nfc.NdefRecord;
59import android.nfc.NfcAdapter;
60import android.nfc.Tag;
61import android.nfc.TechListParcel;
62import android.nfc.TransceiveResult;
63import android.nfc.tech.Ndef;
64import android.nfc.tech.TagTechnology;
65import android.os.AsyncTask;
66import android.os.Bundle;
67import android.os.Handler;
68import android.os.IBinder;
69import android.os.Message;
70import android.os.PowerManager;
71import android.os.RemoteException;
72import android.os.ServiceManager;
73import android.util.Log;
74
75import java.io.ByteArrayOutputStream;
76import java.io.DataInputStream;
77import java.io.FileInputStream;
78import java.io.FileNotFoundException;
79import java.io.FileOutputStream;
80import java.io.IOException;
81import java.util.ArrayList;
82import java.util.HashMap;
83import java.util.HashSet;
84import java.util.Iterator;
85import java.util.List;
86
87public class NfcService extends Application implements DeviceHostListener {
88    private static final String ACTION_MASTER_CLEAR_NOTIFICATION = "android.intent.action.MASTER_CLEAR_NOTIFICATION";
89
90    static final boolean DBG = true;
91    static final String TAG = "NfcService";
92
93    private static final String SE_RESET_SCRIPT_FILE_NAME = "/system/etc/se-reset-script";
94
95    public static final String SERVICE_NAME = "nfc";
96
97    private static final String NFC_PERM = android.Manifest.permission.NFC;
98    private static final String NFC_PERM_ERROR = "NFC permission required";
99    private static final String ADMIN_PERM = android.Manifest.permission.WRITE_SECURE_SETTINGS;
100    private static final String ADMIN_PERM_ERROR = "WRITE_SECURE_SETTINGS permission required";
101    private static final String NFCEE_ADMIN_PERM = "com.android.nfc.permission.NFCEE_ADMIN";
102    private static final String NFCEE_ADMIN_PERM_ERROR = "NFCEE_ADMIN permission required";
103
104    /*package*/ static final String PREF = "NfcServicePrefs";
105
106    private static final String PREF_NFC_ON = "nfc_on";
107    private static final boolean NFC_ON_DEFAULT = true;
108    private static final String PREF_ZEROCLICK_ON = "zeroclick_on";
109    private static final boolean ZEROCLICK_ON_DEFAULT = true;
110
111    private static final String PREF_FIRST_BOOT = "first_boot";
112
113    static final int MSG_NDEF_TAG = 0;
114    static final int MSG_CARD_EMULATION = 1;
115    static final int MSG_LLCP_LINK_ACTIVATION = 2;
116    static final int MSG_LLCP_LINK_DEACTIVATED = 3;
117    static final int MSG_TARGET_DESELECTED = 4;
118    static final int MSG_MOCK_NDEF = 7;
119    static final int MSG_SE_FIELD_ACTIVATED = 8;
120    static final int MSG_SE_FIELD_DEACTIVATED = 9;
121    static final int MSG_SE_APDU_RECEIVED = 10;
122    static final int MSG_SE_EMV_CARD_REMOVAL = 11;
123    static final int MSG_SE_MIFARE_ACCESS = 12;
124
125    // Copied from com.android.nfc_extras to avoid library dependency
126    // Must keep in sync with com.android.nfc_extras
127    static final int ROUTE_OFF = 1;
128    static final int ROUTE_ON_WHEN_SCREEN_ON = 2;
129
130    public static final String ACTION_RF_FIELD_ON_DETECTED =
131        "com.android.nfc_extras.action.RF_FIELD_ON_DETECTED";
132    public static final String ACTION_RF_FIELD_OFF_DETECTED =
133        "com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED";
134    public static final String ACTION_AID_SELECTED =
135        "com.android.nfc_extras.action.AID_SELECTED";
136    public static final String EXTRA_AID = "com.android.nfc_extras.extra.AID";
137
138    public static final String ACTION_APDU_RECEIVED =
139        "com.android.nfc_extras.action.APDU_RECEIVED";
140    public static final String EXTRA_APDU_BYTES =
141        "com.android.nfc_extras.extra.APDU_BYTES";
142
143    public static final String ACTION_EMV_CARD_REMOVAL =
144        "com.android.nfc_extras.action.EMV_CARD_REMOVAL";
145
146    public static final String ACTION_MIFARE_ACCESS_DETECTED =
147        "com.android.nfc_extras.action.MIFARE_ACCESS_DETECTED";
148    public static final String EXTRA_MIFARE_BLOCK =
149        "com.android.nfc_extras.extra.MIFARE_BLOCK";
150
151    // TODO: none of these appear to be synchronized but are
152    // read/written from different threads (notably Binder threads)...
153    private int mGeneratedSocketHandle = 0;
154    private volatile boolean mIsNfcEnabled = false;
155    private boolean mIsDiscoveryOn = false;
156    private boolean mZeroClickOn = false;
157
158    // NFC Execution Environment
159    // fields below are protected by this
160    private NativeNfcSecureElement mSecureElement;
161    private OpenSecureElement mOpenEe;  // null when EE closed
162    private int mEeRoutingState;  // contactless interface routing
163
164    // fields below are used in multiple threads and protected by synchronized(this)
165    private final HashMap<Integer, Object> mObjectMap = new HashMap<Integer, Object>();
166    private final HashMap<Integer, Object> mSocketMap = new HashMap<Integer, Object>();
167    private boolean mScreenUnlocked;
168    private HashSet<String> mSePackages = new HashSet<String>();
169
170    // fields below are final after onCreate()
171    Context mContext;
172    private NativeNfcManager mDeviceHost;
173    private SharedPreferences mPrefs;
174    private SharedPreferences.Editor mPrefsEditor;
175    private PowerManager.WakeLock mWakeLock;
176    NdefP2pManager mP2pManager;
177    int mStartSound;
178    int mEndSound;
179    int mErrorSound;
180    SoundPool mSoundPool; // playback synchronized on this
181
182    private NfcDispatcher mNfcDispatcher;
183    private KeyguardManager mKeyguard;
184
185    private static NfcService sService;
186
187    public static void enforceAdminPerm(Context context) {
188        int admin = context.checkCallingOrSelfPermission(ADMIN_PERM);
189        int nfcee = context.checkCallingOrSelfPermission(NFCEE_ADMIN_PERM);
190        if (admin != PackageManager.PERMISSION_GRANTED
191                && nfcee != PackageManager.PERMISSION_GRANTED) {
192            throw new SecurityException(ADMIN_PERM_ERROR);
193        }
194    }
195
196    public static void enforceNfceeAdminPerm(Context context) {
197        context.enforceCallingOrSelfPermission(NFCEE_ADMIN_PERM, NFCEE_ADMIN_PERM_ERROR);
198    }
199
200    public static NfcService getInstance() {
201        return sService;
202    }
203
204    @Override
205    public void onRemoteEndpointDiscovered(TagEndpoint tag) {
206        sendMessage(NfcService.MSG_NDEF_TAG, tag);
207    }
208
209    /**
210     * Notifies transaction
211     */
212    @Override
213    public void onCardEmulationDeselected() {
214        sendMessage(NfcService.MSG_TARGET_DESELECTED, null);
215    }
216
217    /**
218     * Notifies transaction
219     */
220    @Override
221    public void onCardEmulationAidSelected(byte[] aid) {
222        sendMessage(NfcService.MSG_CARD_EMULATION, aid);
223    }
224
225    /**
226     * Notifies P2P Device detected, to activate LLCP link
227     */
228    @Override
229    public void onLlcpLinkActivated(NfcDepEndpoint device) {
230        sendMessage(NfcService.MSG_LLCP_LINK_ACTIVATION, device);
231    }
232
233    /**
234     * Notifies P2P Device detected, to activate LLCP link
235     */
236    @Override
237    public void onLlcpLinkDeactivated(NfcDepEndpoint device) {
238        sendMessage(NfcService.MSG_LLCP_LINK_DEACTIVATED, device);
239    }
240
241    @Override
242    public void onRemoteFieldActivated() {
243        sendMessage(NfcService.MSG_SE_FIELD_ACTIVATED, null);
244    }
245
246    @Override
247    public void onRemoteFieldDeactivated() {
248        sendMessage(NfcService.MSG_SE_FIELD_DEACTIVATED, null);
249    }
250
251    @Override
252    public void onSeApduReceived(byte[] apdu) {
253        sendMessage(NfcService.MSG_SE_APDU_RECEIVED, apdu);
254    }
255
256    @Override
257    public void onSeEmvCardRemoval() {
258        sendMessage(NfcService.MSG_SE_EMV_CARD_REMOVAL, null);
259    }
260
261    @Override
262    public void onSeMifareAccess(byte[] block) {
263        sendMessage(NfcService.MSG_SE_MIFARE_ACCESS, block);
264    }
265
266    @Override
267    public void onCreate() {
268        super.onCreate();
269
270        Log.i(TAG, "Starting NFC service");
271
272        sService = this;
273
274        mSoundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0);
275        mStartSound = mSoundPool.load(this, R.raw.start, 1);
276        mEndSound = mSoundPool.load(this, R.raw.end, 1);
277        mErrorSound = mSoundPool.load(this, R.raw.error, 1);
278
279        mContext = this;
280        mDeviceHost = new NativeNfcManager(this, this);
281        mDeviceHost.initializeNativeStructure();
282
283        mP2pManager = new NdefP2pManager(this, mNfcAdapter);
284        mNfcDispatcher = new NfcDispatcher(this, mP2pManager);
285
286        mSecureElement = new NativeNfcSecureElement();
287        mEeRoutingState = ROUTE_OFF;
288
289        mPrefs = getSharedPreferences(PREF, Context.MODE_PRIVATE);
290        mPrefsEditor = mPrefs.edit();
291
292        mIsNfcEnabled = false;  // load from preferences later
293
294        PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
295
296        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "NfcService");
297        mKeyguard = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
298        mScreenUnlocked = !mKeyguard.isKeyguardLocked() && !mKeyguard.isKeyguardSecure();
299
300        ServiceManager.addService(SERVICE_NAME, mNfcAdapter);
301
302        IntentFilter filter = new IntentFilter(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION);
303        filter.addAction(Intent.ACTION_SCREEN_OFF);
304        filter.addAction(Intent.ACTION_SCREEN_ON);
305        filter.addAction(ACTION_MASTER_CLEAR_NOTIFICATION);
306        filter.addAction(Intent.ACTION_USER_PRESENT);
307        registerReceiver(mReceiver, filter);
308
309        filter = new IntentFilter();
310        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
311        filter.addDataScheme("package");
312
313        registerReceiver(mReceiver, filter);
314
315        Thread t = new Thread() {
316            @Override
317            public void run() {
318                boolean nfc_on = mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT);
319                if (nfc_on) {
320                    _enable(false, true);
321                }
322                resetSeOnFirstBoot();
323            }
324        };
325        t.start();
326    }
327
328    public void playSound(int sound) {
329        synchronized (this) {
330            mSoundPool.play(sound, 1.0f, 1.0f, 0, 0, 1.0f);
331        }
332    }
333
334    @Override
335    public void onTerminate() {
336        super.onTerminate();
337        // NFC application is persistent, it should not be destroyed by framework
338        Log.wtf(TAG, "NFC service is under attack!");
339    }
340
341    private final INfcAdapter.Stub mNfcAdapter = new INfcAdapter.Stub() {
342        /** Protected by "this" */
343        NdefMessage mLocalMessage = null;
344
345        @Override
346        public boolean enable() throws RemoteException {
347            NfcService.enforceAdminPerm(mContext);
348
349            boolean isSuccess = false;
350            boolean previouslyEnabled = isEnabled();
351            if (!previouslyEnabled) {
352                reset();
353                isSuccess = _enable(previouslyEnabled, true);
354            }
355            return isSuccess;
356        }
357
358        @Override
359        public boolean disable() throws RemoteException {
360            boolean isSuccess = false;
361            NfcService.enforceAdminPerm(mContext);
362            boolean previouslyEnabled = isEnabled();
363            if (DBG) Log.d(TAG, "Disabling NFC.  previous=" + previouslyEnabled);
364
365            if (previouslyEnabled) {
366                isSuccess = _disable(previouslyEnabled, true);
367            }
368            return isSuccess;
369        }
370
371        @Override
372        public boolean zeroClickEnabled() throws RemoteException {
373            return mZeroClickOn;
374        }
375
376        @Override
377        public boolean enableZeroClick() throws RemoteException {
378            NfcService.enforceAdminPerm(mContext);
379            synchronized(NfcService.this) {
380                if (!mZeroClickOn) {
381                    Log.e(TAG, "ENABLING 0-CLICK");
382                    mPrefsEditor.putBoolean(PREF_ZEROCLICK_ON, true);
383                    mPrefsEditor.apply();
384                    mP2pManager.enableNdefServer();
385                    mZeroClickOn = true;
386                }
387            }
388            return true;
389        }
390
391        @Override
392        public boolean disableZeroClick() throws RemoteException {
393            NfcService.enforceAdminPerm(mContext);
394            synchronized(NfcService.this) {
395                if (mZeroClickOn) {
396                    Log.e(TAG, "DISABLING 0-CLICK");
397                    mPrefsEditor.putBoolean(PREF_ZEROCLICK_ON, false);
398                    mPrefsEditor.apply();
399                    mP2pManager.disableNdefServer();
400                    mZeroClickOn = false;
401                }
402            }
403            return true;
404        }
405
406
407        @Override
408        public void enableForegroundDispatch(ComponentName activity, PendingIntent intent,
409                IntentFilter[] filters, TechListParcel techListsParcel) {
410            // Permission check
411            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
412
413            // Argument validation
414            if (activity == null || intent == null) {
415                throw new IllegalArgumentException();
416            }
417
418            // Validate the IntentFilters
419            if (filters != null) {
420                if (filters.length == 0) {
421                    filters = null;
422                } else {
423                    for (IntentFilter filter : filters) {
424                        if (filter == null) {
425                            throw new IllegalArgumentException("null IntentFilter");
426                        }
427                    }
428                }
429            }
430
431            // Validate the tech lists
432            String[][] techLists = null;
433            if (techListsParcel != null) {
434                techLists = techListsParcel.getTechLists();
435            }
436
437            mNfcDispatcher.enableForegroundDispatch(intent, filters, techLists);
438        }
439
440        @Override
441        public void disableForegroundDispatch(ComponentName activity) {
442            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
443
444            mNfcDispatcher.disableForegroundDispatch();
445        }
446
447        @Override
448        public void enableForegroundNdefPush(ComponentName activity, NdefMessage msg) {
449            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
450            if (activity == null || msg == null) {
451                throw new IllegalArgumentException();
452            }
453            if (mP2pManager.setForegroundMessage(msg)) {
454                Log.e(TAG, "Replacing active NDEF push message");
455            }
456        }
457
458        @Override
459        public void enableForegroundNdefPushWithCallback(ComponentName activity,
460                INdefPushCallback callback) {
461            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
462            if (activity == null || callback == null) {
463                throw new IllegalArgumentException();
464            }
465            if (mP2pManager.setForegroundCallback(callback)) {
466                Log.e(TAG, "Replacing active NDEF push message");
467            }
468        }
469
470        @Override
471        public void disableForegroundNdefPush(ComponentName activity) {
472            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
473            boolean hadMsg = mP2pManager.setForegroundMessage(null);
474            boolean hadCallback = mP2pManager.setForegroundCallback(null);
475            if (!hadMsg || !hadCallback) {
476                Log.e(TAG, "No active foreground NDEF push message");
477            }
478        }
479
480        @Override
481        public int createLlcpConnectionlessSocket(int sap) throws RemoteException {
482            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
483
484            // Check if NFC is enabled
485            if (!mIsNfcEnabled) {
486                return ErrorCodes.ERROR_NOT_INITIALIZED;
487            }
488
489            /* Check SAP is not already used */
490
491            /* Store the socket handle */
492            int sockeHandle = mGeneratedSocketHandle;
493            NativeLlcpConnectionlessSocket socket;
494
495            socket = mDeviceHost.doCreateLlcpConnectionlessSocket(sap);
496            if (socket != null) {
497                synchronized(NfcService.this) {
498                    /* update socket handle generation */
499                    mGeneratedSocketHandle++;
500
501                    /* Add the socket into the socket map */
502                    mSocketMap.put(mGeneratedSocketHandle, socket);
503                   return mGeneratedSocketHandle;
504                }
505            } else {
506                /* Get Error Status */
507                int errorStatus = mDeviceHost.doGetLastError();
508
509                switch (errorStatus) {
510                    case ErrorCodes.ERROR_BUFFER_TO_SMALL:
511                        return ErrorCodes.ERROR_BUFFER_TO_SMALL;
512                    case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
513                        return ErrorCodes.ERROR_INSUFFICIENT_RESOURCES;
514                    default:
515                        return ErrorCodes.ERROR_SOCKET_CREATION;
516                }
517            }
518        }
519
520        @Override
521        public int createLlcpServiceSocket(int sap, String sn, int miu, int rw, int linearBufferLength)
522                throws RemoteException {
523            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
524
525            // Check if NFC is enabled
526            if (!mIsNfcEnabled) {
527                return ErrorCodes.ERROR_NOT_INITIALIZED;
528            }
529
530            NativeLlcpServiceSocket socket;
531
532            socket = mDeviceHost.doCreateLlcpServiceSocket(sap, sn, miu, rw, linearBufferLength);
533            if (socket != null) {
534                synchronized(NfcService.this) {
535                    /* update socket handle generation */
536                    mGeneratedSocketHandle++;
537
538                    /* Add the socket into the socket map */
539                    mSocketMap.put(mGeneratedSocketHandle, socket);
540                    return mGeneratedSocketHandle;
541                }
542            } else {
543                /* Get Error Status */
544                int errorStatus = mDeviceHost.doGetLastError();
545
546                switch (errorStatus) {
547                    case ErrorCodes.ERROR_BUFFER_TO_SMALL:
548                        return ErrorCodes.ERROR_BUFFER_TO_SMALL;
549                    case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
550                        return ErrorCodes.ERROR_INSUFFICIENT_RESOURCES;
551                    default:
552                        return ErrorCodes.ERROR_SOCKET_CREATION;
553                }
554            }
555        }
556
557        @Override
558        public int createLlcpSocket(int sap, int miu, int rw, int linearBufferLength)
559                throws RemoteException {
560            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
561
562            // Check if NFC is enabled
563            if (!mIsNfcEnabled) {
564                return ErrorCodes.ERROR_NOT_INITIALIZED;
565            }
566
567            if (DBG) Log.d(TAG, "creating llcp socket");
568            NativeLlcpSocket socket;
569
570            socket = mDeviceHost.doCreateLlcpSocket(sap, miu, rw, linearBufferLength);
571
572            if (socket != null) {
573                synchronized(NfcService.this) {
574                    /* update socket handle generation */
575                    mGeneratedSocketHandle++;
576
577                    /* Add the socket into the socket map */
578                    mSocketMap.put(mGeneratedSocketHandle, socket);
579                   return mGeneratedSocketHandle;
580                }
581            } else {
582                /* Get Error Status */
583                int errorStatus = mDeviceHost.doGetLastError();
584
585                Log.d(TAG, "failed to create llcp socket: " + ErrorCodes.asString(errorStatus));
586
587                switch (errorStatus) {
588                    case ErrorCodes.ERROR_BUFFER_TO_SMALL:
589                        return ErrorCodes.ERROR_BUFFER_TO_SMALL;
590                    case ErrorCodes.ERROR_INSUFFICIENT_RESOURCES:
591                        return ErrorCodes.ERROR_INSUFFICIENT_RESOURCES;
592                    default:
593                        return ErrorCodes.ERROR_SOCKET_CREATION;
594                }
595            }
596        }
597
598        @Override
599        public ILlcpConnectionlessSocket getLlcpConnectionlessInterface() throws RemoteException {
600            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
601            return mLlcpConnectionlessSocketService;
602        }
603
604        @Override
605        public ILlcpSocket getLlcpInterface() throws RemoteException {
606            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
607            return mLlcpSocket;
608        }
609
610        @Override
611        public ILlcpServiceSocket getLlcpServiceInterface() throws RemoteException {
612            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
613            return mLlcpServerSocketService;
614        }
615
616        @Override
617        public INfcTag getNfcTagInterface() throws RemoteException {
618            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
619            return mNfcTagService;
620        }
621
622        @Override
623        public IP2pInitiator getP2pInitiatorInterface() throws RemoteException {
624            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
625            return mP2pInitiatorService;
626        }
627
628        @Override
629        public IP2pTarget getP2pTargetInterface() throws RemoteException {
630            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
631            return mP2pTargetService;
632        }
633
634        @Override
635        public INfcAdapterExtras getNfcAdapterExtrasInterface() {
636            NfcService.enforceNfceeAdminPerm(mContext);
637            return mExtrasService;
638        }
639
640        @Override
641        public boolean isEnabled() throws RemoteException {
642            return mIsNfcEnabled;
643        }
644    };
645
646    private final ILlcpSocket mLlcpSocket = new ILlcpSocket.Stub() {
647
648        private NativeLlcpSocket findSocket(int nativeHandle) {
649            Object socket = NfcService.this.findSocket(nativeHandle);
650            if (!(socket instanceof NativeLlcpSocket)) {
651                return null;
652            }
653            return (NativeLlcpSocket) socket;
654        }
655
656        @Override
657        public int close(int nativeHandle) throws RemoteException {
658            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
659
660            NativeLlcpSocket socket = null;
661
662            // Check if NFC is enabled
663            if (!mIsNfcEnabled) {
664                return ErrorCodes.ERROR_NOT_INITIALIZED;
665            }
666
667            /* find the socket in the hmap */
668            socket = findSocket(nativeHandle);
669            if (socket != null) {
670                socket.doClose();
671                /* Remove the socket closed from the hmap */
672                removeSocket(nativeHandle);
673                return ErrorCodes.SUCCESS;
674            } else {
675                return ErrorCodes.ERROR_IO;
676            }
677        }
678
679        @Override
680        public int connect(int nativeHandle, int sap) throws RemoteException {
681            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
682
683            NativeLlcpSocket socket = null;
684            boolean isSuccess = false;
685
686            // Check if NFC is enabled
687            if (!mIsNfcEnabled) {
688                return ErrorCodes.ERROR_NOT_INITIALIZED;
689            }
690
691            /* find the socket in the hmap */
692            socket = findSocket(nativeHandle);
693            if (socket != null) {
694                isSuccess = socket.doConnect(sap);
695                if (isSuccess) {
696                    return ErrorCodes.SUCCESS;
697                } else {
698                    return ErrorCodes.ERROR_IO;
699                }
700            } else {
701                return ErrorCodes.ERROR_IO;
702            }
703
704        }
705
706        @Override
707        public int connectByName(int nativeHandle, String sn) throws RemoteException {
708            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
709
710            NativeLlcpSocket socket = null;
711            boolean isSuccess = false;
712
713            // Check if NFC is enabled
714            if (!mIsNfcEnabled) {
715                return ErrorCodes.ERROR_NOT_INITIALIZED;
716            }
717
718            /* find the socket in the hmap */
719            socket = findSocket(nativeHandle);
720            if (socket != null) {
721                isSuccess = socket.doConnectBy(sn);
722                if (isSuccess) {
723                    return ErrorCodes.SUCCESS;
724                } else {
725                    return ErrorCodes.ERROR_IO;
726                }
727            } else {
728                return ErrorCodes.ERROR_IO;
729            }
730
731        }
732
733        @Override
734        public int getLocalSap(int nativeHandle) throws RemoteException {
735            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
736
737            NativeLlcpSocket socket = null;
738
739            // Check if NFC is enabled
740            if (!mIsNfcEnabled) {
741                return ErrorCodes.ERROR_NOT_INITIALIZED;
742            }
743
744            /* find the socket in the hmap */
745            socket = findSocket(nativeHandle);
746            if (socket != null) {
747                return socket.getSap();
748            } else {
749                return 0;
750            }
751        }
752
753        @Override
754        public int getLocalSocketMiu(int nativeHandle) throws RemoteException {
755            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
756
757            NativeLlcpSocket socket = null;
758
759            // Check if NFC is enabled
760            if (!mIsNfcEnabled) {
761                return ErrorCodes.ERROR_NOT_INITIALIZED;
762            }
763
764            /* find the socket in the hmap */
765            socket = findSocket(nativeHandle);
766            if (socket != null) {
767                return socket.getMiu();
768            } else {
769                return 0;
770            }
771        }
772
773        @Override
774        public int getLocalSocketRw(int nativeHandle) throws RemoteException {
775            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
776
777            NativeLlcpSocket socket = null;
778
779            // Check if NFC is enabled
780            if (!mIsNfcEnabled) {
781                return ErrorCodes.ERROR_NOT_INITIALIZED;
782            }
783
784            /* find the socket in the hmap */
785            socket = findSocket(nativeHandle);
786            if (socket != null) {
787                return socket.getRw();
788            } else {
789                return 0;
790            }
791        }
792
793        @Override
794        public int getRemoteSocketMiu(int nativeHandle) throws RemoteException {
795            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
796
797            NativeLlcpSocket socket = null;
798
799            // Check if NFC is enabled
800            if (!mIsNfcEnabled) {
801                return ErrorCodes.ERROR_NOT_INITIALIZED;
802            }
803
804            /* find the socket in the hmap */
805            socket = findSocket(nativeHandle);
806            if (socket != null) {
807                if (socket.doGetRemoteSocketMiu() != 0) {
808                    return socket.doGetRemoteSocketMiu();
809                } else {
810                    return ErrorCodes.ERROR_SOCKET_NOT_CONNECTED;
811                }
812            } else {
813                return ErrorCodes.ERROR_SOCKET_NOT_CONNECTED;
814            }
815        }
816
817        @Override
818        public int getRemoteSocketRw(int nativeHandle) throws RemoteException {
819            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
820
821            NativeLlcpSocket socket = null;
822
823            // Check if NFC is enabled
824            if (!mIsNfcEnabled) {
825                return ErrorCodes.ERROR_NOT_INITIALIZED;
826            }
827
828            /* find the socket in the hmap */
829            socket = findSocket(nativeHandle);
830            if (socket != null) {
831                if (socket.doGetRemoteSocketRw() != 0) {
832                    return socket.doGetRemoteSocketRw();
833                } else {
834                    return ErrorCodes.ERROR_SOCKET_NOT_CONNECTED;
835                }
836            } else {
837                return ErrorCodes.ERROR_SOCKET_NOT_CONNECTED;
838            }
839        }
840
841        @Override
842        public int receive(int nativeHandle, byte[] receiveBuffer) throws RemoteException {
843            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
844
845            NativeLlcpSocket socket = null;
846
847            // Check if NFC is enabled
848            if (!mIsNfcEnabled) {
849                return ErrorCodes.ERROR_NOT_INITIALIZED;
850            }
851
852            /* find the socket in the hmap */
853            socket = findSocket(nativeHandle);
854            if (socket != null) {
855                return socket.doReceive(receiveBuffer);
856            } else {
857                return 0;
858            }
859        }
860
861        @Override
862        public int send(int nativeHandle, byte[] data) throws RemoteException {
863            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
864
865            NativeLlcpSocket socket = null;
866            boolean isSuccess = false;
867
868            // Check if NFC is enabled
869            if (!mIsNfcEnabled) {
870                return ErrorCodes.ERROR_NOT_INITIALIZED;
871            }
872
873            /* find the socket in the hmap */
874            socket = findSocket(nativeHandle);
875            if (socket != null) {
876                isSuccess = socket.doSend(data);
877                if (isSuccess) {
878                    return ErrorCodes.SUCCESS;
879                } else {
880                    return ErrorCodes.ERROR_IO;
881                }
882            } else {
883                return ErrorCodes.ERROR_IO;
884            }
885        }
886    };
887
888    private final ILlcpServiceSocket mLlcpServerSocketService = new ILlcpServiceSocket.Stub() {
889
890        private NativeLlcpServiceSocket findSocket(int nativeHandle) {
891            Object socket = NfcService.this.findSocket(nativeHandle);
892            if (!(socket instanceof NativeLlcpServiceSocket)) {
893                return null;
894            }
895            return (NativeLlcpServiceSocket) socket;
896        }
897
898        @Override
899        public int accept(int nativeHandle) throws RemoteException {
900            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
901
902            NativeLlcpServiceSocket socket = null;
903            NativeLlcpSocket clientSocket = null;
904
905            // Check if NFC is enabled
906            if (!mIsNfcEnabled) {
907                return ErrorCodes.ERROR_NOT_INITIALIZED;
908            }
909
910                /* find the socket in the hmap */
911                socket = findSocket(nativeHandle);
912                if (socket != null) {
913                    clientSocket = socket.doAccept(socket.getMiu(),
914                            socket.getRw(), socket.getLinearBufferLength());
915                    if (clientSocket != null) {
916                        /* Add the socket into the socket map */
917                        synchronized(this) {
918                            mGeneratedSocketHandle++;
919                            mSocketMap.put(mGeneratedSocketHandle, clientSocket);
920                            return mGeneratedSocketHandle;
921                        }
922                    } else {
923                        return ErrorCodes.ERROR_IO;
924                    }
925                } else {
926                    return ErrorCodes.ERROR_IO;
927                }
928        }
929
930        @Override
931        public void close(int nativeHandle) throws RemoteException {
932            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
933
934            NativeLlcpServiceSocket socket = null;
935
936            // Check if NFC is enabled
937            if (!mIsNfcEnabled) {
938                return;
939            }
940
941            /* find the socket in the hmap */
942            socket = findSocket(nativeHandle);
943            if (socket != null) {
944                socket.doClose();
945                synchronized (this) {
946                    /* Remove the socket closed from the hmap */
947                    removeSocket(nativeHandle);
948                }
949            }
950        }
951    };
952
953    private final ILlcpConnectionlessSocket mLlcpConnectionlessSocketService = new ILlcpConnectionlessSocket.Stub() {
954
955        private NativeLlcpConnectionlessSocket findSocket(int nativeHandle) {
956            Object socket = NfcService.this.findSocket(nativeHandle);
957            if (!(socket instanceof NativeLlcpConnectionlessSocket)) {
958                return null;
959            }
960            return (NativeLlcpConnectionlessSocket) socket;
961        }
962
963        @Override
964        public void close(int nativeHandle) throws RemoteException {
965            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
966
967            NativeLlcpConnectionlessSocket socket = null;
968
969            // Check if NFC is enabled
970            if (!mIsNfcEnabled) {
971                return;
972            }
973
974            /* find the socket in the hmap */
975            socket = findSocket(nativeHandle);
976            if (socket != null) {
977                socket.doClose();
978                /* Remove the socket closed from the hmap */
979                removeSocket(nativeHandle);
980            }
981        }
982
983        @Override
984        public int getSap(int nativeHandle) throws RemoteException {
985            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
986
987            NativeLlcpConnectionlessSocket socket = null;
988
989            // Check if NFC is enabled
990            if (!mIsNfcEnabled) {
991                return ErrorCodes.ERROR_NOT_INITIALIZED;
992            }
993
994            /* find the socket in the hmap */
995            socket = findSocket(nativeHandle);
996            if (socket != null) {
997                return socket.getSap();
998            } else {
999                return 0;
1000            }
1001        }
1002
1003        @Override
1004        public LlcpPacket receiveFrom(int nativeHandle) throws RemoteException {
1005            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1006
1007            NativeLlcpConnectionlessSocket socket = null;
1008            LlcpPacket packet;
1009
1010            // Check if NFC is enabled
1011            if (!mIsNfcEnabled) {
1012                return null;
1013            }
1014
1015            /* find the socket in the hmap */
1016            socket = findSocket(nativeHandle);
1017            if (socket != null) {
1018                packet = socket.doReceiveFrom(socket.getLinkMiu());
1019                if (packet != null) {
1020                    return packet;
1021                }
1022                return null;
1023            } else {
1024                return null;
1025            }
1026        }
1027
1028        @Override
1029        public int sendTo(int nativeHandle, LlcpPacket packet) throws RemoteException {
1030            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1031
1032            NativeLlcpConnectionlessSocket socket = null;
1033            boolean isSuccess = false;
1034
1035            // Check if NFC is enabled
1036            if (!mIsNfcEnabled) {
1037                return ErrorCodes.ERROR_NOT_INITIALIZED;
1038            }
1039
1040            /* find the socket in the hmap */
1041            socket = findSocket(nativeHandle);
1042            if (socket != null) {
1043                isSuccess = socket.doSendTo(packet.getRemoteSap(), packet.getDataBuffer());
1044                if (isSuccess) {
1045                    return ErrorCodes.SUCCESS;
1046                } else {
1047                    return ErrorCodes.ERROR_IO;
1048                }
1049            } else {
1050                return ErrorCodes.ERROR_IO;
1051            }
1052        }
1053    };
1054
1055    private final INfcTag mNfcTagService = new INfcTag.Stub() {
1056
1057        @Override
1058        public int close(int nativeHandle) throws RemoteException {
1059            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1060
1061            TagEndpoint tag = null;
1062
1063            // Check if NFC is enabled
1064            if (!mIsNfcEnabled) {
1065                return ErrorCodes.ERROR_NOT_INITIALIZED;
1066            }
1067
1068            /* find the tag in the hmap */
1069            tag = (TagEndpoint) findObject(nativeHandle);
1070            if (tag != null) {
1071                /* Remove the device from the hmap */
1072                unregisterObject(nativeHandle);
1073                tag.disconnect();
1074                return ErrorCodes.SUCCESS;
1075            }
1076            /* Restart polling loop for notification */
1077            applyRouting();
1078            return ErrorCodes.ERROR_DISCONNECT;
1079        }
1080
1081        @Override
1082        public int connect(int nativeHandle, int technology) throws RemoteException {
1083            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1084
1085            TagEndpoint tag = null;
1086
1087            // Check if NFC is enabled
1088            if (!mIsNfcEnabled) {
1089                return ErrorCodes.ERROR_NOT_INITIALIZED;
1090            }
1091
1092            /* find the tag in the hmap */
1093            tag = (TagEndpoint) findObject(nativeHandle);
1094            if (tag == null) {
1095                return ErrorCodes.ERROR_DISCONNECT;
1096            }
1097
1098            if (technology == TagTechnology.NFC_B) {
1099                return ErrorCodes.ERROR_NOT_SUPPORTED;
1100            }
1101
1102            // Note that on most tags, all technologies are behind a single
1103            // handle. This means that the connect at the lower levels
1104            // will do nothing, as the tag is already connected to that handle.
1105            if (tag.connect(technology)) {
1106                return ErrorCodes.SUCCESS;
1107            } else {
1108                return ErrorCodes.ERROR_DISCONNECT;
1109            }
1110        }
1111
1112        @Override
1113        public int reconnect(int nativeHandle) throws RemoteException {
1114            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1115
1116            TagEndpoint tag = null;
1117
1118            // Check if NFC is enabled
1119            if (!mIsNfcEnabled) {
1120                return ErrorCodes.ERROR_NOT_INITIALIZED;
1121            }
1122
1123            /* find the tag in the hmap */
1124            tag = (TagEndpoint) findObject(nativeHandle);
1125            if (tag != null) {
1126                if (tag.reconnect()) {
1127                    return ErrorCodes.SUCCESS;
1128                } else {
1129                    return ErrorCodes.ERROR_DISCONNECT;
1130                }
1131            }
1132            return ErrorCodes.ERROR_DISCONNECT;
1133        }
1134
1135        @Override
1136        public int[] getTechList(int nativeHandle) throws RemoteException {
1137            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1138
1139            // Check if NFC is enabled
1140            if (!mIsNfcEnabled) {
1141                return null;
1142            }
1143
1144            /* find the tag in the hmap */
1145            TagEndpoint tag = (TagEndpoint) findObject(nativeHandle);
1146            if (tag != null) {
1147                return tag.getTechList();
1148            }
1149            return null;
1150        }
1151
1152        @Override
1153        public byte[] getUid(int nativeHandle) throws RemoteException {
1154            TagEndpoint tag = null;
1155            byte[] uid;
1156
1157            // Check if NFC is enabled
1158            if (!mIsNfcEnabled) {
1159                return null;
1160            }
1161
1162            /* find the tag in the hmap */
1163            tag = (TagEndpoint) findObject(nativeHandle);
1164            if (tag != null) {
1165                uid = tag.getUid();
1166                return uid;
1167            }
1168            return null;
1169        }
1170
1171        @Override
1172        public boolean isPresent(int nativeHandle) throws RemoteException {
1173            TagEndpoint tag = null;
1174
1175            // Check if NFC is enabled
1176            if (!mIsNfcEnabled) {
1177                return false;
1178            }
1179
1180            /* find the tag in the hmap */
1181            tag = (TagEndpoint) findObject(nativeHandle);
1182            if (tag == null) {
1183                return false;
1184            }
1185
1186            return tag.isPresent();
1187        }
1188
1189        @Override
1190        public boolean isNdef(int nativeHandle) throws RemoteException {
1191            TagEndpoint tag = null;
1192
1193            // Check if NFC is enabled
1194            if (!mIsNfcEnabled) {
1195                return false;
1196            }
1197
1198            /* find the tag in the hmap */
1199            tag = (TagEndpoint) findObject(nativeHandle);
1200            int[] ndefInfo = new int[2];
1201            if (tag == null) {
1202                return false;
1203            }
1204            return tag.checkNdef(ndefInfo);
1205        }
1206
1207        @Override
1208        public TransceiveResult transceive(int nativeHandle, byte[] data, boolean raw)
1209                throws RemoteException {
1210            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1211
1212            TagEndpoint tag = null;
1213            byte[] response;
1214
1215            // Check if NFC is enabled
1216            if (!mIsNfcEnabled) {
1217                return null;
1218            }
1219
1220            /* find the tag in the hmap */
1221            tag = (TagEndpoint) findObject(nativeHandle);
1222            if (tag != null) {
1223                int[] targetLost = new int[1];
1224                response = tag.transceive(data, raw, targetLost);
1225                TransceiveResult transResult = new TransceiveResult(
1226                        (response != null) ? true : false,
1227                        (targetLost[0] == 1) ? true : false,
1228                        response);
1229                return transResult;
1230            }
1231            return null;
1232        }
1233
1234        @Override
1235        public NdefMessage ndefRead(int nativeHandle) throws RemoteException {
1236            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1237
1238            TagEndpoint tag;
1239
1240            // Check if NFC is enabled
1241            if (!mIsNfcEnabled) {
1242                return null;
1243            }
1244
1245            /* find the tag in the hmap */
1246            tag = (TagEndpoint) findObject(nativeHandle);
1247            if (tag != null) {
1248                byte[] buf = tag.readNdef();
1249                if (buf == null) {
1250                    return null;
1251                }
1252
1253                /* Create an NdefMessage */
1254                try {
1255                    return new NdefMessage(buf);
1256                } catch (FormatException e) {
1257                    return null;
1258                }
1259            }
1260            return null;
1261        }
1262
1263        @Override
1264        public int ndefWrite(int nativeHandle, NdefMessage msg) throws RemoteException {
1265            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1266
1267            TagEndpoint tag;
1268
1269            // Check if NFC is enabled
1270            if (!mIsNfcEnabled) {
1271                return ErrorCodes.ERROR_NOT_INITIALIZED;
1272            }
1273
1274            /* find the tag in the hmap */
1275            tag = (TagEndpoint) findObject(nativeHandle);
1276            if (tag == null) {
1277                return ErrorCodes.ERROR_IO;
1278            }
1279
1280            if (tag.writeNdef(msg.toByteArray())) {
1281                return ErrorCodes.SUCCESS;
1282            } else {
1283                return ErrorCodes.ERROR_IO;
1284            }
1285
1286        }
1287
1288        @Override
1289        public int getLastError(int nativeHandle) throws RemoteException {
1290            return(mDeviceHost.doGetLastError());
1291        }
1292
1293        @Override
1294        public boolean ndefIsWritable(int nativeHandle) throws RemoteException {
1295            throw new UnsupportedOperationException();
1296        }
1297
1298        @Override
1299        public int ndefMakeReadOnly(int nativeHandle) throws RemoteException {
1300            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1301
1302            TagEndpoint tag;
1303
1304            // Check if NFC is enabled
1305            if (!mIsNfcEnabled) {
1306                return ErrorCodes.ERROR_NOT_INITIALIZED;
1307            }
1308
1309            /* find the tag in the hmap */
1310            tag = (TagEndpoint) findObject(nativeHandle);
1311            if (tag == null) {
1312                return ErrorCodes.ERROR_IO;
1313            }
1314
1315            if (tag.makeReadOnly()) {
1316                return ErrorCodes.SUCCESS;
1317            } else {
1318                return ErrorCodes.ERROR_IO;
1319            }
1320        }
1321
1322        @Override
1323        public int formatNdef(int nativeHandle, byte[] key) throws RemoteException {
1324            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1325
1326            TagEndpoint tag;
1327
1328            // Check if NFC is enabled
1329            if (!mIsNfcEnabled) {
1330                return ErrorCodes.ERROR_NOT_INITIALIZED;
1331            }
1332
1333            /* find the tag in the hmap */
1334            tag = (TagEndpoint) findObject(nativeHandle);
1335            if (tag == null) {
1336                return ErrorCodes.ERROR_IO;
1337            }
1338
1339            if (tag.formatNdef(key)) {
1340                return ErrorCodes.SUCCESS;
1341            } else {
1342                return ErrorCodes.ERROR_IO;
1343            }
1344        }
1345
1346        @Override
1347        public Tag rediscover(int nativeHandle) throws RemoteException {
1348            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1349
1350            TagEndpoint tag = null;
1351
1352            // Check if NFC is enabled
1353            if (!mIsNfcEnabled) {
1354                return null;
1355            }
1356
1357            /* find the tag in the hmap */
1358            tag = (TagEndpoint) findObject(nativeHandle);
1359            if (tag != null) {
1360                // For now the prime usecase for rediscover() is to be able
1361                // to access the NDEF technology after formatting without
1362                // having to remove the tag from the field, or similar
1363                // to have access to NdefFormatable in case low-level commands
1364                // were used to remove NDEF. So instead of doing a full stack
1365                // rediscover (which is poorly supported at the moment anyway),
1366                // we simply remove these two technologies and detect them
1367                // again.
1368                tag.removeTechnology(TagTechnology.NDEF);
1369                tag.removeTechnology(TagTechnology.NDEF_FORMATABLE);
1370                NdefMessage[] msgs = tag.findAndReadNdef();
1371                // Build a new Tag object to return
1372                Tag newTag = new Tag(tag.getUid(), tag.getTechList(),
1373                        tag.getTechExtras(), tag.getHandle(), mNfcTagService);
1374                return newTag;
1375            }
1376            return null;
1377        }
1378
1379        @Override
1380        public int setTimeout(int tech, int timeout) throws RemoteException {
1381            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1382            boolean success = mDeviceHost.setTimeout(tech, timeout);
1383            if (success) {
1384                return ErrorCodes.SUCCESS;
1385            } else {
1386                return ErrorCodes.ERROR_INVALID_PARAM;
1387            }
1388        }
1389
1390        @Override
1391        public int getTimeout(int tech) throws RemoteException {
1392            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1393
1394            return mDeviceHost.getTimeout(tech);
1395        }
1396
1397        @Override
1398        public void resetTimeouts() throws RemoteException {
1399            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1400
1401            mDeviceHost.resetTimeouts();
1402        }
1403    };
1404
1405    private final IP2pInitiator mP2pInitiatorService = new IP2pInitiator.Stub() {
1406
1407        @Override
1408        public byte[] getGeneralBytes(int nativeHandle) throws RemoteException {
1409            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1410
1411            NfcDepEndpoint device;
1412
1413            // Check if NFC is enabled
1414            if (!mIsNfcEnabled) {
1415                return null;
1416            }
1417
1418            /* find the device in the hmap */
1419            device = (NfcDepEndpoint) findObject(nativeHandle);
1420            if (device != null) {
1421                byte[] buff = device.getGeneralBytes();
1422                if (buff == null)
1423                    return null;
1424                return buff;
1425            }
1426            return null;
1427        }
1428
1429        @Override
1430        public int getMode(int nativeHandle) throws RemoteException {
1431            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1432
1433            NfcDepEndpoint device;
1434
1435            // Check if NFC is enabled
1436            if (!mIsNfcEnabled) {
1437                return ErrorCodes.ERROR_NOT_INITIALIZED;
1438            }
1439
1440            /* find the device in the hmap */
1441            device = (NfcDepEndpoint) findObject(nativeHandle);
1442            if (device != null) {
1443                return device.getMode();
1444            }
1445            return ErrorCodes.ERROR_INVALID_PARAM;
1446        }
1447
1448        @Override
1449        public byte[] receive(int nativeHandle) throws RemoteException {
1450            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1451
1452            NfcDepEndpoint device;
1453
1454            // Check if NFC is enabled
1455            if (!mIsNfcEnabled) {
1456                return null;
1457            }
1458
1459            /* find the device in the hmap */
1460            device = (NfcDepEndpoint) findObject(nativeHandle);
1461            if (device != null) {
1462                byte[] buff = device.receive();
1463                if (buff == null) {
1464                    return null;
1465                }
1466                return buff;
1467            }
1468            /* Restart polling loop for notification */
1469            applyRouting();
1470            return null;
1471        }
1472
1473        @Override
1474        public boolean send(int nativeHandle, byte[] data) throws RemoteException {
1475            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1476
1477            NfcDepEndpoint device;
1478            boolean isSuccess = false;
1479
1480            // Check if NFC is enabled
1481            if (!mIsNfcEnabled) {
1482                return isSuccess;
1483            }
1484
1485            /* find the device in the hmap */
1486            device = (NfcDepEndpoint) findObject(nativeHandle);
1487            if (device != null) {
1488                isSuccess = device.send(data);
1489            }
1490            return isSuccess;
1491        }
1492    };
1493
1494    private final IP2pTarget mP2pTargetService = new IP2pTarget.Stub() {
1495
1496        @Override
1497        public int connect(int nativeHandle) throws RemoteException {
1498            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1499
1500            NfcDepEndpoint device;
1501
1502            // Check if NFC is enabled
1503            if (!mIsNfcEnabled) {
1504                return ErrorCodes.ERROR_NOT_INITIALIZED;
1505            }
1506
1507            /* find the device in the hmap */
1508            device = (NfcDepEndpoint) findObject(nativeHandle);
1509            if (device != null) {
1510                if (device.connect()) {
1511                    return ErrorCodes.SUCCESS;
1512                }
1513            }
1514            return ErrorCodes.ERROR_CONNECT;
1515        }
1516
1517        @Override
1518        public boolean disconnect(int nativeHandle) throws RemoteException {
1519            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1520
1521            NfcDepEndpoint device;
1522            boolean isSuccess = false;
1523
1524            // Check if NFC is enabled
1525            if (!mIsNfcEnabled) {
1526                return isSuccess;
1527            }
1528
1529            /* find the device in the hmap */
1530            device = (NfcDepEndpoint) findObject(nativeHandle);
1531            if (device != null) {
1532                if (isSuccess = device.disconnect()) {
1533                    /* remove the device from the hmap */
1534                    unregisterObject(nativeHandle);
1535                    /* Restart polling loop for notification */
1536                    applyRouting();
1537                }
1538            }
1539            return isSuccess;
1540
1541        }
1542
1543        @Override
1544        public byte[] getGeneralBytes(int nativeHandle) throws RemoteException {
1545            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1546
1547            NfcDepEndpoint device;
1548
1549            // Check if NFC is enabled
1550            if (!mIsNfcEnabled) {
1551                return null;
1552            }
1553
1554            /* find the device in the hmap */
1555            device = (NfcDepEndpoint) findObject(nativeHandle);
1556            if (device != null) {
1557                byte[] buff = device.getGeneralBytes();
1558                if (buff == null)
1559                    return null;
1560                return buff;
1561            }
1562            return null;
1563        }
1564
1565        @Override
1566        public int getMode(int nativeHandle) throws RemoteException {
1567            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1568
1569            NfcDepEndpoint device;
1570
1571            // Check if NFC is enabled
1572            if (!mIsNfcEnabled) {
1573                return ErrorCodes.ERROR_NOT_INITIALIZED;
1574            }
1575
1576            /* find the device in the hmap */
1577            device = (NfcDepEndpoint) findObject(nativeHandle);
1578            if (device != null) {
1579                return device.getMode();
1580            }
1581            return ErrorCodes.ERROR_INVALID_PARAM;
1582        }
1583
1584        @Override
1585        public byte[] transceive(int nativeHandle, byte[] data)
1586                throws RemoteException {
1587            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1588
1589            NfcDepEndpoint device;
1590
1591            // Check if NFC is enabled
1592            if (!mIsNfcEnabled) {
1593                return null;
1594            }
1595
1596            /* find the device in the hmap */
1597            device = (NfcDepEndpoint) findObject(nativeHandle);
1598            if (device != null) {
1599                return device.transceive(data);
1600            }
1601            return null;
1602        }
1603    };
1604
1605    private void _nfcEeClose(boolean checkPid, int callingPid) throws IOException {
1606        // Blocks until a pending open() or transceive() times out.
1607        //TODO: This is incorrect behavior - the close should interrupt pending
1608        // operations. However this is not supported by current hardware.
1609
1610        synchronized(NfcService.this) {
1611            if (!mIsNfcEnabled) {
1612                throw new IOException("NFC adapter is disabled");
1613            }
1614            if (mOpenEe == null) {
1615                throw new IOException("NFC EE closed");
1616            }
1617            if (checkPid && mOpenEe.pid != -1 && callingPid != mOpenEe.pid) {
1618                throw new SecurityException("Wrong PID");
1619            }
1620
1621            mDeviceHost.resetTimeouts();
1622            mSecureElement.doDisconnect(mOpenEe.handle);
1623            mOpenEe = null;
1624
1625            applyRouting();
1626        }
1627    }
1628
1629    private INfcAdapterExtras mExtrasService = new INfcAdapterExtras.Stub() {
1630        private Bundle writeNoException() {
1631            Bundle p = new Bundle();
1632            p.putInt("e", 0);
1633            return p;
1634        }
1635        private Bundle writeIoException(IOException e) {
1636            Bundle p = new Bundle();
1637            p.putInt("e", -1);
1638            p.putString("m", e.getMessage());
1639            return p;
1640        }
1641
1642        @Override
1643        public Bundle open(IBinder b) throws RemoteException {
1644            NfcService.enforceNfceeAdminPerm(mContext);
1645
1646            Bundle result;
1647            try {
1648                _open(b);
1649                result = writeNoException();
1650            } catch (IOException e) {
1651                result = writeIoException(e);
1652            }
1653            return result;
1654        }
1655
1656        private void _open(IBinder b) throws IOException, RemoteException {
1657            synchronized(NfcService.this) {
1658                if (!mIsNfcEnabled) {
1659                    throw new IOException("NFC adapter is disabled");
1660                }
1661                if (mOpenEe != null) {
1662                    throw new IOException("NFC EE already open");
1663                }
1664
1665                int handle = mSecureElement.doOpenSecureElementConnection();
1666                if (handle == 0) {
1667                    throw new IOException("NFC EE failed to open");
1668                }
1669                mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 10000);
1670
1671                mOpenEe = new OpenSecureElement(getCallingPid(), handle);
1672                try {
1673                    b.linkToDeath(mOpenEe, 0);
1674                } catch (RemoteException e) {
1675                    mOpenEe.binderDied();
1676                }
1677
1678                // Add the calling package to the list of packages that have accessed
1679                // the secure element.
1680                for (String packageName : getPackageManager().getPackagesForUid(getCallingUid())) {
1681                    mSePackages.add(packageName);
1682                }
1683           }
1684        }
1685
1686        @Override
1687        public Bundle close() throws RemoteException {
1688            NfcService.enforceNfceeAdminPerm(mContext);
1689
1690            Bundle result;
1691            try {
1692                _nfcEeClose(true, getCallingPid());
1693                result = writeNoException();
1694            } catch (IOException e) {
1695                result = writeIoException(e);
1696            }
1697            return result;
1698        }
1699
1700        @Override
1701        public Bundle transceive(byte[] in) throws RemoteException {
1702            NfcService.enforceNfceeAdminPerm(mContext);
1703
1704            Bundle result;
1705            byte[] out;
1706            try {
1707                out = _transceive(in);
1708                result = writeNoException();
1709                result.putByteArray("out", out);
1710            } catch (IOException e) {
1711                result = writeIoException(e);
1712            }
1713            return result;
1714        }
1715
1716        private byte[] _transceive(byte[] data) throws IOException, RemoteException {
1717            synchronized(NfcService.this) {
1718                if (!mIsNfcEnabled) {
1719                    throw new IOException("NFC is not enabled");
1720                }
1721                if (mOpenEe == null){
1722                    throw new IOException("NFC EE is not open");
1723                }
1724                if (getCallingPid() != mOpenEe.pid) {
1725                    throw new SecurityException("Wrong PID");
1726                }
1727            }
1728
1729            return mSecureElement.doTransceive(mOpenEe.handle, data);
1730        }
1731
1732        @Override
1733        public int getCardEmulationRoute() throws RemoteException {
1734            NfcService.enforceNfceeAdminPerm(mContext);
1735            return mEeRoutingState;
1736        }
1737
1738        @Override
1739        public void setCardEmulationRoute(int route) throws RemoteException {
1740            NfcService.enforceNfceeAdminPerm(mContext);
1741            mEeRoutingState = route;
1742            applyRouting();
1743        }
1744
1745        @Override
1746        public void authenticate(byte[] token) throws RemoteException {
1747            NfcService.enforceNfceeAdminPerm(mContext);
1748        }
1749    };
1750
1751    /** resources kept while secure element is open */
1752    private class OpenSecureElement implements IBinder.DeathRecipient {
1753        public int pid;  // pid that opened SE
1754        public int handle; // low-level handle
1755        public OpenSecureElement(int pid, int handle) {
1756            this.pid = pid;
1757            this.handle = handle;
1758        }
1759        @Override
1760        public void binderDied() {
1761            synchronized (NfcService.this) {
1762                if (DBG) Log.d(TAG, "Tracked app " + pid + " died");
1763                pid = -1;
1764                try {
1765                    _nfcEeClose(false, -1);
1766                } catch (IOException e) { /* already closed */ }
1767            }
1768        }
1769    }
1770
1771    private boolean _enable(boolean oldEnabledState, boolean savePref) {
1772        boolean isSuccess = mDeviceHost.initialize();
1773        if (isSuccess) {
1774            mIsNfcEnabled = true;
1775            mIsDiscoveryOn = true;
1776
1777            /* Start polling loop */
1778            applyRouting();
1779            synchronized(NfcService.this) {
1780                boolean zeroclick_on = mPrefs.getBoolean(PREF_ZEROCLICK_ON,
1781                        ZEROCLICK_ON_DEFAULT);
1782                if (zeroclick_on) {
1783                    /* bring up p2p ndef servers */
1784                    mP2pManager.enableNdefServer();
1785                    mZeroClickOn = true;
1786                }
1787            }
1788        } else {
1789            Log.w(TAG, "Error enabling NFC");
1790            mIsNfcEnabled = false;
1791        }
1792
1793        if (savePref) {
1794            updateNfcOnSetting(oldEnabledState);
1795        }
1796
1797        return isSuccess;
1798    }
1799
1800    private boolean _disable(boolean oldEnabledState, boolean savePref) {
1801        /* sometimes mDeviceHost.deinitialize() hangs, watch-dog it */
1802        WatchDogThread watchDog = new WatchDogThread();
1803        watchDog.start();
1804
1805        boolean isSuccess;
1806
1807        /* tear down the p2p server */
1808        synchronized(NfcService.this) {
1809            if (mZeroClickOn) {
1810                mP2pManager.disableNdefServer();
1811                mZeroClickOn = false;
1812            }
1813        }
1814        // Stop watchdog if tag present
1815        // A convenient way to stop the watchdog properly consists of
1816        // disconnecting the tag. The polling loop shall be stopped before
1817        // to avoid the tag being discovered again.
1818        mIsDiscoveryOn = false;
1819        applyRouting();
1820        maybeDisconnectTarget();
1821
1822        isSuccess = mDeviceHost.deinitialize();
1823        if (DBG) Log.d(TAG, "NFC success of deinitialize = " + isSuccess);
1824        if (isSuccess) {
1825            mIsNfcEnabled = false;
1826            mNfcDispatcher.disableForegroundDispatch();
1827            mP2pManager.setForegroundMessage(null);
1828        }
1829
1830        if (savePref) {
1831            updateNfcOnSetting(oldEnabledState);
1832        }
1833
1834        watchDog.cancel();
1835        return isSuccess;
1836    }
1837
1838    private class WatchDogThread extends Thread {
1839        boolean mWatchDogCanceled = false;
1840        @Override
1841        public void run() {
1842            boolean slept = false;
1843            while (!slept) {
1844                try {
1845                    Thread.sleep(10000);
1846                    slept = true;
1847                } catch (InterruptedException e) { }
1848            }
1849            synchronized (this) {
1850                if (!mWatchDogCanceled) {
1851                    // Trigger watch-dog
1852                    Log.e(TAG, "Watch dog triggered");
1853                    mDeviceHost.doAbort();
1854                }
1855            }
1856        }
1857        public synchronized void cancel() {
1858            mWatchDogCanceled = true;
1859        }
1860    }
1861
1862    /** apply NFC discovery and EE routing */
1863    private synchronized void applyRouting() {
1864        if (mIsNfcEnabled && mOpenEe == null) {
1865            if (mScreenUnlocked) {
1866                if (mEeRoutingState == ROUTE_ON_WHEN_SCREEN_ON) {
1867                    Log.d(TAG, "NFC-EE routing ON");
1868                    mDeviceHost.doSelectSecureElement();
1869                } else {
1870                    Log.d(TAG, "NFC-EE routing OFF");
1871                    mDeviceHost.doDeselectSecureElement();
1872                }
1873                if (mIsDiscoveryOn) {
1874                    Log.d(TAG, "NFC-C discovery ON");
1875                    mDeviceHost.enableDiscovery();
1876                } else {
1877                    Log.d(TAG, "NFC-C discovery OFF");
1878                    mDeviceHost.disableDiscovery();
1879                }
1880            } else {
1881                Log.d(TAG, "NFC-EE routing OFF");
1882                mDeviceHost.doDeselectSecureElement();
1883                Log.d(TAG, "NFC-C discovery OFF");
1884                mDeviceHost.disableDiscovery();
1885            }
1886        }
1887    }
1888
1889    /** Disconnect any target if present */
1890    private synchronized void maybeDisconnectTarget() {
1891        if (mIsNfcEnabled) {
1892            Iterator<?> iterator = mObjectMap.values().iterator();
1893            while(iterator.hasNext()) {
1894                Object object = iterator.next();
1895                if (object instanceof TagEndpoint) {
1896                    // Disconnect from tags
1897                    TagEndpoint tag = (TagEndpoint) object;
1898                    tag.disconnect();
1899                } else if(object instanceof NfcDepEndpoint) {
1900                    // Disconnect from P2P devices
1901                    NfcDepEndpoint device = (NfcDepEndpoint) object;
1902                    if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
1903                        // Remote peer is target, request disconnection
1904                        device.disconnect();
1905                    } else {
1906                        // Remote peer is initiator, we cannot disconnect
1907                        // Just wait for field removal
1908                    }
1909                }
1910                iterator.remove();
1911            }
1912        }
1913    }
1914
1915    //TODO: dont hardcode this
1916    private static final byte[][] SE_RESET_APDUS = {
1917        {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
1918        {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00, (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x20, (byte)0x10, (byte)0x00},
1919        {(byte)0x80, (byte)0xe2, (byte)0x01, (byte)0x03, (byte)0x00},
1920        {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
1921        {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00, (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x30, (byte)0x30, (byte)0x00},
1922        {(byte)0x80, (byte)0xb4, (byte)0x00, (byte)0x00, (byte)0x00},
1923        {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
1924    };
1925
1926    private void resetSeOnFirstBoot() {
1927        if (mPrefs.getBoolean(PREF_FIRST_BOOT, true)) {
1928            Log.i(TAG, "First Boot");
1929            mPrefsEditor.putBoolean(PREF_FIRST_BOOT, false);
1930            mPrefsEditor.apply();
1931            executeSeReset();
1932        }
1933    }
1934
1935    private synchronized void executeSeReset() {
1936        // TODO: read SE reset list from /system/etc
1937        //List<byte[]> apdus = readSeResetApdus();
1938        byte[][]apdus = SE_RESET_APDUS;
1939        if (apdus == null) {
1940            return;
1941        }
1942
1943        boolean tempEnable = !mIsNfcEnabled;
1944        if (tempEnable) {
1945            if (!_enable(false, false)) {
1946                Log.w(TAG, "Could not enable NFC to reset EE!");
1947                return;
1948            }
1949        }
1950
1951        Log.i(TAG, "Executing SE Reset Script");
1952        int handle = mSecureElement.doOpenSecureElementConnection();
1953        if (handle == 0) {
1954            Log.e(TAG, "Could not open the secure element!");
1955            if (tempEnable) {
1956                _disable(true, false);
1957            }
1958            return;
1959        }
1960
1961        mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 10000);
1962
1963        for (byte[] cmd : apdus) {
1964            mSecureElement.doTransceive(handle, cmd);
1965        }
1966
1967        mDeviceHost.resetTimeouts();
1968
1969        mSecureElement.doDisconnect(handle);
1970
1971        if (tempEnable) {
1972            _disable(true, false);
1973        }
1974    }
1975
1976    private List<byte[]> readSeResetApdus() {
1977        FileInputStream input = null;
1978        List<byte[]> apdus = null;
1979
1980        try {
1981            input = openFileInput(SE_RESET_SCRIPT_FILE_NAME);
1982            DataInputStream stream = new DataInputStream(input);
1983
1984            int commandsSize = stream.readInt();
1985            apdus = new ArrayList<byte[]>(commandsSize);
1986
1987            for (int i = 0 ; i < commandsSize ; i++) {
1988                int length = stream.readInt();
1989
1990                byte[] cmd = new byte[length];
1991
1992                stream.read(cmd);
1993                apdus.add(cmd);
1994            }
1995
1996            return apdus;
1997        } catch (FileNotFoundException e) {
1998            Log.e(TAG, "SE Reset Script not found: " + SE_RESET_SCRIPT_FILE_NAME);
1999        } catch (IOException e) {
2000            Log.e(TAG, "SE Reset Script corrupt: ", e);
2001            apdus = null;
2002        } finally {
2003            try {
2004                if (input != null) {
2005                    input.close();
2006                }
2007            } catch (IOException e) {
2008                // Ignore
2009            }
2010        }
2011        return apdus;
2012    }
2013
2014    private void updateNfcOnSetting(boolean oldEnabledState) {
2015        mPrefsEditor.putBoolean(PREF_NFC_ON, mIsNfcEnabled);
2016        mPrefsEditor.apply();
2017
2018        synchronized(this) {
2019            if (oldEnabledState != mIsNfcEnabled) {
2020                Intent intent = new Intent(NfcAdapter.ACTION_ADAPTER_STATE_CHANGE);
2021                intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
2022                intent.putExtra(NfcAdapter.EXTRA_NEW_BOOLEAN_STATE, mIsNfcEnabled);
2023                mContext.sendBroadcast(intent);
2024            }
2025        }
2026    }
2027
2028    // Reset all internals
2029    private synchronized void reset() {
2030        // TODO: none of these appear to be synchronized but are
2031        // read/written from different threads (notably Binder threads)...
2032
2033        // Clear tables
2034        mObjectMap.clear();
2035        mSocketMap.clear();
2036
2037        // Reset variables
2038        mIsNfcEnabled = false;
2039    }
2040
2041    private synchronized Object findObject(int key) {
2042        Object device = null;
2043
2044        device = mObjectMap.get(key);
2045        if (device == null) {
2046            Log.w(TAG, "Handle not found !");
2047        }
2048
2049        return device;
2050    }
2051
2052    synchronized void registerTagObject(TagEndpoint tag) {
2053        mObjectMap.put(tag.getHandle(), tag);
2054    }
2055
2056    synchronized void unregisterObject(int handle) {
2057        mObjectMap.remove(handle);
2058    }
2059
2060    private synchronized Object findSocket(int key) {
2061        if (mSocketMap == null) {
2062            return null;
2063        }
2064        return mSocketMap.get(key);
2065    }
2066
2067    private void removeSocket(int key) {
2068        mSocketMap.remove(key);
2069    }
2070
2071    /** For use by code in this process */
2072    public LlcpSocket createLlcpSocket(int sap, int miu, int rw, int linearBufferLength) {
2073        try {
2074            int handle = mNfcAdapter.createLlcpSocket(sap, miu, rw, linearBufferLength);
2075            if (ErrorCodes.isError(handle)) {
2076                Log.e(TAG, "unable to create socket: " + ErrorCodes.asString(handle));
2077                return null;
2078            }
2079            return new LlcpSocket(mLlcpSocket, handle);
2080        } catch (RemoteException e) {
2081            // This will never happen since the code is calling into it's own process
2082            throw new IllegalStateException("unable to talk to myself", e);
2083        }
2084    }
2085
2086    /** For use by code in this process */
2087    public LlcpServiceSocket createLlcpServiceSocket(int sap, String sn, int miu, int rw,
2088            int linearBufferLength) {
2089        try {
2090            int handle = mNfcAdapter.createLlcpServiceSocket(sap, sn, miu, rw, linearBufferLength);
2091            if (ErrorCodes.isError(handle)) {
2092                Log.e(TAG, "unable to create socket: " + ErrorCodes.asString(handle));
2093                return null;
2094            }
2095            return new LlcpServiceSocket(mLlcpServerSocketService, mLlcpSocket, handle);
2096        } catch (RemoteException e) {
2097            // This will never happen since the code is calling into it's own process
2098            throw new IllegalStateException("unable to talk to myself", e);
2099        }
2100    }
2101
2102    public void sendMockNdefTag(NdefMessage msg) {
2103        sendMessage(MSG_MOCK_NDEF, msg);
2104    }
2105
2106    public void sendMeProfile(NdefMessage target, NdefMessage profile) {
2107        mP2pManager.sendMeProfile(target, profile);
2108    }
2109
2110    void sendMessage(int what, Object obj) {
2111        Message msg = mHandler.obtainMessage();
2112        msg.what = what;
2113        msg.obj = obj;
2114        mHandler.sendMessage(msg);
2115    }
2116
2117    final class NfcServiceHandler extends Handler {
2118        @Override
2119        public void handleMessage(Message msg) {
2120           switch (msg.what) {
2121           case MSG_MOCK_NDEF: {
2122               NdefMessage ndefMsg = (NdefMessage) msg.obj;
2123               Bundle extras = new Bundle();
2124               extras.putParcelable(Ndef.EXTRA_NDEF_MSG, ndefMsg);
2125               extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, 0);
2126               extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, Ndef.NDEF_MODE_READ_ONLY);
2127               extras.putInt(Ndef.EXTRA_NDEF_TYPE, Ndef.TYPE_OTHER);
2128               Tag tag = Tag.createMockTag(new byte[] { 0x00 },
2129                       new int[] { TagTechnology.NDEF },
2130                       new Bundle[] { extras });
2131               Log.d(TAG, "mock NDEF tag, starting corresponding activity");
2132               Log.d(TAG, tag.toString());
2133               boolean delivered = mNfcDispatcher.dispatchTag(tag, new NdefMessage[] { ndefMsg });
2134               if (delivered) {
2135                   playSound(mEndSound);
2136               } else {
2137                   playSound(mErrorSound);
2138               }
2139               break;
2140           }
2141
2142           case MSG_NDEF_TAG:
2143               if (DBG) Log.d(TAG, "Tag detected, notifying applications");
2144               TagEndpoint tag = (TagEndpoint) msg.obj;
2145               playSound(mStartSound);
2146               NdefMessage[] ndefMsgs = tag.findAndReadNdef();
2147
2148               if (ndefMsgs != null) {
2149                   tag.startPresenceChecking();
2150                   dispatchTagEndpoint(tag, ndefMsgs);
2151               } else {
2152                   if (tag.reconnect()) {
2153                       tag.startPresenceChecking();
2154                       dispatchTagEndpoint(tag, null);
2155                   } else {
2156                       tag.disconnect();
2157                   }
2158               }
2159               break;
2160
2161           case MSG_CARD_EMULATION:
2162               if (DBG) Log.d(TAG, "Card Emulation message");
2163               byte[] aid = (byte[]) msg.obj;
2164               /* Send broadcast */
2165               Intent aidIntent = new Intent();
2166               aidIntent.setAction(ACTION_AID_SELECTED);
2167               aidIntent.putExtra(EXTRA_AID, aid);
2168               if (DBG) Log.d(TAG, "Broadcasting " + ACTION_AID_SELECTED);
2169               mContext.sendBroadcast(aidIntent, NFCEE_ADMIN_PERM);
2170               break;
2171
2172           case MSG_SE_EMV_CARD_REMOVAL:
2173               if (DBG) Log.d(TAG, "Card Removal message");
2174               /* Send broadcast */
2175               Intent cardRemovalIntent = new Intent();
2176               cardRemovalIntent.setAction(ACTION_EMV_CARD_REMOVAL);
2177               if (DBG) Log.d(TAG, "Broadcasting " + ACTION_EMV_CARD_REMOVAL);
2178               mContext.sendBroadcast(cardRemovalIntent, NFCEE_ADMIN_PERM);
2179               break;
2180
2181           case MSG_SE_APDU_RECEIVED:
2182               if (DBG) Log.d(TAG, "APDU Received message");
2183               byte[] apduBytes = (byte[]) msg.obj;
2184               /* Send broadcast */
2185               Intent apduReceivedIntent = new Intent();
2186               apduReceivedIntent.setAction(ACTION_APDU_RECEIVED);
2187               if (apduBytes != null && apduBytes.length > 0) {
2188                 apduReceivedIntent.putExtra(EXTRA_APDU_BYTES, apduBytes);
2189               }
2190               if (DBG) Log.d(TAG, "Broadcasting " + ACTION_APDU_RECEIVED);
2191               mContext.sendBroadcast(apduReceivedIntent, NFCEE_ADMIN_PERM);
2192               break;
2193
2194           case MSG_SE_MIFARE_ACCESS:
2195               if (DBG) Log.d(TAG, "MIFARE access message");
2196               /* Send broadcast */
2197               byte[] mifareCmd = (byte[]) msg.obj;
2198               Intent mifareAccessIntent = new Intent();
2199               mifareAccessIntent.setAction(ACTION_MIFARE_ACCESS_DETECTED);
2200               if (mifareCmd != null && mifareCmd.length > 1) {
2201                 int mifareBlock = mifareCmd[1] & 0xff;
2202                 if (DBG) Log.d(TAG, "Mifare Block=" + mifareBlock);
2203                 mifareAccessIntent.putExtra(EXTRA_MIFARE_BLOCK, mifareBlock);
2204               }
2205               if (DBG) Log.d(TAG, "Broadcasting " + ACTION_MIFARE_ACCESS_DETECTED);
2206               mContext.sendBroadcast(mifareAccessIntent, NFCEE_ADMIN_PERM);
2207               break;
2208
2209           case MSG_LLCP_LINK_ACTIVATION:
2210               if (llcpActivated((NfcDepEndpoint) msg.obj)) {
2211                   playSound(mStartSound);
2212               } else {
2213                   playSound(mErrorSound);
2214               }
2215               break;
2216
2217           case MSG_LLCP_LINK_DEACTIVATED:
2218               NfcDepEndpoint device = (NfcDepEndpoint) msg.obj;
2219
2220               Log.d(TAG, "LLCP Link Deactivated message. Restart polling loop.");
2221               synchronized (NfcService.this) {
2222                   /* Check if the device has been already unregistered */
2223                   if (mObjectMap.remove(device.getHandle()) != null) {
2224                       /* Disconnect if we are initiator */
2225                       if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
2226                           if (DBG) Log.d(TAG, "disconnecting from target");
2227                           /* Restart polling loop */
2228                           device.disconnect();
2229                       } else {
2230                           if (DBG) Log.d(TAG, "not disconnecting from initiator");
2231                       }
2232                   }
2233               }
2234
2235               mP2pManager.llcpDeactivated();
2236               break;
2237
2238           case MSG_TARGET_DESELECTED:
2239               /* Broadcast Intent Target Deselected */
2240               if (DBG) Log.d(TAG, "Target Deselected");
2241               Intent intent = new Intent();
2242               intent.setAction(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION);
2243               if (DBG) Log.d(TAG, "Broadcasting Intent");
2244               mContext.sendOrderedBroadcast(intent, NFC_PERM);
2245               break;
2246
2247           case MSG_SE_FIELD_ACTIVATED:{
2248               if (DBG) Log.d(TAG, "SE FIELD ACTIVATED");
2249               Intent eventFieldOnIntent = new Intent();
2250               eventFieldOnIntent.setAction(ACTION_RF_FIELD_ON_DETECTED);
2251               mContext.sendBroadcast(eventFieldOnIntent, NFCEE_ADMIN_PERM);
2252               break;
2253           }
2254
2255           case MSG_SE_FIELD_DEACTIVATED:{
2256               if (DBG) Log.d(TAG, "SE FIELD DEACTIVATED");
2257               Intent eventFieldOffIntent = new Intent();
2258               eventFieldOffIntent.setAction(ACTION_RF_FIELD_OFF_DETECTED);
2259               mContext.sendBroadcast(eventFieldOffIntent, NFCEE_ADMIN_PERM);
2260               break;
2261           }
2262
2263           default:
2264               Log.e(TAG, "Unknown message received");
2265               break;
2266           }
2267        }
2268
2269        private boolean llcpActivated(NfcDepEndpoint device) {
2270            Log.d(TAG, "LLCP Activation message");
2271
2272            if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
2273                if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_TARGET");
2274                if (device.connect()) {
2275                    /* Check LLCP compliancy */
2276                    if (mDeviceHost.doCheckLlcp()) {
2277                        /* Activate LLCP Link */
2278                        if (mDeviceHost.doActivateLlcp()) {
2279                            if (DBG) Log.d(TAG, "Initiator Activate LLCP OK");
2280                            // Register P2P device
2281                            mObjectMap.put(device.getHandle(), device);
2282                            // TODO this should be done decently instead, not depend on the bool
2283                            if (mZeroClickOn) {
2284                                mP2pManager.llcpActivated();
2285                            }
2286                            return true;
2287                        } else {
2288                            /* should not happen */
2289                            Log.w(TAG, "Initiator LLCP activation failed. Disconnect.");
2290                            device.disconnect();
2291                        }
2292                    } else {
2293                        if (DBG) Log.d(TAG, "Remote Target does not support LLCP. Disconnect.");
2294                        device.disconnect();
2295                    }
2296                } else {
2297                    if (DBG) Log.d(TAG, "Cannot connect remote Target. Polling loop restarted.");
2298                    /*
2299                     * The polling loop should have been restarted in failing
2300                     * doConnect
2301                     */
2302                }
2303            } else if (device.getMode() == NfcDepEndpoint.MODE_P2P_INITIATOR) {
2304                if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_INITIATOR");
2305                /* Check LLCP compliancy */
2306                if (mDeviceHost.doCheckLlcp()) {
2307                    /* Activate LLCP Link */
2308                    if (mDeviceHost.doActivateLlcp()) {
2309                        if (DBG) Log.d(TAG, "Target Activate LLCP OK");
2310                        // Register P2P device
2311                        mObjectMap.put(device.getHandle(), device);
2312                        // TODO this should be done decently instead, not depend on the bool
2313                        if (mZeroClickOn) {
2314                            mP2pManager.llcpActivated();
2315                        }
2316                        return true;
2317                    }
2318                } else {
2319                    Log.w(TAG, "checkLlcp failed");
2320                }
2321            }
2322
2323            return false;
2324        }
2325
2326        private void dispatchTagEndpoint(TagEndpoint tagEndpoint, NdefMessage[] msgs) {
2327            Tag tag = new Tag(tagEndpoint.getUid(), tagEndpoint.getTechList(),
2328                    tagEndpoint.getTechExtras(), tagEndpoint.getHandle(), mNfcTagService);
2329            registerTagObject(tagEndpoint);
2330            if (!mNfcDispatcher.dispatchTag(tag, msgs)) {
2331                unregisterObject(tagEndpoint.getHandle());
2332                playSound(mErrorSound);
2333            } else {
2334                playSound(mEndSound);
2335            }
2336        }
2337    }
2338
2339    private NfcServiceHandler mHandler = new NfcServiceHandler();
2340
2341    private class EnableDisableDiscoveryTask extends AsyncTask<Boolean, Void, Void> {
2342        @Override
2343        protected Void doInBackground(Boolean... params) {
2344            if (DBG) Log.d(TAG, "EnableDisableDiscoveryTask: enable = " + params[0]);
2345
2346            if (params != null && params.length > 0 && params[0]) {
2347                synchronized (NfcService.this) {
2348                    if (!mScreenUnlocked) {
2349                        mScreenUnlocked = true;
2350                        applyRouting();
2351                    } else {
2352                        if (DBG) Log.d(TAG, "Ignoring enable request");
2353                    }
2354                }
2355            } else {
2356                mWakeLock.acquire();
2357                synchronized (NfcService.this) {
2358                    if (mScreenUnlocked) {
2359                        mScreenUnlocked = false;
2360                        applyRouting();
2361                        maybeDisconnectTarget();
2362                    } else {
2363                        if (DBG) Log.d(TAG, "Ignoring disable request");
2364                    }
2365                }
2366                mWakeLock.release();
2367            }
2368            return null;
2369        }
2370    }
2371
2372    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
2373        @Override
2374        public void onReceive(Context context, Intent intent) {
2375            if (intent.getAction().equals(
2376                    NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION)) {
2377                if (DBG) Log.d(TAG, "INERNAL_TARGET_DESELECTED_ACTION");
2378
2379                /* Restart polling loop for notification */
2380                applyRouting();
2381
2382            } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
2383                // Only enable if the screen is unlocked. If the screen is locked
2384                // Intent.ACTION_USER_PRESENT will be broadcast when the screen is
2385                // unlocked.
2386                boolean enable = !mKeyguard.isKeyguardSecure() || !mKeyguard.isKeyguardLocked();
2387
2388                // Perform discovery enable in thread to protect against ANR when the
2389                // NFC stack wedges. This is *not* the correct way to fix this issue -
2390                // configuration of the local NFC adapter should be very quick and should
2391                // be safe on the main thread, and the NFC stack should not wedge.
2392                new EnableDisableDiscoveryTask().execute(enable);
2393            } else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
2394                // Perform discovery disable in thread to protect against ANR when the
2395                // NFC stack wedges. This is *not* the correct way to fix this issue -
2396                // configuration of the local NFC adapter should be very quick and should
2397                // be safe on the main thread, and the NFC stack should not wedge.
2398                new EnableDisableDiscoveryTask().execute(Boolean.FALSE);
2399            } else if (intent.getAction().equals(Intent.ACTION_USER_PRESENT)) {
2400                // The user has unlocked the screen. Enabled!
2401                new EnableDisableDiscoveryTask().execute(Boolean.TRUE);
2402            } else if (intent.getAction().equals(ACTION_MASTER_CLEAR_NOTIFICATION)) {
2403                executeSeReset();
2404            } else if (intent.getAction().equals(Intent.ACTION_PACKAGE_REMOVED)) {
2405                boolean dataRemoved = intent.getBooleanExtra(Intent.EXTRA_DATA_REMOVED, false);
2406                if (dataRemoved) {
2407                    Uri data = intent.getData();
2408                    if (data == null) return;
2409                    String packageName = data.getSchemeSpecificPart();
2410
2411                    synchronized (NfcService.this) {
2412                        if (mSePackages.contains(packageName)) {
2413                            executeSeReset();
2414                            mSePackages.remove(packageName);
2415                        }
2416                    }
2417                }
2418            }
2419        }
2420    };
2421}
2422