NfcService.java revision e008eba3b51c5303d52bf3e9e989dfd03b18435a
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.nfc.DeviceHost.DeviceHostListener;
20import com.android.nfc.DeviceHost.LlcpConnectionlessSocket;
21import com.android.nfc.DeviceHost.LlcpServerSocket;
22import com.android.nfc.DeviceHost.LlcpSocket;
23import com.android.nfc.DeviceHost.NfcDepEndpoint;
24import com.android.nfc.DeviceHost.TagEndpoint;
25import com.android.nfc.nxp.NativeNfcManager;
26import com.android.nfc.nxp.NativeNfcSecureElement;
27
28import android.app.Application;
29import android.app.KeyguardManager;
30import android.app.PendingIntent;
31import android.content.BroadcastReceiver;
32import android.content.ContentResolver;
33import android.content.Context;
34import android.content.Intent;
35import android.content.IntentFilter;
36import android.content.SharedPreferences;
37import android.content.pm.PackageInfo;
38import android.content.pm.PackageManager;
39import android.media.AudioManager;
40import android.media.SoundPool;
41import android.net.Uri;
42import android.nfc.ErrorCodes;
43import android.nfc.FormatException;
44import android.nfc.INdefPushCallback;
45import android.nfc.INfcAdapter;
46import android.nfc.INfcAdapterExtras;
47import android.nfc.INfcTag;
48import android.nfc.NdefMessage;
49import android.nfc.NfcAdapter;
50import android.nfc.Tag;
51import android.nfc.TechListParcel;
52import android.nfc.TransceiveResult;
53import android.nfc.tech.Ndef;
54import android.nfc.tech.TagTechnology;
55import android.os.AsyncTask;
56import android.os.Binder;
57import android.os.Bundle;
58import android.os.Handler;
59import android.os.IBinder;
60import android.os.Message;
61import android.os.PowerManager;
62import android.os.Process;
63import android.os.RemoteException;
64import android.os.ServiceManager;
65import android.provider.Settings;
66import android.util.Log;
67
68import java.io.FileDescriptor;
69import java.io.IOException;
70import java.io.PrintWriter;
71import java.util.Arrays;
72import java.util.HashMap;
73import java.util.HashSet;
74import java.util.List;
75import java.util.concurrent.ExecutionException;
76
77public class NfcService extends Application implements DeviceHostListener {
78    private static final String ACTION_MASTER_CLEAR_NOTIFICATION = "android.intent.action.MASTER_CLEAR_NOTIFICATION";
79
80    static final boolean DBG = false;
81    static final String TAG = "NfcService";
82
83    public static final String SERVICE_NAME = "nfc";
84
85    /** Regular NFC permission */
86    private static final String NFC_PERM = android.Manifest.permission.NFC;
87    private static final String NFC_PERM_ERROR = "NFC permission required";
88
89    /** NFC ADMIN permission - only for system apps */
90    private static final String ADMIN_PERM = android.Manifest.permission.WRITE_SECURE_SETTINGS;
91    private static final String ADMIN_PERM_ERROR = "WRITE_SECURE_SETTINGS permission required";
92
93    public static final String PREF = "NfcServicePrefs";
94
95    static final String PREF_NFC_ON = "nfc_on";
96    static final boolean NFC_ON_DEFAULT = true;
97    static final String PREF_NDEF_PUSH_ON = "ndef_push_on";
98    static final boolean NDEF_PUSH_ON_DEFAULT = true;
99    static final String PREF_FIRST_BEAM = "first_beam";
100    static final String PREF_FIRST_BOOT = "first_boot";
101
102    static final boolean PN544_QUIRK_DISCONNECT_BEFORE_RECONFIGURE = true;
103
104    static final int MSG_NDEF_TAG = 0;
105    static final int MSG_CARD_EMULATION = 1;
106    static final int MSG_LLCP_LINK_ACTIVATION = 2;
107    static final int MSG_LLCP_LINK_DEACTIVATED = 3;
108    static final int MSG_TARGET_DESELECTED = 4;
109    static final int MSG_MOCK_NDEF = 7;
110    static final int MSG_SE_FIELD_ACTIVATED = 8;
111    static final int MSG_SE_FIELD_DEACTIVATED = 9;
112    static final int MSG_SE_APDU_RECEIVED = 10;
113    static final int MSG_SE_EMV_CARD_REMOVAL = 11;
114    static final int MSG_SE_MIFARE_ACCESS = 12;
115
116    static final int TASK_ENABLE = 1;
117    static final int TASK_DISABLE = 2;
118    static final int TASK_BOOT = 3;
119    static final int TASK_EE_WIPE = 4;
120
121    // Screen state, used by mScreenState
122    static final int SCREEN_STATE_UNKNOWN = 0;
123    static final int SCREEN_STATE_OFF = 1;
124    static final int SCREEN_STATE_ON_LOCKED = 2;
125    static final int SCREEN_STATE_ON_UNLOCKED = 3;
126
127    // Copied from com.android.nfc_extras to avoid library dependency
128    // Must keep in sync with com.android.nfc_extras
129    static final int ROUTE_OFF = 1;
130    static final int ROUTE_ON_WHEN_SCREEN_ON = 2;
131
132    /** minimum screen state that enables NFC polling (discovery) */
133    static final int POLLING_MODE = SCREEN_STATE_ON_UNLOCKED;
134
135    // for use with playSound()
136    public static final int SOUND_START = 0;
137    public static final int SOUND_END = 1;
138    public static final int SOUND_ERROR = 2;
139
140    public static final String ACTION_RF_FIELD_ON_DETECTED =
141        "com.android.nfc_extras.action.RF_FIELD_ON_DETECTED";
142    public static final String ACTION_RF_FIELD_OFF_DETECTED =
143        "com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED";
144    public static final String ACTION_AID_SELECTED =
145        "com.android.nfc_extras.action.AID_SELECTED";
146    public static final String EXTRA_AID = "com.android.nfc_extras.extra.AID";
147
148    public static final String ACTION_APDU_RECEIVED =
149        "com.android.nfc_extras.action.APDU_RECEIVED";
150    public static final String EXTRA_APDU_BYTES =
151        "com.android.nfc_extras.extra.APDU_BYTES";
152
153    public static final String ACTION_EMV_CARD_REMOVAL =
154        "com.android.nfc_extras.action.EMV_CARD_REMOVAL";
155
156    public static final String ACTION_MIFARE_ACCESS_DETECTED =
157        "com.android.nfc_extras.action.MIFARE_ACCESS_DETECTED";
158    public static final String EXTRA_MIFARE_BLOCK =
159        "com.android.nfc_extras.extra.MIFARE_BLOCK";
160
161    //TODO: dont hardcode this
162    private static final byte[][] EE_WIPE_APDUS = {
163        {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
164        {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00,
165                (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x20, (byte)0x10, (byte)0x00},
166        {(byte)0x80, (byte)0xe2, (byte)0x01, (byte)0x03, (byte)0x00},
167        {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
168        {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x07, (byte)0xa0, (byte)0x00,
169                (byte)0x00, (byte)0x04, (byte)0x76, (byte)0x30, (byte)0x30, (byte)0x00},
170        {(byte)0x80, (byte)0xb4, (byte)0x00, (byte)0x00, (byte)0x00},
171        {(byte)0x00, (byte)0xa4, (byte)0x04, (byte)0x00, (byte)0x00},
172    };
173
174    // NFC Execution Environment
175    // fields below are protected by this
176    private NativeNfcSecureElement mSecureElement;
177    private OpenSecureElement mOpenEe;  // null when EE closed
178    private int mEeRoutingState;  // contactless interface routing
179
180    // fields below must be used only on the UI thread and therefore aren't synchronized
181    boolean mP2pStarted = false;
182
183    // fields below are used in multiple threads and protected by synchronized(this)
184    final HashMap<Integer, Object> mObjectMap = new HashMap<Integer, Object>();
185    HashSet<String> mSePackages = new HashSet<String>();
186    int mScreenState;
187    boolean mIsNdefPushEnabled;
188    boolean mNfceeRouteEnabled;  // current Device Host state of NFC-EE routing
189    boolean mNfcPollingEnabled;  // current Device Host state of NFC-C polling
190
191    // mState is protected by this, however it is only modified in onCreate()
192    // and the default AsyncTask thread so it is read unprotected from that
193    // thread
194    int mState;  // one of NfcAdapter.STATE_ON, STATE_TURNING_ON, etc
195
196    // fields below are final after onCreate()
197    Context mContext;
198    private DeviceHost mDeviceHost;
199    private SharedPreferences mPrefs;
200    private SharedPreferences.Editor mPrefsEditor;
201    private PowerManager.WakeLock mWakeLock;
202    int mStartSound;
203    int mEndSound;
204    int mErrorSound;
205    SoundPool mSoundPool; // playback synchronized on this
206    P2pLinkManager mP2pLinkManager;
207    TagService mNfcTagService;
208    NfcAdapterService mNfcAdapter;
209    NfcAdapterExtrasService mExtrasService;
210    boolean mIsAirplaneSensitive;
211    boolean mIsAirplaneToggleable;
212    NfceeAccessControl mNfceeAccessControl;
213
214    private NfcDispatcher mNfcDispatcher;
215    private PowerManager mPowerManager;
216    private KeyguardManager mKeyguard;
217
218    private static NfcService sService;
219
220    public static void enforceAdminPerm(Context context) {
221        context.enforceCallingOrSelfPermission(ADMIN_PERM, ADMIN_PERM_ERROR);
222    }
223
224    public void enforceNfceeAdminPerm(String pkg) {
225        if (pkg == null) {
226            throw new SecurityException("caller must pass a package name");
227        }
228        mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
229        if (!mNfceeAccessControl.check(Binder.getCallingUid(), pkg)) {
230            throw new SecurityException(NfceeAccessControl.NFCEE_ACCESS_PATH +
231                    " denies NFCEE access to " + pkg);
232        }
233    }
234
235    public static NfcService getInstance() {
236        return sService;
237    }
238
239    @Override
240    public void onRemoteEndpointDiscovered(TagEndpoint tag) {
241        sendMessage(NfcService.MSG_NDEF_TAG, tag);
242    }
243
244    /**
245     * Notifies transaction
246     */
247    @Override
248    public void onCardEmulationDeselected() {
249        sendMessage(NfcService.MSG_TARGET_DESELECTED, null);
250    }
251
252    /**
253     * Notifies transaction
254     */
255    @Override
256    public void onCardEmulationAidSelected(byte[] aid) {
257        sendMessage(NfcService.MSG_CARD_EMULATION, aid);
258    }
259
260    /**
261     * Notifies P2P Device detected, to activate LLCP link
262     */
263    @Override
264    public void onLlcpLinkActivated(NfcDepEndpoint device) {
265        sendMessage(NfcService.MSG_LLCP_LINK_ACTIVATION, device);
266    }
267
268    /**
269     * Notifies P2P Device detected, to activate LLCP link
270     */
271    @Override
272    public void onLlcpLinkDeactivated(NfcDepEndpoint device) {
273        sendMessage(NfcService.MSG_LLCP_LINK_DEACTIVATED, device);
274    }
275
276    @Override
277    public void onRemoteFieldActivated() {
278        sendMessage(NfcService.MSG_SE_FIELD_ACTIVATED, null);
279    }
280
281    @Override
282    public void onRemoteFieldDeactivated() {
283        sendMessage(NfcService.MSG_SE_FIELD_DEACTIVATED, null);
284    }
285
286    @Override
287    public void onSeApduReceived(byte[] apdu) {
288        sendMessage(NfcService.MSG_SE_APDU_RECEIVED, apdu);
289    }
290
291    @Override
292    public void onSeEmvCardRemoval() {
293        sendMessage(NfcService.MSG_SE_EMV_CARD_REMOVAL, null);
294    }
295
296    @Override
297    public void onSeMifareAccess(byte[] block) {
298        sendMessage(NfcService.MSG_SE_MIFARE_ACCESS, block);
299    }
300
301    @Override
302    public void onCreate() {
303        super.onCreate();
304
305        mNfcTagService = new TagService();
306        mNfcAdapter = new NfcAdapterService();
307        mExtrasService = new NfcAdapterExtrasService();
308
309        Log.i(TAG, "Starting NFC service");
310
311        sService = this;
312
313        mContext = this;
314        mDeviceHost = new NativeNfcManager(this, this);
315
316        mP2pLinkManager = new P2pLinkManager(mContext);
317        mNfcDispatcher = new NfcDispatcher(this, mP2pLinkManager);
318
319        mSecureElement = new NativeNfcSecureElement();
320        mEeRoutingState = ROUTE_OFF;
321
322        mNfceeAccessControl = new NfceeAccessControl(this);
323
324        mPrefs = getSharedPreferences(PREF, Context.MODE_PRIVATE);
325        mPrefsEditor = mPrefs.edit();
326
327        mState = NfcAdapter.STATE_OFF;
328        mIsNdefPushEnabled = mPrefs.getBoolean(PREF_NDEF_PUSH_ON, NDEF_PUSH_ON_DEFAULT);
329
330        mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
331
332        mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "NfcService");
333        mKeyguard = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
334        mScreenState = checkScreenState();
335
336        ServiceManager.addService(SERVICE_NAME, mNfcAdapter);
337
338        IntentFilter filter = new IntentFilter(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION);
339        filter.addAction(Intent.ACTION_SCREEN_OFF);
340        filter.addAction(Intent.ACTION_SCREEN_ON);
341        filter.addAction(ACTION_MASTER_CLEAR_NOTIFICATION);
342        filter.addAction(Intent.ACTION_USER_PRESENT);
343        registerForAirplaneMode(filter);
344        registerReceiver(mReceiver, filter);
345
346        filter = new IntentFilter();
347        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
348        filter.addDataScheme("package");
349
350        registerReceiver(mReceiver, filter);
351
352        new EnableDisableTask().execute(TASK_BOOT);  // do blocking boot tasks
353    }
354
355    void initSoundPool() {
356        synchronized(this) {
357            if (mSoundPool == null) {
358                mSoundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0);
359                mStartSound = mSoundPool.load(this, R.raw.start, 1);
360                mEndSound = mSoundPool.load(this, R.raw.end, 1);
361                mErrorSound = mSoundPool.load(this, R.raw.error, 1);
362            }
363        }
364    }
365
366    void releaseSoundPool() {
367        synchronized(this) {
368            if (mSoundPool != null) {
369                mSoundPool.release();
370                mSoundPool = null;
371            }
372        }
373    }
374
375    void registerForAirplaneMode(IntentFilter filter) {
376        final ContentResolver resolver = mContext.getContentResolver();
377        final String airplaneModeRadios = Settings.System.getString(resolver,
378                Settings.System.AIRPLANE_MODE_RADIOS);
379        final String toggleableRadios = Settings.System.getString(resolver,
380                Settings.System.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
381
382        mIsAirplaneSensitive = airplaneModeRadios == null ? true :
383                airplaneModeRadios.contains(Settings.System.RADIO_NFC);
384        mIsAirplaneToggleable = toggleableRadios == null ? false :
385            toggleableRadios.contains(Settings.System.RADIO_NFC);
386
387        if (mIsAirplaneSensitive) {
388            filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
389        }
390    }
391
392    int checkScreenState() {
393        if (!mPowerManager.isScreenOn()) {
394            return SCREEN_STATE_OFF;
395        } else if (mKeyguard.isKeyguardLocked()) {
396            return SCREEN_STATE_ON_LOCKED;
397        } else {
398            return SCREEN_STATE_ON_UNLOCKED;
399        }
400    }
401
402    /**
403     * Manages tasks that involve turning on/off the NFC controller.
404     *
405     * <p>All work that might turn the NFC adapter on or off must be done
406     * through this task, to keep the handling of mState simple.
407     * In other words, mState is only modified in these tasks (and we
408     * don't need a lock to read it in these tasks).
409     *
410     * <p>These tasks are all done on the same AsyncTask background
411     * thread, so they are serialized. Each task may temporarily transition
412     * mState to STATE_TURNING_OFF or STATE_TURNING_ON, but must exit in
413     * either STATE_ON or STATE_OFF. This way each task can be guaranteed
414     * of starting in either STATE_OFF or STATE_ON, without needing to hold
415     * NfcService.this for the entire task.
416     *
417     * <p>AsyncTask's are also implicitly queued. This is useful for corner
418     * cases like turning airplane mode on while TASK_ENABLE is in progress.
419     * The TASK_DISABLE triggered by airplane mode will be correctly executed
420     * immediately after TASK_ENABLE is complete. This seems like the most sane
421     * way to deal with these situations.
422     *
423     * <p>{@link #TASK_ENABLE} enables the NFC adapter, without changing
424     * preferences
425     * <p>{@link #TASK_DISABLE} disables the NFC adapter, without changing
426     * preferences
427     * <p>{@link #TASK_BOOT} does first boot work and may enable NFC
428     * <p>{@link #TASK_EE_WIPE} wipes the Execution Environment, and in the
429     * process may temporarily enable the NFC adapter
430     */
431    class EnableDisableTask extends AsyncTask<Integer, Void, Void> {
432        @Override
433        protected Void doInBackground(Integer... params) {
434            // Sanity check mState
435            switch (mState) {
436                case NfcAdapter.STATE_TURNING_OFF:
437                case NfcAdapter.STATE_TURNING_ON:
438                    Log.e(TAG, "Processing EnableDisable task " + params[0] + " from bad state " +
439                            mState);
440                    return null;
441            }
442
443            /* AsyncTask sets this thread to THREAD_PRIORITY_BACKGROUND,
444             * override with the default. THREAD_PRIORITY_BACKGROUND causes
445             * us to service software I2C too slow for firmware download
446             * with the NXP PN544.
447             * TODO: move this to the DAL I2C layer in libnfc-nxp, since this
448             * problem only occurs on I2C platforms using PN544
449             */
450            Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
451
452            switch (params[0].intValue()) {
453                case TASK_ENABLE:
454                    enableInternal();
455                    break;
456                case TASK_DISABLE:
457                    disableInternal();
458                    break;
459                case TASK_BOOT:
460                    Log.d(TAG,"checking on firmware download");
461                    if (mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT) &&
462                            !(mIsAirplaneSensitive && isAirplaneModeOn())) {
463                        Log.d(TAG,"NFC is on. Doing normal stuff");
464                        enableInternal();
465                    } else {
466                        Log.d(TAG,"NFC is off.  Checking firmware version");
467                        mDeviceHost.checkFirmware();
468                    }
469                    if (mPrefs.getBoolean(PREF_FIRST_BOOT, true)) {
470                        Log.i(TAG, "First Boot");
471                        mPrefsEditor.putBoolean(PREF_FIRST_BOOT, false);
472                        mPrefsEditor.apply();
473                        executeEeWipe();
474                    }
475                    break;
476                case TASK_EE_WIPE:
477                    executeEeWipe();
478                    break;
479            }
480
481            // Restore default AsyncTask priority
482            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
483            return null;
484        }
485
486        /**
487         * Enable NFC adapter functions.
488         * Does not toggle preferences.
489         */
490        boolean enableInternal() {
491            if (mState == NfcAdapter.STATE_ON) {
492                return true;
493            }
494            Log.i(TAG, "Enabling NFC");
495            updateState(NfcAdapter.STATE_TURNING_ON);
496
497            if (!mDeviceHost.initialize()) {
498                Log.w(TAG, "Error enabling NFC");
499                updateState(NfcAdapter.STATE_OFF);
500                return false;
501            }
502
503            synchronized(NfcService.this) {
504                mObjectMap.clear();
505
506                mP2pLinkManager.enableDisable(mIsNdefPushEnabled, true);
507                updateState(NfcAdapter.STATE_ON);
508            }
509
510            initSoundPool();
511
512            /* Start polling loop */
513            applyRouting(true);
514            return true;
515        }
516
517        /**
518         * Disable all NFC adapter functions.
519         * Does not toggle preferences.
520         */
521        boolean disableInternal() {
522            if (mState == NfcAdapter.STATE_OFF) {
523                return true;
524            }
525            Log.i(TAG, "Disabling NFC");
526            updateState(NfcAdapter.STATE_TURNING_OFF);
527
528            /* Sometimes mDeviceHost.deinitialize() hangs, use a watch-dog.
529             * Implemented with a new thread (instead of a Handler or AsyncTask),
530             * because the UI Thread and AsyncTask thread-pools can also get hung
531             * when the NFC controller stops responding */
532            WatchDogThread watchDog = new WatchDogThread();
533            watchDog.start();
534
535            mP2pLinkManager.enableDisable(false, false);
536
537            // Stop watchdog if tag present
538            // A convenient way to stop the watchdog properly consists of
539            // disconnecting the tag. The polling loop shall be stopped before
540            // to avoid the tag being discovered again.
541            applyRouting(true);
542            maybeDisconnectTarget();
543
544            mNfcDispatcher.setForegroundDispatch(null, null, null);
545
546            boolean result = mDeviceHost.deinitialize();
547            if (DBG) Log.d(TAG, "mDeviceHost.deinitialize() = " + result);
548
549            watchDog.cancel();
550
551            updateState(NfcAdapter.STATE_OFF);
552
553            releaseSoundPool();
554
555            return result;
556        }
557
558        void executeEeWipe() {
559            // TODO: read SE reset list from /system/etc
560            byte[][]apdus = EE_WIPE_APDUS;
561
562            boolean tempEnable = mState == NfcAdapter.STATE_OFF;
563            if (tempEnable) {
564                if (!enableInternal()) {
565                    Log.w(TAG, "Could not enable NFC to wipe NFC-EE");
566                    return;
567                }
568            }
569            Log.i(TAG, "Executing SE wipe");
570            int handle = mSecureElement.doOpenSecureElementConnection();
571            if (handle == 0) {
572                Log.w(TAG, "Could not open the secure element");
573                if (tempEnable) {
574                    disableInternal();
575                }
576                return;
577            }
578
579            mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 10000);
580
581            for (byte[] cmd : apdus) {
582                byte[] resp = mSecureElement.doTransceive(handle, cmd);
583                if (resp == null) {
584                    Log.w(TAG, "Transceive failed, could not wipe NFC-EE");
585                    break;
586                }
587            }
588
589            mDeviceHost.resetTimeouts();
590            mSecureElement.doDisconnect(handle);
591
592            if (tempEnable) {
593                disableInternal();
594            }
595        }
596
597        void updateState(int newState) {
598            synchronized (NfcService.this) {
599                if (newState == mState) {
600                    return;
601                }
602                mState = newState;
603                Intent intent = new Intent(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
604                intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
605                intent.putExtra(NfcAdapter.EXTRA_ADAPTER_STATE, mState);
606                mContext.sendBroadcast(intent);
607            }
608        }
609    }
610
611    void saveNfcOnSetting(boolean on) {
612        synchronized (NfcService.this) {
613            mPrefsEditor.putBoolean(PREF_NFC_ON, on);
614            mPrefsEditor.apply();
615        }
616    }
617
618    public void playSound(int sound) {
619        synchronized (this) {
620            if (mSoundPool == null) {
621                Log.w(TAG, "Not playing sound when NFC is disabled");
622                return;
623            }
624            switch (sound) {
625                case SOUND_START:
626                    mSoundPool.play(mStartSound, 1.0f, 1.0f, 0, 0, 1.0f);
627                    break;
628                case SOUND_END:
629                    mSoundPool.play(mEndSound, 1.0f, 1.0f, 0, 0, 1.0f);
630                    break;
631                case SOUND_ERROR:
632                    mSoundPool.play(mErrorSound, 1.0f, 1.0f, 0, 0, 1.0f);
633                    break;
634            }
635        }
636    }
637
638    @Override
639    public void onTerminate() {
640        super.onTerminate();
641        // NFC application is persistent, it should not be destroyed by framework
642        Log.wtf(TAG, "NFC service is under attack!");
643    }
644
645    final class NfcAdapterService extends INfcAdapter.Stub {
646        @Override
647        public boolean enable() throws RemoteException {
648            NfcService.enforceAdminPerm(mContext);
649
650            saveNfcOnSetting(true);
651            if (mIsAirplaneSensitive && isAirplaneModeOn() && !mIsAirplaneToggleable) {
652                Log.i(TAG, "denying enable() request (airplane mode)");
653                return false;
654            }
655            new EnableDisableTask().execute(TASK_ENABLE);
656
657            return true;
658        }
659
660        @Override
661        public boolean disable() throws RemoteException {
662            NfcService.enforceAdminPerm(mContext);
663
664            saveNfcOnSetting(false);
665            new EnableDisableTask().execute(TASK_DISABLE);
666
667            return true;
668        }
669
670        @Override
671        public boolean isNdefPushEnabled() throws RemoteException {
672            synchronized (NfcService.this) {
673                return mState == NfcAdapter.STATE_ON && mIsNdefPushEnabled;
674            }
675        }
676
677        @Override
678        public boolean enableNdefPush() throws RemoteException {
679            NfcService.enforceAdminPerm(mContext);
680            synchronized(NfcService.this) {
681                if (mIsNdefPushEnabled) {
682                    return true;
683                }
684                Log.i(TAG, "enabling NDEF Push");
685                mPrefsEditor.putBoolean(PREF_NDEF_PUSH_ON, true);
686                mPrefsEditor.apply();
687                mIsNdefPushEnabled = true;
688                if (isNfcEnabled()) {
689                    mP2pLinkManager.enableDisable(true, true);
690                }
691            }
692            return true;
693        }
694
695        @Override
696        public boolean disableNdefPush() throws RemoteException {
697            NfcService.enforceAdminPerm(mContext);
698            synchronized(NfcService.this) {
699                if (!mIsNdefPushEnabled) {
700                    return true;
701                }
702                Log.i(TAG, "disabling NDEF Push");
703                mPrefsEditor.putBoolean(PREF_NDEF_PUSH_ON, false);
704                mPrefsEditor.apply();
705                mIsNdefPushEnabled = false;
706                if (isNfcEnabled()) {
707                    mP2pLinkManager.enableDisable(false, true);
708                }
709            }
710            return true;
711        }
712
713        @Override
714        public void setForegroundDispatch(PendingIntent intent,
715                IntentFilter[] filters, TechListParcel techListsParcel) {
716            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
717
718            // Short-cut the disable path
719            if (intent == null && filters == null && techListsParcel == null) {
720                mNfcDispatcher.setForegroundDispatch(null, null, null);
721                return;
722            }
723
724            // Validate the IntentFilters
725            if (filters != null) {
726                if (filters.length == 0) {
727                    filters = null;
728                } else {
729                    for (IntentFilter filter : filters) {
730                        if (filter == null) {
731                            throw new IllegalArgumentException("null IntentFilter");
732                        }
733                    }
734                }
735            }
736
737            // Validate the tech lists
738            String[][] techLists = null;
739            if (techListsParcel != null) {
740                techLists = techListsParcel.getTechLists();
741            }
742
743            mNfcDispatcher.setForegroundDispatch(intent, filters, techLists);
744        }
745
746        @Override
747        public void setForegroundNdefPush(NdefMessage msg, INdefPushCallback callback) {
748            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
749            mP2pLinkManager.setNdefToSend(msg, callback);
750        }
751
752        @Override
753        public INfcTag getNfcTagInterface() throws RemoteException {
754            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
755            return mNfcTagService;
756        }
757
758        @Override
759        public INfcAdapterExtras getNfcAdapterExtrasInterface(String pkg) {
760            NfcService.this.enforceNfceeAdminPerm(pkg);
761            return mExtrasService;
762        }
763
764        @Override
765        public int getState() throws RemoteException {
766            synchronized (NfcService.this) {
767                return mState;
768            }
769        }
770
771        @Override
772        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
773            NfcService.this.dump(fd, pw, args);
774        }
775    }
776
777    final class TagService extends INfcTag.Stub {
778        @Override
779        public int close(int nativeHandle) throws RemoteException {
780            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
781
782            TagEndpoint tag = null;
783
784            if (!isNfcEnabled()) {
785                return ErrorCodes.ERROR_NOT_INITIALIZED;
786            }
787
788            /* find the tag in the hmap */
789            tag = (TagEndpoint) findObject(nativeHandle);
790            if (tag != null) {
791                /* Remove the device from the hmap */
792                unregisterObject(nativeHandle);
793                tag.disconnect();
794                return ErrorCodes.SUCCESS;
795            }
796            /* Restart polling loop for notification */
797            applyRouting(true);
798            return ErrorCodes.ERROR_DISCONNECT;
799        }
800
801        @Override
802        public int connect(int nativeHandle, int technology) throws RemoteException {
803            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
804
805            TagEndpoint tag = null;
806
807            if (!isNfcEnabled()) {
808                return ErrorCodes.ERROR_NOT_INITIALIZED;
809            }
810
811            /* find the tag in the hmap */
812            tag = (TagEndpoint) findObject(nativeHandle);
813            if (tag == null) {
814                return ErrorCodes.ERROR_DISCONNECT;
815            }
816
817            if (technology == TagTechnology.NFC_B) {
818                return ErrorCodes.ERROR_NOT_SUPPORTED;
819            }
820
821            // Note that on most tags, all technologies are behind a single
822            // handle. This means that the connect at the lower levels
823            // will do nothing, as the tag is already connected to that handle.
824            if (tag.connect(technology)) {
825                return ErrorCodes.SUCCESS;
826            } else {
827                return ErrorCodes.ERROR_DISCONNECT;
828            }
829        }
830
831        @Override
832        public int reconnect(int nativeHandle) throws RemoteException {
833            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
834
835            TagEndpoint tag = null;
836
837            // Check if NFC is enabled
838            if (!isNfcEnabled()) {
839                return ErrorCodes.ERROR_NOT_INITIALIZED;
840            }
841
842            /* find the tag in the hmap */
843            tag = (TagEndpoint) findObject(nativeHandle);
844            if (tag != null) {
845                if (tag.reconnect()) {
846                    return ErrorCodes.SUCCESS;
847                } else {
848                    return ErrorCodes.ERROR_DISCONNECT;
849                }
850            }
851            return ErrorCodes.ERROR_DISCONNECT;
852        }
853
854        @Override
855        public int[] getTechList(int nativeHandle) throws RemoteException {
856            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
857
858            // Check if NFC is enabled
859            if (!isNfcEnabled()) {
860                return null;
861            }
862
863            /* find the tag in the hmap */
864            TagEndpoint tag = (TagEndpoint) findObject(nativeHandle);
865            if (tag != null) {
866                return tag.getTechList();
867            }
868            return null;
869        }
870
871        @Override
872        public byte[] getUid(int nativeHandle) throws RemoteException {
873            TagEndpoint tag = null;
874            byte[] uid;
875
876            // Check if NFC is enabled
877            if (!isNfcEnabled()) {
878                return null;
879            }
880
881            /* find the tag in the hmap */
882            tag = (TagEndpoint) findObject(nativeHandle);
883            if (tag != null) {
884                uid = tag.getUid();
885                return uid;
886            }
887            return null;
888        }
889
890        @Override
891        public boolean isPresent(int nativeHandle) throws RemoteException {
892            TagEndpoint tag = null;
893
894            // Check if NFC is enabled
895            if (!isNfcEnabled()) {
896                return false;
897            }
898
899            /* find the tag in the hmap */
900            tag = (TagEndpoint) findObject(nativeHandle);
901            if (tag == null) {
902                return false;
903            }
904
905            return tag.isPresent();
906        }
907
908        @Override
909        public boolean isNdef(int nativeHandle) throws RemoteException {
910            TagEndpoint tag = null;
911
912            // Check if NFC is enabled
913            if (!isNfcEnabled()) {
914                return false;
915            }
916
917            /* find the tag in the hmap */
918            tag = (TagEndpoint) findObject(nativeHandle);
919            int[] ndefInfo = new int[2];
920            if (tag == null) {
921                return false;
922            }
923            return tag.checkNdef(ndefInfo);
924        }
925
926        @Override
927        public TransceiveResult transceive(int nativeHandle, byte[] data, boolean raw)
928                throws RemoteException {
929            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
930
931            TagEndpoint tag = null;
932            byte[] response;
933
934            // Check if NFC is enabled
935            if (!isNfcEnabled()) {
936                return null;
937            }
938
939            /* find the tag in the hmap */
940            tag = (TagEndpoint) findObject(nativeHandle);
941            if (tag != null) {
942                // Check if length is within limits
943                if (data.length > getMaxTransceiveLength(tag.getConnectedTechnology())) {
944                    return new TransceiveResult(TransceiveResult.RESULT_EXCEEDED_LENGTH, null);
945                }
946                int[] targetLost = new int[1];
947                response = tag.transceive(data, raw, targetLost);
948                int result;
949                if (response != null) {
950                    result = TransceiveResult.RESULT_SUCCESS;
951                } else if (targetLost[0] == 1) {
952                    result = TransceiveResult.RESULT_TAGLOST;
953                } else {
954                    result = TransceiveResult.RESULT_FAILURE;
955                }
956                return new TransceiveResult(result, response);
957            }
958            return null;
959        }
960
961        @Override
962        public NdefMessage ndefRead(int nativeHandle) throws RemoteException {
963            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
964
965            TagEndpoint tag;
966
967            // Check if NFC is enabled
968            if (!isNfcEnabled()) {
969                return null;
970            }
971
972            /* find the tag in the hmap */
973            tag = (TagEndpoint) findObject(nativeHandle);
974            if (tag != null) {
975                byte[] buf = tag.readNdef();
976                if (buf == null) {
977                    return null;
978                }
979
980                /* Create an NdefMessage */
981                try {
982                    return new NdefMessage(buf);
983                } catch (FormatException e) {
984                    return null;
985                }
986            }
987            return null;
988        }
989
990        @Override
991        public int ndefWrite(int nativeHandle, NdefMessage msg) throws RemoteException {
992            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
993
994            TagEndpoint tag;
995
996            // Check if NFC is enabled
997            if (!isNfcEnabled()) {
998                return ErrorCodes.ERROR_NOT_INITIALIZED;
999            }
1000
1001            /* find the tag in the hmap */
1002            tag = (TagEndpoint) findObject(nativeHandle);
1003            if (tag == null) {
1004                return ErrorCodes.ERROR_IO;
1005            }
1006
1007            if (tag.writeNdef(msg.toByteArray())) {
1008                return ErrorCodes.SUCCESS;
1009            } else {
1010                return ErrorCodes.ERROR_IO;
1011            }
1012
1013        }
1014
1015        @Override
1016        public int getLastError(int nativeHandle) throws RemoteException {
1017            return(mDeviceHost.doGetLastError());
1018        }
1019
1020        @Override
1021        public boolean ndefIsWritable(int nativeHandle) throws RemoteException {
1022            throw new UnsupportedOperationException();
1023        }
1024
1025        @Override
1026        public int ndefMakeReadOnly(int nativeHandle) throws RemoteException {
1027            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1028
1029            TagEndpoint tag;
1030
1031            // Check if NFC is enabled
1032            if (!isNfcEnabled()) {
1033                return ErrorCodes.ERROR_NOT_INITIALIZED;
1034            }
1035
1036            /* find the tag in the hmap */
1037            tag = (TagEndpoint) findObject(nativeHandle);
1038            if (tag == null) {
1039                return ErrorCodes.ERROR_IO;
1040            }
1041
1042            if (tag.makeReadOnly()) {
1043                return ErrorCodes.SUCCESS;
1044            } else {
1045                return ErrorCodes.ERROR_IO;
1046            }
1047        }
1048
1049        @Override
1050        public int formatNdef(int nativeHandle, byte[] key) throws RemoteException {
1051            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1052
1053            TagEndpoint tag;
1054
1055            // Check if NFC is enabled
1056            if (!isNfcEnabled()) {
1057                return ErrorCodes.ERROR_NOT_INITIALIZED;
1058            }
1059
1060            /* find the tag in the hmap */
1061            tag = (TagEndpoint) findObject(nativeHandle);
1062            if (tag == null) {
1063                return ErrorCodes.ERROR_IO;
1064            }
1065
1066            if (tag.formatNdef(key)) {
1067                return ErrorCodes.SUCCESS;
1068            } else {
1069                return ErrorCodes.ERROR_IO;
1070            }
1071        }
1072
1073        @Override
1074        public Tag rediscover(int nativeHandle) throws RemoteException {
1075            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1076
1077            TagEndpoint tag = null;
1078
1079            // Check if NFC is enabled
1080            if (!isNfcEnabled()) {
1081                return null;
1082            }
1083
1084            /* find the tag in the hmap */
1085            tag = (TagEndpoint) findObject(nativeHandle);
1086            if (tag != null) {
1087                // For now the prime usecase for rediscover() is to be able
1088                // to access the NDEF technology after formatting without
1089                // having to remove the tag from the field, or similar
1090                // to have access to NdefFormatable in case low-level commands
1091                // were used to remove NDEF. So instead of doing a full stack
1092                // rediscover (which is poorly supported at the moment anyway),
1093                // we simply remove these two technologies and detect them
1094                // again.
1095                tag.removeTechnology(TagTechnology.NDEF);
1096                tag.removeTechnology(TagTechnology.NDEF_FORMATABLE);
1097                NdefMessage[] msgs = tag.findAndReadNdef();
1098                // Build a new Tag object to return
1099                Tag newTag = new Tag(tag.getUid(), tag.getTechList(),
1100                        tag.getTechExtras(), tag.getHandle(), this);
1101                return newTag;
1102            }
1103            return null;
1104        }
1105
1106        @Override
1107        public int setTimeout(int tech, int timeout) throws RemoteException {
1108            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1109            boolean success = mDeviceHost.setTimeout(tech, timeout);
1110            if (success) {
1111                return ErrorCodes.SUCCESS;
1112            } else {
1113                return ErrorCodes.ERROR_INVALID_PARAM;
1114            }
1115        }
1116
1117        @Override
1118        public int getTimeout(int tech) throws RemoteException {
1119            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1120
1121            return mDeviceHost.getTimeout(tech);
1122        }
1123
1124        @Override
1125        public void resetTimeouts() throws RemoteException {
1126            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1127
1128            mDeviceHost.resetTimeouts();
1129        }
1130
1131        @Override
1132        public boolean canMakeReadOnly(int ndefType) throws RemoteException {
1133            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1134
1135            return mDeviceHost.canMakeReadOnly(ndefType);
1136        }
1137
1138        @Override
1139        public int getMaxTransceiveLength(int tech) throws RemoteException {
1140            mContext.enforceCallingOrSelfPermission(NFC_PERM, NFC_PERM_ERROR);
1141
1142            return mDeviceHost.getMaxTransceiveLength(tech);
1143        }
1144    }
1145
1146    void _nfcEeClose(int callingPid, IBinder binder) throws IOException {
1147        // Blocks until a pending open() or transceive() times out.
1148        //TODO: This is incorrect behavior - the close should interrupt pending
1149        // operations. However this is not supported by current hardware.
1150
1151        synchronized (NfcService.this) {
1152            if (!isNfcEnabled()) {
1153                throw new IOException("NFC adapter is disabled");
1154            }
1155            if (mOpenEe == null) {
1156                throw new IOException("NFC EE closed");
1157            }
1158            if (callingPid != -1 && callingPid != mOpenEe.pid) {
1159                throw new SecurityException("Wrong PID");
1160            }
1161            if (mOpenEe.binder != binder) {
1162                throw new SecurityException("Wrong binder handle");
1163            }
1164
1165            binder.unlinkToDeath(mOpenEe, 0);
1166            mDeviceHost.resetTimeouts();
1167            mSecureElement.doDisconnect(mOpenEe.handle);
1168            mOpenEe = null;
1169
1170            applyRouting(true);
1171        }
1172    }
1173
1174    final class NfcAdapterExtrasService extends INfcAdapterExtras.Stub {
1175        private Bundle writeNoException() {
1176            Bundle p = new Bundle();
1177            p.putInt("e", 0);
1178            return p;
1179        }
1180        private Bundle writeIoException(IOException e) {
1181            Bundle p = new Bundle();
1182            p.putInt("e", -1);
1183            p.putString("m", e.getMessage());
1184            return p;
1185        }
1186
1187        @Override
1188        public Bundle open(String pkg, IBinder b) throws RemoteException {
1189            NfcService.this.enforceNfceeAdminPerm(pkg);
1190
1191            Bundle result;
1192            try {
1193                _open(b);
1194                result = writeNoException();
1195            } catch (IOException e) {
1196                result = writeIoException(e);
1197            }
1198            return result;
1199        }
1200
1201        private void _open(IBinder b) throws IOException {
1202            synchronized(NfcService.this) {
1203                if (!isNfcEnabled()) {
1204                    throw new IOException("NFC adapter is disabled");
1205                }
1206                if (mOpenEe != null) {
1207                    throw new IOException("NFC EE already open");
1208                }
1209
1210                int handle = mSecureElement.doOpenSecureElementConnection();
1211                if (handle == 0) {
1212                    throw new IOException("NFC EE failed to open");
1213                }
1214                mDeviceHost.setTimeout(TagTechnology.ISO_DEP, 10000);
1215
1216                mOpenEe = new OpenSecureElement(getCallingPid(), handle, b);
1217                try {
1218                    b.linkToDeath(mOpenEe, 0);
1219                } catch (RemoteException e) {
1220                    mOpenEe.binderDied();
1221                }
1222
1223                // Add the calling package to the list of packages that have accessed
1224                // the secure element.
1225                for (String packageName : getPackageManager().getPackagesForUid(getCallingUid())) {
1226                    mSePackages.add(packageName);
1227                }
1228           }
1229        }
1230
1231        @Override
1232        public Bundle close(String pkg, IBinder binder) throws RemoteException {
1233            NfcService.this.enforceNfceeAdminPerm(pkg);
1234
1235            Bundle result;
1236            try {
1237                _nfcEeClose(getCallingPid(), binder);
1238                result = writeNoException();
1239            } catch (IOException e) {
1240                result = writeIoException(e);
1241            }
1242            return result;
1243        }
1244
1245        @Override
1246        public Bundle transceive(String pkg, byte[] in) throws RemoteException {
1247            NfcService.this.enforceNfceeAdminPerm(pkg);
1248
1249            Bundle result;
1250            byte[] out;
1251            try {
1252                out = _transceive(in);
1253                result = writeNoException();
1254                result.putByteArray("out", out);
1255            } catch (IOException e) {
1256                result = writeIoException(e);
1257            }
1258            return result;
1259        }
1260
1261        private byte[] _transceive(byte[] data) throws IOException {
1262            synchronized(NfcService.this) {
1263                if (!isNfcEnabled()) {
1264                    throw new IOException("NFC is not enabled");
1265                }
1266                if (mOpenEe == null) {
1267                    throw new IOException("NFC EE is not open");
1268                }
1269                if (getCallingPid() != mOpenEe.pid) {
1270                    throw new SecurityException("Wrong PID");
1271                }
1272            }
1273
1274            return mSecureElement.doTransceive(mOpenEe.handle, data);
1275        }
1276
1277        @Override
1278        public int getCardEmulationRoute(String pkg) throws RemoteException {
1279            NfcService.this.enforceNfceeAdminPerm(pkg);
1280            return mEeRoutingState;
1281        }
1282
1283        @Override
1284        public void setCardEmulationRoute(String pkg, int route) throws RemoteException {
1285            NfcService.this.enforceNfceeAdminPerm(pkg);
1286            mEeRoutingState = route;
1287            applyRouting(true);
1288        }
1289
1290        @Override
1291        public void authenticate(String pkg, byte[] token) throws RemoteException {
1292            NfcService.this.enforceNfceeAdminPerm(pkg);
1293        }
1294    }
1295
1296    /** resources kept while secure element is open */
1297    private class OpenSecureElement implements IBinder.DeathRecipient {
1298        public int pid;  // pid that opened SE
1299        // binder handle used for DeathReceipient. Must keep
1300        // a reference to this, otherwise it can get GC'd and
1301        // the binder stub code might create a different BinderProxy
1302        // for the same remote IBinder, causing mismatched
1303        // link()/unlink()
1304        public IBinder binder;
1305        public int handle; // low-level handle
1306        public OpenSecureElement(int pid, int handle, IBinder binder) {
1307            this.pid = pid;
1308            this.handle = handle;
1309            this.binder = binder;
1310        }
1311        @Override
1312        public void binderDied() {
1313            synchronized (NfcService.this) {
1314                Log.i(TAG, "Tracked app " + pid + " died");
1315                pid = -1;
1316                try {
1317                    _nfcEeClose(-1, binder);
1318                } catch (IOException e) { /* already closed */ }
1319            }
1320        }
1321        @Override
1322        public String toString() {
1323            return new StringBuilder('@').append(Integer.toHexString(hashCode())).append("[pid=")
1324                    .append(pid).append(" handle=").append(handle).append("]").toString();
1325        }
1326    }
1327
1328    boolean isNfcEnabled() {
1329        synchronized (this) {
1330            return mState == NfcAdapter.STATE_ON;
1331        }
1332    }
1333
1334    class WatchDogThread extends Thread {
1335        boolean mWatchDogCanceled = false;
1336        @Override
1337        public void run() {
1338            boolean slept = false;
1339            while (!slept) {
1340                try {
1341                    Thread.sleep(10000);
1342                    slept = true;
1343                } catch (InterruptedException e) { }
1344            }
1345            synchronized (this) {
1346                if (!mWatchDogCanceled) {
1347                    // Trigger watch-dog
1348                    Log.e(TAG, "Watch dog triggered");
1349                    mDeviceHost.doAbort();
1350                }
1351            }
1352        }
1353        public synchronized void cancel() {
1354            mWatchDogCanceled = true;
1355        }
1356    }
1357
1358    /**
1359     * Read mScreenState and apply NFC-C polling and NFC-EE routing
1360     */
1361    void applyRouting(boolean force) {
1362        synchronized (this) {
1363            if (!isNfcEnabled() || mOpenEe != null) {
1364                // PN544 cannot be reconfigured while EE is open
1365                return;
1366            }
1367
1368            if (PN544_QUIRK_DISCONNECT_BEFORE_RECONFIGURE && mScreenState == SCREEN_STATE_OFF) {
1369                /* TODO undo this after the LLCP stack is fixed.
1370                 * Use a different sequence when turning the screen off to
1371                 * workaround race conditions in pn544 libnfc. The race occurs
1372                 * when we change routing while there is a P2P target connect.
1373                 * The async LLCP callback will crash since the routing code
1374                 * is overwriting globals it relies on.
1375                 */
1376                if (POLLING_MODE > SCREEN_STATE_OFF) {
1377                    if (force || mNfcPollingEnabled) {
1378                        Log.d(TAG, "NFC-C OFF, disconnect");
1379                        mNfcPollingEnabled = false;
1380                        mDeviceHost.disableDiscovery();
1381                        maybeDisconnectTarget();
1382                    }
1383                }
1384                if (mEeRoutingState == ROUTE_ON_WHEN_SCREEN_ON) {
1385                    if (force || mNfceeRouteEnabled) {
1386                        Log.d(TAG, "NFC-EE OFF");
1387                        mNfceeRouteEnabled = false;
1388                        mDeviceHost.doDeselectSecureElement();
1389                    }
1390                }
1391                return;
1392            }
1393
1394            // configure NFC-EE routing
1395            if (mScreenState >= SCREEN_STATE_ON_LOCKED &&
1396                    mEeRoutingState == ROUTE_ON_WHEN_SCREEN_ON) {
1397                if (force || !mNfceeRouteEnabled) {
1398                    Log.d(TAG, "NFC-EE ON");
1399                    mNfceeRouteEnabled = true;
1400                    mDeviceHost.doSelectSecureElement();
1401                }
1402            } else {
1403                if (force ||  mNfceeRouteEnabled) {
1404                    Log.d(TAG, "NFC-EE OFF");
1405                    mNfceeRouteEnabled = false;
1406                    mDeviceHost.doDeselectSecureElement();
1407                }
1408            }
1409
1410            // configure NFC-C polling
1411            if (mScreenState >= POLLING_MODE) {
1412                if (force || !mNfcPollingEnabled) {
1413                    Log.d(TAG, "NFC-C ON");
1414                    mNfcPollingEnabled = true;
1415                    mDeviceHost.enableDiscovery();
1416                }
1417            } else {
1418                if (force || mNfcPollingEnabled) {
1419                    Log.d(TAG, "NFC-C OFF");
1420                    mNfcPollingEnabled = false;
1421                    mDeviceHost.disableDiscovery();
1422                }
1423            }
1424        }
1425    }
1426
1427    /** Disconnect any target if present */
1428    void maybeDisconnectTarget() {
1429        if (!isNfcEnabled()) {
1430            return;
1431        }
1432        Object[] objectsToDisconnect;
1433        synchronized (this) {
1434            Object[] objectValues = mObjectMap.values().toArray();
1435            // Copy the array before we clear mObjectMap,
1436            // just in case the HashMap values are backed by the same array
1437            objectsToDisconnect = Arrays.copyOf(objectValues, objectValues.length);
1438            mObjectMap.clear();
1439        }
1440        for (Object o : objectsToDisconnect) {
1441            if (DBG) Log.d(TAG, "disconnecting " + o.getClass().getName());
1442            if (o instanceof TagEndpoint) {
1443                // Disconnect from tags
1444                TagEndpoint tag = (TagEndpoint) o;
1445                tag.disconnect();
1446            } else if (o instanceof NfcDepEndpoint) {
1447                // Disconnect from P2P devices
1448                NfcDepEndpoint device = (NfcDepEndpoint) o;
1449                if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
1450                    // Remote peer is target, request disconnection
1451                    device.disconnect();
1452                } else {
1453                    // Remote peer is initiator, we cannot disconnect
1454                    // Just wait for field removal
1455                }
1456            }
1457        }
1458    }
1459
1460    Object findObject(int key) {
1461        synchronized (this) {
1462            Object device = mObjectMap.get(key);
1463            if (device == null) {
1464                Log.w(TAG, "Handle not found");
1465            }
1466            return device;
1467        }
1468    }
1469
1470    void registerTagObject(TagEndpoint tag) {
1471        synchronized (this) {
1472            mObjectMap.put(tag.getHandle(), tag);
1473        }
1474    }
1475
1476    void unregisterObject(int handle) {
1477        synchronized (this) {
1478            mObjectMap.remove(handle);
1479        }
1480    }
1481
1482    /** For use by code in this process */
1483    public LlcpSocket createLlcpSocket(int sap, int miu, int rw, int linearBufferLength)
1484            throws LlcpException {
1485        return mDeviceHost.createLlcpSocket(sap, miu, rw, linearBufferLength);
1486    }
1487
1488    /** For use by code in this process */
1489    public LlcpConnectionlessSocket createLlcpConnectionLessSocket(int sap)
1490            throws LlcpException {
1491        return mDeviceHost.createLlcpConnectionlessSocket(sap);
1492    }
1493
1494    /** For use by code in this process */
1495    public LlcpServerSocket createLlcpServerSocket(int sap, String sn, int miu, int rw,
1496            int linearBufferLength) throws LlcpException {
1497        return mDeviceHost.createLlcpServerSocket(sap, sn, miu, rw, linearBufferLength);
1498    }
1499
1500    public void sendMockNdefTag(NdefMessage msg) {
1501        sendMessage(MSG_MOCK_NDEF, msg);
1502    }
1503
1504    void sendMessage(int what, Object obj) {
1505        Message msg = mHandler.obtainMessage();
1506        msg.what = what;
1507        msg.obj = obj;
1508        mHandler.sendMessage(msg);
1509    }
1510
1511    final class NfcServiceHandler extends Handler {
1512        @Override
1513        public void handleMessage(Message msg) {
1514            switch (msg.what) {
1515                case MSG_MOCK_NDEF: {
1516                    NdefMessage ndefMsg = (NdefMessage) msg.obj;
1517                    Bundle extras = new Bundle();
1518                    extras.putParcelable(Ndef.EXTRA_NDEF_MSG, ndefMsg);
1519                    extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, 0);
1520                    extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, Ndef.NDEF_MODE_READ_ONLY);
1521                    extras.putInt(Ndef.EXTRA_NDEF_TYPE, Ndef.TYPE_OTHER);
1522                    Tag tag = Tag.createMockTag(new byte[] { 0x00 },
1523                            new int[] { TagTechnology.NDEF },
1524                            new Bundle[] { extras });
1525                    Log.d(TAG, "mock NDEF tag, starting corresponding activity");
1526                    Log.d(TAG, tag.toString());
1527                    boolean delivered = mNfcDispatcher.dispatchTag(tag,
1528                            new NdefMessage[] { ndefMsg });
1529                    if (delivered) {
1530                        playSound(SOUND_END);
1531                    } else {
1532                        playSound(SOUND_ERROR);
1533                    }
1534                    break;
1535                }
1536
1537                case MSG_NDEF_TAG:
1538                    if (DBG) Log.d(TAG, "Tag detected, notifying applications");
1539                    TagEndpoint tag = (TagEndpoint) msg.obj;
1540                    playSound(SOUND_START);
1541                    NdefMessage[] ndefMsgs = tag.findAndReadNdef();
1542
1543                    if (ndefMsgs != null) {
1544                        tag.startPresenceChecking();
1545                        dispatchTagEndpoint(tag, ndefMsgs);
1546                    } else {
1547                        if (tag.reconnect()) {
1548                            tag.startPresenceChecking();
1549                            dispatchTagEndpoint(tag, null);
1550                        } else {
1551                            tag.disconnect();
1552                            playSound(SOUND_ERROR);
1553                        }
1554                    }
1555                    break;
1556
1557                case MSG_CARD_EMULATION:
1558                    if (DBG) Log.d(TAG, "Card Emulation message");
1559                    byte[] aid = (byte[]) msg.obj;
1560                    /* Send broadcast */
1561                    Intent aidIntent = new Intent();
1562                    aidIntent.setAction(ACTION_AID_SELECTED);
1563                    aidIntent.putExtra(EXTRA_AID, aid);
1564                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_AID_SELECTED);
1565                    sendSeBroadcast(aidIntent);
1566                    break;
1567
1568                case MSG_SE_EMV_CARD_REMOVAL:
1569                    if (DBG) Log.d(TAG, "Card Removal message");
1570                    /* Send broadcast */
1571                    Intent cardRemovalIntent = new Intent();
1572                    cardRemovalIntent.setAction(ACTION_EMV_CARD_REMOVAL);
1573                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_EMV_CARD_REMOVAL);
1574                    sendSeBroadcast(cardRemovalIntent);
1575                    break;
1576
1577                case MSG_SE_APDU_RECEIVED:
1578                    if (DBG) Log.d(TAG, "APDU Received message");
1579                    byte[] apduBytes = (byte[]) msg.obj;
1580                    /* Send broadcast */
1581                    Intent apduReceivedIntent = new Intent();
1582                    apduReceivedIntent.setAction(ACTION_APDU_RECEIVED);
1583                    if (apduBytes != null && apduBytes.length > 0) {
1584                        apduReceivedIntent.putExtra(EXTRA_APDU_BYTES, apduBytes);
1585                    }
1586                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_APDU_RECEIVED);
1587                    sendSeBroadcast(apduReceivedIntent);
1588                    break;
1589
1590                case MSG_SE_MIFARE_ACCESS:
1591                    if (DBG) Log.d(TAG, "MIFARE access message");
1592                    /* Send broadcast */
1593                    byte[] mifareCmd = (byte[]) msg.obj;
1594                    Intent mifareAccessIntent = new Intent();
1595                    mifareAccessIntent.setAction(ACTION_MIFARE_ACCESS_DETECTED);
1596                    if (mifareCmd != null && mifareCmd.length > 1) {
1597                        int mifareBlock = mifareCmd[1] & 0xff;
1598                        if (DBG) Log.d(TAG, "Mifare Block=" + mifareBlock);
1599                        mifareAccessIntent.putExtra(EXTRA_MIFARE_BLOCK, mifareBlock);
1600                    }
1601                    if (DBG) Log.d(TAG, "Broadcasting " + ACTION_MIFARE_ACCESS_DETECTED);
1602                    sendSeBroadcast(mifareAccessIntent);
1603                    break;
1604
1605                case MSG_LLCP_LINK_ACTIVATION:
1606                    llcpActivated((NfcDepEndpoint) msg.obj);
1607                    break;
1608
1609                case MSG_LLCP_LINK_DEACTIVATED:
1610                    NfcDepEndpoint device = (NfcDepEndpoint) msg.obj;
1611                    boolean needsDisconnect = false;
1612
1613                    Log.d(TAG, "LLCP Link Deactivated message. Restart polling loop.");
1614                    synchronized (NfcService.this) {
1615                        /* Check if the device has been already unregistered */
1616                        if (mObjectMap.remove(device.getHandle()) != null) {
1617                            /* Disconnect if we are initiator */
1618                            if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
1619                                if (DBG) Log.d(TAG, "disconnecting from target");
1620                                needsDisconnect = true;
1621                            } else {
1622                                if (DBG) Log.d(TAG, "not disconnecting from initiator");
1623                            }
1624                        }
1625                    }
1626                    if (needsDisconnect) {
1627                        device.disconnect();  // restarts polling loop
1628                    }
1629
1630                    mP2pLinkManager.onLlcpDeactivated();
1631                    break;
1632
1633                case MSG_TARGET_DESELECTED:
1634                    /* Broadcast Intent Target Deselected */
1635                    if (DBG) Log.d(TAG, "Target Deselected");
1636                    Intent intent = new Intent();
1637                    intent.setAction(NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION);
1638                    if (DBG) Log.d(TAG, "Broadcasting Intent");
1639                    mContext.sendOrderedBroadcast(intent, NFC_PERM);
1640                    break;
1641
1642                case MSG_SE_FIELD_ACTIVATED: {
1643                    if (DBG) Log.d(TAG, "SE FIELD ACTIVATED");
1644                    Intent eventFieldOnIntent = new Intent();
1645                    eventFieldOnIntent.setAction(ACTION_RF_FIELD_ON_DETECTED);
1646                    sendSeBroadcast(eventFieldOnIntent);
1647                    break;
1648                }
1649
1650                case MSG_SE_FIELD_DEACTIVATED: {
1651                    if (DBG) Log.d(TAG, "SE FIELD DEACTIVATED");
1652                    Intent eventFieldOffIntent = new Intent();
1653                    eventFieldOffIntent.setAction(ACTION_RF_FIELD_OFF_DETECTED);
1654                    sendSeBroadcast(eventFieldOffIntent);
1655                    break;
1656                }
1657
1658                default:
1659                    Log.e(TAG, "Unknown message received");
1660                    break;
1661            }
1662        }
1663
1664        private void sendSeBroadcast(Intent intent) {
1665            PackageManager pm = getPackageManager();
1666            intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
1667
1668            // Resume app switches so the receivers can start activites without delay
1669            mNfcDispatcher.resumeAppSwitches();
1670
1671            List<PackageInfo> packages = pm.getInstalledPackages(0);
1672            for (PackageInfo pkg : packages) {
1673                if (pkg != null && pkg.applicationInfo != null) {
1674                    if (mNfceeAccessControl.check(pkg.applicationInfo)) {
1675                        intent.setPackage(pkg.packageName);
1676                        mContext.sendBroadcast(intent);
1677                    }
1678                }
1679            }
1680        }
1681
1682        private boolean llcpActivated(NfcDepEndpoint device) {
1683            Log.d(TAG, "LLCP Activation message");
1684
1685            if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
1686                if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_TARGET");
1687                if (device.connect()) {
1688                    /* Check LLCP compliancy */
1689                    if (mDeviceHost.doCheckLlcp()) {
1690                        /* Activate LLCP Link */
1691                        if (mDeviceHost.doActivateLlcp()) {
1692                            if (DBG) Log.d(TAG, "Initiator Activate LLCP OK");
1693                            synchronized (NfcService.this) {
1694                                // Register P2P device
1695                                mObjectMap.put(device.getHandle(), device);
1696                            }
1697                            mP2pLinkManager.onLlcpActivated();
1698                            return true;
1699                        } else {
1700                            /* should not happen */
1701                            Log.w(TAG, "Initiator LLCP activation failed. Disconnect.");
1702                            device.disconnect();
1703                        }
1704                    } else {
1705                        if (DBG) Log.d(TAG, "Remote Target does not support LLCP. Disconnect.");
1706                        device.disconnect();
1707                    }
1708                } else {
1709                    if (DBG) Log.d(TAG, "Cannot connect remote Target. Polling loop restarted.");
1710                    /*
1711                     * The polling loop should have been restarted in failing
1712                     * doConnect
1713                     */
1714                }
1715            } else if (device.getMode() == NfcDepEndpoint.MODE_P2P_INITIATOR) {
1716                if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_INITIATOR");
1717                /* Check LLCP compliancy */
1718                if (mDeviceHost.doCheckLlcp()) {
1719                    /* Activate LLCP Link */
1720                    if (mDeviceHost.doActivateLlcp()) {
1721                        if (DBG) Log.d(TAG, "Target Activate LLCP OK");
1722                        synchronized (NfcService.this) {
1723                            // Register P2P device
1724                            mObjectMap.put(device.getHandle(), device);
1725                        }
1726                        mP2pLinkManager.onLlcpActivated();
1727                        return true;
1728                    }
1729                } else {
1730                    Log.w(TAG, "checkLlcp failed");
1731                }
1732            }
1733
1734            return false;
1735        }
1736
1737        private void dispatchTagEndpoint(TagEndpoint tagEndpoint, NdefMessage[] msgs) {
1738            Tag tag = new Tag(tagEndpoint.getUid(), tagEndpoint.getTechList(),
1739                    tagEndpoint.getTechExtras(), tagEndpoint.getHandle(), mNfcTagService);
1740            registerTagObject(tagEndpoint);
1741            if (!mNfcDispatcher.dispatchTag(tag, msgs)) {
1742                unregisterObject(tagEndpoint.getHandle());
1743                playSound(SOUND_ERROR);
1744            } else {
1745                playSound(SOUND_END);
1746            }
1747        }
1748    }
1749
1750    private NfcServiceHandler mHandler = new NfcServiceHandler();
1751
1752    class ApplyRoutingTask extends AsyncTask<Integer, Void, Void> {
1753        @Override
1754        protected Void doInBackground(Integer... params) {
1755            synchronized (NfcService.this) {
1756                if (params == null || params.length != 1) {
1757                    // force apply current routing
1758                    applyRouting(true);
1759                    return null;
1760                }
1761                mScreenState = params[0].intValue();
1762
1763                boolean needWakelock = mScreenState == SCREEN_STATE_OFF;
1764                if (needWakelock) {
1765                    mWakeLock.acquire();
1766                }
1767                applyRouting(false);
1768                if (needWakelock) {
1769                    mWakeLock.release();
1770                }
1771                return null;
1772            }
1773        }
1774    }
1775
1776    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
1777        @Override
1778        public void onReceive(Context context, Intent intent) {
1779            String action = intent.getAction();
1780            if (action.equals(
1781                    NativeNfcManager.INTERNAL_TARGET_DESELECTED_ACTION)) {
1782                // Perform applyRouting() in AsyncTask to serialize blocking calls
1783                new ApplyRoutingTask().execute();
1784            } else if (action.equals(Intent.ACTION_SCREEN_ON)
1785                    || action.equals(Intent.ACTION_SCREEN_OFF)
1786                    || action.equals(Intent.ACTION_USER_PRESENT)) {
1787                // Perform applyRouting() in AsyncTask to serialize blocking calls
1788                int screenState = SCREEN_STATE_OFF;
1789                if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1790                    screenState = SCREEN_STATE_OFF;
1791                } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
1792                    screenState = mKeyguard.isKeyguardLocked() ?
1793                            SCREEN_STATE_ON_LOCKED : SCREEN_STATE_ON_UNLOCKED;
1794                } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
1795                    screenState = SCREEN_STATE_ON_UNLOCKED;
1796                }
1797                new ApplyRoutingTask().execute(Integer.valueOf(screenState));
1798            } else if (action.equals(ACTION_MASTER_CLEAR_NOTIFICATION)) {
1799                EnableDisableTask eeWipeTask = new EnableDisableTask();
1800                eeWipeTask.execute(TASK_EE_WIPE);
1801                try {
1802                    eeWipeTask.get();  // blocks until EE wipe is complete
1803                } catch (ExecutionException e) {
1804                    Log.w(TAG, "failed to wipe NFC-EE");
1805                } catch (InterruptedException e) {
1806                    Log.w(TAG, "failed to wipe NFC-EE");
1807                }
1808            } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
1809                // Clear the NFCEE access cache in case a UID gets recycled
1810                mNfceeAccessControl.invalidateCache();
1811
1812                boolean dataRemoved = intent.getBooleanExtra(Intent.EXTRA_DATA_REMOVED, false);
1813                if (dataRemoved) {
1814                    Uri data = intent.getData();
1815                    if (data == null) return;
1816                    String packageName = data.getSchemeSpecificPart();
1817
1818                    synchronized (NfcService.this) {
1819                        if (mSePackages.contains(packageName)) {
1820                            new EnableDisableTask().execute(TASK_EE_WIPE);
1821                            mSePackages.remove(packageName);
1822                        }
1823                    }
1824                }
1825            } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
1826                boolean isAirplaneModeOn = intent.getBooleanExtra("state", false);
1827                // Query the airplane mode from Settings.System just to make sure that
1828                // some random app is not sending this intent
1829                if (isAirplaneModeOn != isAirplaneModeOn()) {
1830                    return;
1831                }
1832                if (!mIsAirplaneSensitive) {
1833                    return;
1834                }
1835                if (isAirplaneModeOn) {
1836                    new EnableDisableTask().execute(TASK_DISABLE);
1837                } else if (!isAirplaneModeOn && mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT)) {
1838                    new EnableDisableTask().execute(TASK_ENABLE);
1839                }
1840            }
1841        }
1842    };
1843
1844    /** Returns true if airplane mode is currently on */
1845    boolean isAirplaneModeOn() {
1846        return Settings.System.getInt(mContext.getContentResolver(),
1847                Settings.System.AIRPLANE_MODE_ON, 0) == 1;
1848    }
1849
1850    /** for debugging only - no i18n */
1851    static String stateToString(int state) {
1852        switch (state) {
1853            case NfcAdapter.STATE_OFF:
1854                return "off";
1855            case NfcAdapter.STATE_TURNING_ON:
1856                return "turning on";
1857            case NfcAdapter.STATE_ON:
1858                return "on";
1859            case NfcAdapter.STATE_TURNING_OFF:
1860                return "turning off";
1861            default:
1862                return "<error>";
1863        }
1864    }
1865
1866    /** For debugging only - no i18n */
1867    static String screenStateToString(int screenState) {
1868        switch (screenState) {
1869            case SCREEN_STATE_OFF:
1870                return "OFF";
1871            case SCREEN_STATE_ON_LOCKED:
1872                return "ON_LOCKED";
1873            case SCREEN_STATE_ON_UNLOCKED:
1874                return "ON_UNLOCKED";
1875            default:
1876                return "UNKNOWN";
1877        }
1878    }
1879
1880    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1881        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1882                != PackageManager.PERMISSION_GRANTED) {
1883            pw.println("Permission Denial: can't dump nfc from from pid="
1884                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
1885                    + " without permission " + android.Manifest.permission.DUMP);
1886            return;
1887        }
1888
1889        synchronized (this) {
1890            pw.println("mState=" + stateToString(mState));
1891            pw.println("mIsZeroClickRequested=" + mIsNdefPushEnabled);
1892            pw.println("mScreenState=" + screenStateToString(mScreenState));
1893            pw.println("mNfcPollingEnabled=" + mNfcPollingEnabled);
1894            pw.println("mNfceeRouteEnabled=" + mNfceeRouteEnabled);
1895            pw.println("mIsAirplaneSensitive=" + mIsAirplaneSensitive);
1896            pw.println("mIsAirplaneToggleable=" + mIsAirplaneToggleable);
1897            pw.println("mOpenEe=" + mOpenEe);
1898            mP2pLinkManager.dump(fd, pw, args);
1899            mNfceeAccessControl.dump(fd, pw, args);
1900            pw.println(mDeviceHost.dump());
1901
1902        }
1903    }
1904}
1905