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