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