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