NfcService.java revision 34322b73c1e09907cb007e86bae77c744b338cd7
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 android.app.ActivityManager;
20import android.app.Application;
21import android.app.KeyguardManager;
22import android.app.PendingIntent;
23import android.app.ActivityManager.RunningTaskInfo;
24import android.content.BroadcastReceiver;
25import android.content.ContentResolver;
26import android.content.Context;
27import android.content.Intent;
28import android.content.IntentFilter;
29import android.content.SharedPreferences;
30import android.content.pm.PackageManager;
31import android.content.res.Resources.NotFoundException;
32import android.media.AudioManager;
33import android.media.SoundPool;
34import android.nfc.BeamShareData;
35import android.nfc.ErrorCodes;
36import android.nfc.FormatException;
37import android.nfc.IAppCallback;
38import android.nfc.INfcAdapter;
39import android.nfc.INfcAdapterExtras;
40import android.nfc.INfcCardEmulation;
41import android.nfc.INfcLockscreenDispatch;
42import android.nfc.INfcTag;
43import android.nfc.NdefMessage;
44import android.nfc.NfcAdapter;
45import android.nfc.Tag;
46import android.nfc.TechListParcel;
47import android.nfc.TransceiveResult;
48import android.nfc.tech.Ndef;
49import android.nfc.tech.TagTechnology;
50import android.os.AsyncTask;
51import android.os.Binder;
52import android.os.Build;
53import android.os.Bundle;
54import android.os.Handler;
55import android.os.IBinder;
56import android.os.Message;
57import android.os.PowerManager;
58import android.os.Process;
59import android.os.RemoteException;
60import android.os.ServiceManager;
61import android.os.UserHandle;
62import android.provider.Settings;
63import android.util.Log;
64
65import com.android.nfc.DeviceHost.DeviceHostListener;
66import com.android.nfc.DeviceHost.LlcpConnectionlessSocket;
67import com.android.nfc.DeviceHost.LlcpServerSocket;
68import com.android.nfc.DeviceHost.LlcpSocket;
69import com.android.nfc.DeviceHost.NfcDepEndpoint;
70import com.android.nfc.DeviceHost.TagEndpoint;
71import com.android.nfc.cardemulation.CardEmulationManager;
72import com.android.nfc.dhimpl.NativeNfcManager;
73import com.android.nfc.handover.HandoverManager;
74
75import java.io.FileDescriptor;
76import java.io.PrintWriter;
77import java.util.Arrays;
78import java.util.HashMap;
79import java.util.List;
80import java.util.Map;
81import java.util.NoSuchElementException;
82
83public class NfcService implements DeviceHostListener {
84    static final boolean DBG = false;
85    static final String TAG = "NfcService";
86
87    public static final String SERVICE_NAME = "nfc";
88
89    public static final String PREF = "NfcServicePrefs";
90
91    static final String PREF_NFC_ON = "nfc_on";
92    static final boolean NFC_ON_DEFAULT = true;
93    static final String PREF_NDEF_PUSH_ON = "ndef_push_on";
94    static final boolean NDEF_PUSH_ON_DEFAULT = true;
95    static final String PREF_FIRST_BEAM = "first_beam";
96    static final String PREF_FIRST_BOOT = "first_boot";
97    static final String PREF_AIRPLANE_OVERRIDE = "airplane_override";
98
99    static final int MSG_NDEF_TAG = 0;
100    static final int MSG_LLCP_LINK_ACTIVATION = 2;
101    static final int MSG_LLCP_LINK_DEACTIVATED = 3;
102    static final int MSG_MOCK_NDEF = 7;
103    static final int MSG_LLCP_LINK_FIRST_PACKET = 15;
104    static final int MSG_ROUTE_AID = 16;
105    static final int MSG_UNROUTE_AID = 17;
106    static final int MSG_COMMIT_ROUTING = 18;
107    static final int MSG_INVOKE_BEAM = 19;
108
109    static final int TASK_ENABLE = 1;
110    static final int TASK_DISABLE = 2;
111    static final int TASK_BOOT = 3;
112
113    // Polling technology masks
114    static final int NFC_POLL_A = 0x01;
115    static final int NFC_POLL_B = 0x02;
116    static final int NFC_POLL_F = 0x04;
117    static final int NFC_POLL_ISO15693 = 0x08;
118    static final int NFC_POLL_B_PRIME = 0x10;
119    static final int NFC_POLL_KOVIO = 0x20;
120
121    // minimum screen state that enables NFC polling
122    static final int NFC_POLLING_MODE = ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED;
123
124    // Time to wait for NFC controller to initialize before watchdog
125    // goes off. This time is chosen large, because firmware download
126    // may be a part of initialization.
127    static final int INIT_WATCHDOG_MS = 90000;
128
129    // Time to wait for routing to be applied before watchdog
130    // goes off
131    static final int ROUTING_WATCHDOG_MS = 10000;
132
133    // Default delay used for presence checks
134    static final int DEFAULT_PRESENCE_CHECK_DELAY = 125;
135
136    // The amount of time we wait before manually launching
137    // the Beam animation when called through the share menu.
138    static final int INVOKE_BEAM_DELAY_MS = 1000;
139
140    // for use with playSound()
141    public static final int SOUND_START = 0;
142    public static final int SOUND_END = 1;
143    public static final int SOUND_ERROR = 2;
144
145    public static final String ACTION_LLCP_UP =
146            "com.android.nfc.action.LLCP_UP";
147
148    public static final String ACTION_LLCP_DOWN =
149            "com.android.nfc.action.LLCP_DOWN";
150
151    // NFC Execution Environment
152    // fields below are protected by this
153    private final ReaderModeDeathRecipient mReaderModeDeathRecipient =
154            new ReaderModeDeathRecipient();
155
156    private boolean mDiscoveryEnabled = false;
157    private int mLockscreenPollMask;
158    private boolean mLockscreenDispatchEnabled;
159
160    // fields below are used in multiple threads and protected by synchronized(this)
161    final HashMap<Integer, Object> mObjectMap = new HashMap<Integer, Object>();
162    int mScreenState;
163    boolean mInProvisionMode; // whether we're in setup wizard and enabled NFC provisioning
164    boolean mIsNdefPushEnabled;
165    NfcDiscoveryParameters mCurrentDiscoveryParameters;
166
167    ReaderModeParams mReaderModeParams;
168
169    // mState is protected by this, however it is only modified in onCreate()
170    // and the default AsyncTask thread so it is read unprotected from that
171    // thread
172    int mState;  // one of NfcAdapter.STATE_ON, STATE_TURNING_ON, etc
173    // fields below are final after onCreate()
174    Context mContext;
175    private DeviceHost mDeviceHost;
176    private SharedPreferences mPrefs;
177    private SharedPreferences.Editor mPrefsEditor;
178    private PowerManager.WakeLock mRoutingWakeLock;
179
180    int mStartSound;
181    int mEndSound;
182    int mErrorSound;
183    SoundPool mSoundPool; // playback synchronized on this
184    P2pLinkManager mP2pLinkManager;
185    TagService mNfcTagService;
186    NfcAdapterService mNfcAdapter;
187    boolean mIsAirplaneSensitive;
188    boolean mIsAirplaneToggleable;
189    boolean mIsDebugBuild;
190    boolean mIsHceCapable;
191
192    private NfcDispatcher mNfcDispatcher;
193    private PowerManager mPowerManager;
194    private KeyguardManager mKeyguard;
195    private HandoverManager mHandoverManager;
196    private ContentResolver mContentResolver;
197    private CardEmulationManager mCardEmulationManager;
198
199    private ScreenStateHelper mScreenStateHelper;
200    private ForegroundUtils mForegroundUtils;
201
202    private int mUserId;
203    private static NfcService sService;
204
205    public static NfcService getInstance() {
206        return sService;
207    }
208
209    @Override
210    public void onRemoteEndpointDiscovered(TagEndpoint tag) {
211        sendMessage(NfcService.MSG_NDEF_TAG, tag);
212    }
213
214    /**
215     * Notifies transaction
216     */
217    @Override
218    public void onHostCardEmulationActivated() {
219        if (mCardEmulationManager != null) {
220            mCardEmulationManager.onHostCardEmulationActivated();
221        }
222    }
223
224    @Override
225    public void onHostCardEmulationData(byte[] data) {
226        if (mCardEmulationManager != null) {
227            mCardEmulationManager.onHostCardEmulationData(data);
228        }
229    }
230
231    @Override
232    public void onHostCardEmulationDeactivated() {
233        if (mCardEmulationManager != null) {
234            mCardEmulationManager.onHostCardEmulationDeactivated();
235        }
236    }
237
238    /**
239     * Notifies P2P Device detected, to activate LLCP link
240     */
241    @Override
242    public void onLlcpLinkActivated(NfcDepEndpoint device) {
243        sendMessage(NfcService.MSG_LLCP_LINK_ACTIVATION, device);
244    }
245
246    /**
247     * Notifies P2P Device detected, to activate LLCP link
248     */
249    @Override
250    public void onLlcpLinkDeactivated(NfcDepEndpoint device) {
251        sendMessage(NfcService.MSG_LLCP_LINK_DEACTIVATED, device);
252    }
253
254    /**
255     * Notifies P2P Device detected, first packet received over LLCP link
256     */
257    @Override
258    public void onLlcpFirstPacketReceived(NfcDepEndpoint device) {
259        sendMessage(NfcService.MSG_LLCP_LINK_FIRST_PACKET, device);
260    }
261
262    final class ReaderModeParams {
263        public int flags;
264        public IAppCallback callback;
265        public int presenceCheckDelay;
266    }
267
268    public NfcService(Application nfcApplication) {
269        mUserId = ActivityManager.getCurrentUser();
270        mContext = nfcApplication;
271
272        mNfcTagService = new TagService();
273        mNfcAdapter = new NfcAdapterService();
274        Log.i(TAG, "Starting NFC service");
275
276        sService = this;
277
278        mScreenStateHelper = new ScreenStateHelper(mContext);
279        mContentResolver = mContext.getContentResolver();
280        mDeviceHost = new NativeNfcManager(mContext, this);
281
282        mHandoverManager = new HandoverManager(mContext);
283        boolean isNfcProvisioningEnabled = false;
284        try {
285            isNfcProvisioningEnabled = mContext.getResources().getBoolean(
286                    R.bool.enable_nfc_provisioning);
287        } catch (NotFoundException e) {
288        }
289
290        if (isNfcProvisioningEnabled) {
291            mInProvisionMode = Settings.Secure.getInt(mContentResolver,
292                    Settings.Global.DEVICE_PROVISIONED, 0) == 0;
293        } else {
294            mInProvisionMode = false;
295        }
296
297        mHandoverManager.setEnabled(!mInProvisionMode);
298        mNfcDispatcher = new NfcDispatcher(mContext, mHandoverManager, mInProvisionMode);
299        mP2pLinkManager = new P2pLinkManager(mContext, mHandoverManager,
300                mDeviceHost.getDefaultLlcpMiu(), mDeviceHost.getDefaultLlcpRwSize());
301
302        mPrefs = mContext.getSharedPreferences(PREF, Context.MODE_PRIVATE);
303        mPrefsEditor = mPrefs.edit();
304
305        mState = NfcAdapter.STATE_OFF;
306        mIsNdefPushEnabled = mPrefs.getBoolean(PREF_NDEF_PUSH_ON, NDEF_PUSH_ON_DEFAULT);
307
308        mIsDebugBuild = "userdebug".equals(Build.TYPE) || "eng".equals(Build.TYPE);
309
310        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
311
312        mRoutingWakeLock = mPowerManager.newWakeLock(
313                PowerManager.PARTIAL_WAKE_LOCK, "NfcService:mRoutingWakeLock");
314
315        mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
316        mScreenState = mScreenStateHelper.checkScreenState();
317
318        ServiceManager.addService(SERVICE_NAME, mNfcAdapter);
319
320        // Intents for all users
321        IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
322        filter.addAction(Intent.ACTION_SCREEN_ON);
323        filter.addAction(Intent.ACTION_USER_PRESENT);
324        filter.addAction(Intent.ACTION_USER_SWITCHED);
325        registerForAirplaneMode(filter);
326        mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, null);
327
328        PackageManager pm = mContext.getPackageManager();
329        mIsHceCapable = pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION);
330        if (mIsHceCapable) {
331            mCardEmulationManager = new CardEmulationManager(mContext);
332        }
333        mForegroundUtils = ForegroundUtils.getInstance();
334        new EnableDisableTask().execute(TASK_BOOT);  // do blocking boot tasks
335    }
336
337    void initSoundPool() {
338        synchronized (this) {
339            if (mSoundPool == null) {
340                mSoundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0);
341                mStartSound = mSoundPool.load(mContext, R.raw.start, 1);
342                mEndSound = mSoundPool.load(mContext, R.raw.end, 1);
343                mErrorSound = mSoundPool.load(mContext, R.raw.error, 1);
344            }
345        }
346    }
347
348    void releaseSoundPool() {
349        synchronized (this) {
350            if (mSoundPool != null) {
351                mSoundPool.release();
352                mSoundPool = null;
353            }
354        }
355    }
356
357    void registerForAirplaneMode(IntentFilter filter) {
358        final String airplaneModeRadios = Settings.System.getString(mContentResolver,
359                Settings.Global.AIRPLANE_MODE_RADIOS);
360        final String toggleableRadios = Settings.System.getString(mContentResolver,
361                Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS);
362
363        mIsAirplaneSensitive = airplaneModeRadios == null ? true :
364                airplaneModeRadios.contains(Settings.Global.RADIO_NFC);
365        mIsAirplaneToggleable = toggleableRadios == null ? false :
366                toggleableRadios.contains(Settings.Global.RADIO_NFC);
367
368        if (mIsAirplaneSensitive) {
369            filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
370        }
371    }
372
373    /**
374     * Manages tasks that involve turning on/off the NFC controller.
375     * <p/>
376     * <p>All work that might turn the NFC adapter on or off must be done
377     * through this task, to keep the handling of mState simple.
378     * In other words, mState is only modified in these tasks (and we
379     * don't need a lock to read it in these tasks).
380     * <p/>
381     * <p>These tasks are all done on the same AsyncTask background
382     * thread, so they are serialized. Each task may temporarily transition
383     * mState to STATE_TURNING_OFF or STATE_TURNING_ON, but must exit in
384     * either STATE_ON or STATE_OFF. This way each task can be guaranteed
385     * of starting in either STATE_OFF or STATE_ON, without needing to hold
386     * NfcService.this for the entire task.
387     * <p/>
388     * <p>AsyncTask's are also implicitly queued. This is useful for corner
389     * cases like turning airplane mode on while TASK_ENABLE is in progress.
390     * The TASK_DISABLE triggered by airplane mode will be correctly executed
391     * immediately after TASK_ENABLE is complete. This seems like the most sane
392     * way to deal with these situations.
393     * <p/>
394     * <p>{@link #TASK_ENABLE} enables the NFC adapter, without changing
395     * preferences
396     * <p>{@link #TASK_DISABLE} disables the NFC adapter, without changing
397     * preferences
398     * <p>{@link #TASK_BOOT} does first boot work and may enable NFC
399     */
400    class EnableDisableTask extends AsyncTask<Integer, Void, Void> {
401        @Override
402        protected Void doInBackground(Integer... params) {
403            // Sanity check mState
404            switch (mState) {
405                case NfcAdapter.STATE_TURNING_OFF:
406                case NfcAdapter.STATE_TURNING_ON:
407                    Log.e(TAG, "Processing EnableDisable task " + params[0] + " from bad state " +
408                            mState);
409                    return null;
410            }
411
412            /* AsyncTask sets this thread to THREAD_PRIORITY_BACKGROUND,
413             * override with the default. THREAD_PRIORITY_BACKGROUND causes
414             * us to service software I2C too slow for firmware download
415             * with the NXP PN544.
416             * TODO: move this to the DAL I2C layer in libnfc-nxp, since this
417             * problem only occurs on I2C platforms using PN544
418             */
419            Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
420
421            switch (params[0].intValue()) {
422                case TASK_ENABLE:
423                    enableInternal();
424                    break;
425                case TASK_DISABLE:
426                    disableInternal();
427                    break;
428                case TASK_BOOT:
429                    Log.d(TAG, "checking on firmware download");
430                    boolean airplaneOverride = mPrefs.getBoolean(PREF_AIRPLANE_OVERRIDE, false);
431                    if (mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT) &&
432                            (!mIsAirplaneSensitive || !isAirplaneModeOn() || airplaneOverride)) {
433                        Log.d(TAG, "NFC is on. Doing normal stuff");
434                        enableInternal();
435                    } else {
436                        Log.d(TAG, "NFC is off.  Checking firmware version");
437                        mDeviceHost.checkFirmware();
438                    }
439                    if (mPrefs.getBoolean(PREF_FIRST_BOOT, true)) {
440                        Log.i(TAG, "First Boot");
441                        mPrefsEditor.putBoolean(PREF_FIRST_BOOT, false);
442                        mPrefsEditor.apply();
443                    }
444                    break;
445            }
446
447            // Restore default AsyncTask priority
448            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
449            return null;
450        }
451
452        /**
453         * Enable NFC adapter functions.
454         * Does not toggle preferences.
455         */
456        boolean enableInternal() {
457            if (mState == NfcAdapter.STATE_ON) {
458                return true;
459            }
460            Log.i(TAG, "Enabling NFC");
461            updateState(NfcAdapter.STATE_TURNING_ON);
462
463            WatchDogThread watchDog = new WatchDogThread("enableInternal", INIT_WATCHDOG_MS);
464            watchDog.start();
465            try {
466                mRoutingWakeLock.acquire();
467                try {
468                    if (!mDeviceHost.initialize(mLockscreenDispatchEnabled)) {
469                        Log.w(TAG, "Error enabling NFC");
470                        updateState(NfcAdapter.STATE_OFF);
471                        return false;
472                    }
473                } finally {
474                    mRoutingWakeLock.release();
475                }
476            } finally {
477                watchDog.cancel();
478            }
479
480            if (mIsHceCapable) {
481                // Generate the initial card emulation routing table
482                mCardEmulationManager.onNfcEnabled();
483            }
484
485            synchronized (NfcService.this) {
486                mObjectMap.clear();
487                mP2pLinkManager.enableDisable(mIsNdefPushEnabled, true);
488                updateState(NfcAdapter.STATE_ON);
489            }
490
491            initSoundPool();
492
493            /* Start polling loop */
494
495            applyRouting(true);
496            return true;
497        }
498
499        /**
500         * Disable all NFC adapter functions.
501         * Does not toggle preferences.
502         */
503        boolean disableInternal() {
504            if (mState == NfcAdapter.STATE_OFF) {
505                return true;
506            }
507            Log.i(TAG, "Disabling NFC");
508            updateState(NfcAdapter.STATE_TURNING_OFF);
509
510            /* Sometimes mDeviceHost.deinitialize() hangs, use a watch-dog.
511             * Implemented with a new thread (instead of a Handler or AsyncTask),
512             * because the UI Thread and AsyncTask thread-pools can also get hung
513             * when the NFC controller stops responding */
514            WatchDogThread watchDog = new WatchDogThread("disableInternal", ROUTING_WATCHDOG_MS);
515            watchDog.start();
516
517            if (mIsHceCapable) {
518                mCardEmulationManager.onNfcDisabled();
519            }
520
521            mP2pLinkManager.enableDisable(false, false);
522
523            // Stop watchdog if tag present
524            // A convenient way to stop the watchdog properly consists of
525            // disconnecting the tag. The polling loop shall be stopped before
526            // to avoid the tag being discovered again.
527            maybeDisconnectTarget();
528
529            mNfcDispatcher.setForegroundDispatch(null, null, null);
530
531            boolean result = mDeviceHost.deinitialize();
532            if (DBG) Log.d(TAG, "mDeviceHost.deinitialize() = " + result);
533
534            watchDog.cancel();
535
536            updateState(NfcAdapter.STATE_OFF);
537
538            releaseSoundPool();
539
540            return result;
541        }
542
543        void updateState(int newState) {
544            synchronized (NfcService.this) {
545                if (newState == mState) {
546                    return;
547                }
548                mState = newState;
549                Intent intent = new Intent(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED);
550                intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
551                intent.putExtra(NfcAdapter.EXTRA_ADAPTER_STATE, mState);
552                mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT);
553            }
554        }
555    }
556
557    void saveNfcOnSetting(boolean on) {
558        synchronized (NfcService.this) {
559            mPrefsEditor.putBoolean(PREF_NFC_ON, on);
560            mPrefsEditor.apply();
561        }
562    }
563
564    public void playSound(int sound) {
565        synchronized (this) {
566            if (mSoundPool == null) {
567                Log.w(TAG, "Not playing sound when NFC is disabled");
568                return;
569            }
570            switch (sound) {
571                case SOUND_START:
572                    mSoundPool.play(mStartSound, 1.0f, 1.0f, 0, 0, 1.0f);
573                    break;
574                case SOUND_END:
575                    mSoundPool.play(mEndSound, 1.0f, 1.0f, 0, 0, 1.0f);
576                    break;
577                case SOUND_ERROR:
578                    mSoundPool.play(mErrorSound, 1.0f, 1.0f, 0, 0, 1.0f);
579                    break;
580            }
581        }
582    }
583
584    synchronized int getUserId() {
585        return mUserId;
586    }
587
588
589    final class NfcAdapterService extends INfcAdapter.Stub {
590        @Override
591        public boolean enable() throws RemoteException {
592            NfcPermissions.enforceAdminPermissions(mContext);
593
594            saveNfcOnSetting(true);
595
596            if (mIsAirplaneSensitive && isAirplaneModeOn()) {
597                if (!mIsAirplaneToggleable) {
598                    Log.i(TAG, "denying enable() request (airplane mode)");
599                    return false;
600                }
601                // Make sure the override survives a reboot
602                mPrefsEditor.putBoolean(PREF_AIRPLANE_OVERRIDE, true);
603                mPrefsEditor.apply();
604            }
605            new EnableDisableTask().execute(TASK_ENABLE);
606
607            return true;
608        }
609
610        @Override
611        public boolean disable(boolean saveState) throws RemoteException {
612            NfcPermissions.enforceAdminPermissions(mContext);
613
614            if (saveState) {
615                saveNfcOnSetting(false);
616            }
617
618            new EnableDisableTask().execute(TASK_DISABLE);
619
620            return true;
621        }
622
623        @Override
624        public boolean isNdefPushEnabled() throws RemoteException {
625            synchronized (NfcService.this) {
626                return mState == NfcAdapter.STATE_ON && mIsNdefPushEnabled;
627            }
628        }
629
630        @Override
631        public boolean enableNdefPush() throws RemoteException {
632            NfcPermissions.enforceAdminPermissions(mContext);
633            synchronized (NfcService.this) {
634                if (mIsNdefPushEnabled) {
635                    return true;
636                }
637                Log.i(TAG, "enabling NDEF Push");
638                mPrefsEditor.putBoolean(PREF_NDEF_PUSH_ON, true);
639                mPrefsEditor.apply();
640                mIsNdefPushEnabled = true;
641                if (isNfcEnabled()) {
642                    mP2pLinkManager.enableDisable(true, true);
643                }
644            }
645            return true;
646        }
647
648        @Override
649        public boolean disableNdefPush() throws RemoteException {
650            NfcPermissions.enforceAdminPermissions(mContext);
651            synchronized (NfcService.this) {
652                if (!mIsNdefPushEnabled) {
653                    return true;
654                }
655                Log.i(TAG, "disabling NDEF Push");
656                mPrefsEditor.putBoolean(PREF_NDEF_PUSH_ON, false);
657                mPrefsEditor.apply();
658                mIsNdefPushEnabled = false;
659                if (isNfcEnabled()) {
660                    mP2pLinkManager.enableDisable(false, true);
661                }
662            }
663            return true;
664        }
665
666        @Override
667        public void setForegroundDispatch(PendingIntent intent,
668                IntentFilter[] filters, TechListParcel techListsParcel) {
669            NfcPermissions.enforceUserPermissions(mContext);
670
671            // Short-cut the disable path
672            if (intent == null && filters == null && techListsParcel == null) {
673                mNfcDispatcher.setForegroundDispatch(null, null, null);
674                return;
675            }
676
677            // Validate the IntentFilters
678            if (filters != null) {
679                if (filters.length == 0) {
680                    filters = null;
681                } else {
682                    for (IntentFilter filter : filters) {
683                        if (filter == null) {
684                            throw new IllegalArgumentException("null IntentFilter");
685                        }
686                    }
687                }
688            }
689
690            // Validate the tech lists
691            String[][] techLists = null;
692            if (techListsParcel != null) {
693                techLists = techListsParcel.getTechLists();
694            }
695
696            mNfcDispatcher.setForegroundDispatch(intent, filters, techLists);
697        }
698
699
700        @Override
701        public void setAppCallback(IAppCallback callback) {
702            NfcPermissions.enforceUserPermissions(mContext);
703            mP2pLinkManager.setNdefCallback(callback, Binder.getCallingUid());
704        }
705
706        @Override
707        public void invokeBeam() {
708            NfcPermissions.enforceUserPermissions(mContext);
709
710            if (mForegroundUtils.isInForeground(Binder.getCallingUid())) {
711                mP2pLinkManager.onManualBeamInvoke(null);
712            } else {
713                Log.e(TAG, "Calling activity not in foreground.");
714            }
715        }
716
717        @Override
718        public void invokeBeamInternal(BeamShareData shareData) {
719            NfcPermissions.enforceAdminPermissions(mContext);
720            Message msg = Message.obtain();
721            msg.what = MSG_INVOKE_BEAM;
722            msg.obj = shareData;
723            // We have to send this message delayed for two reasons:
724            // 1) This is an IPC call from BeamShareActivity, which is
725            //    running when the user has invoked Beam through the
726            //    share menu. As soon as BeamShareActivity closes, the UI
727            //    will need some time to rebuild the original Activity.
728            //    Waiting here for a while gives a better chance of the UI
729            //    having been rebuilt, which means the screenshot that the
730            //    Beam animation is using will be more accurate.
731            // 2) Similarly, because the Activity that launched BeamShareActivity
732            //    with an ACTION_SEND intent is now in paused state, the NDEF
733            //    callbacks that it has registered may no longer be valid.
734            //    Allowing the original Activity to resume will make sure we
735            //    it has a chance to re-register the NDEF message / callback,
736            //    so we share the right data.
737            //
738            //    Note that this is somewhat of a hack because the delay may not actually
739            //    be long enough for 2) on very slow devices, but there's no better
740            //    way to do this right now without additional framework changes.
741            mHandler.sendMessageDelayed(msg, INVOKE_BEAM_DELAY_MS);
742        }
743
744        @Override
745        public INfcTag getNfcTagInterface() throws RemoteException {
746            return mNfcTagService;
747        }
748
749        @Override
750        public INfcCardEmulation getNfcCardEmulationInterface() {
751            if (mIsHceCapable) {
752                return mCardEmulationManager.getNfcCardEmulationInterface();
753            } else {
754                return null;
755            }
756        }
757
758        @Override
759        public int getState() throws RemoteException {
760            synchronized (NfcService.this) {
761                return mState;
762            }
763        }
764
765        @Override
766        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
767            NfcService.this.dump(fd, pw, args);
768        }
769
770        @Override
771        public void dispatch(Tag tag) throws RemoteException {
772            NfcPermissions.enforceAdminPermissions(mContext);
773            mNfcDispatcher.dispatchTag(tag);
774        }
775
776        @Override
777        public void setP2pModes(int initiatorModes, int targetModes) throws RemoteException {
778            NfcPermissions.enforceAdminPermissions(mContext);
779            mDeviceHost.setP2pInitiatorModes(initiatorModes);
780            mDeviceHost.setP2pTargetModes(targetModes);
781            applyRouting(true);
782        }
783
784        @Override
785        public void setReaderMode(IBinder binder, IAppCallback callback, int flags, Bundle extras)
786                throws RemoteException {
787            synchronized (NfcService.this) {
788                if (flags != 0) {
789                    try {
790                        mReaderModeParams = new ReaderModeParams();
791                        mReaderModeParams.callback = callback;
792                        mReaderModeParams.flags = flags;
793                        mReaderModeParams.presenceCheckDelay = extras != null
794                                ? (extras.getInt(NfcAdapter.EXTRA_READER_PRESENCE_CHECK_DELAY,
795                                        DEFAULT_PRESENCE_CHECK_DELAY))
796                                : DEFAULT_PRESENCE_CHECK_DELAY;
797                        binder.linkToDeath(mReaderModeDeathRecipient, 0);
798                    } catch (RemoteException e) {
799                        Log.e(TAG, "Remote binder has already died.");
800                        return;
801                    }
802                } else {
803                    try {
804                        mReaderModeParams = null;
805                        binder.unlinkToDeath(mReaderModeDeathRecipient, 0);
806                    } catch (NoSuchElementException e) {
807                        Log.e(TAG, "Reader mode Binder was never registered.");
808                    }
809                }
810                applyRouting(false);
811            }
812        }
813
814        @Override
815        public INfcAdapterExtras getNfcAdapterExtrasInterface(String pkg) throws RemoteException {
816            // nfc-extras implementation is no longer present in AOSP.
817            return null;
818        }
819
820        @Override
821        public void registerLockscreenDispatch(INfcLockscreenDispatch lockscreenDispatch,
822                                               int[] techList)
823                throws RemoteException {
824
825            NfcPermissions.enforceAdminPermissions(mContext);
826
827            boolean enableLockscreenDispatch = lockscreenDispatch != null;
828            int lockscreenPollMask;
829
830            if (enableLockscreenDispatch) {
831                lockscreenPollMask = computeLockscreenPollMask(techList);
832                mDeviceHost.enableScreenOffSuspend();
833            } else {
834                lockscreenPollMask = 0;
835                mDeviceHost.disableScreenOffSuspend();
836            }
837
838            synchronized (NfcService.this) {
839                mLockscreenPollMask = lockscreenPollMask;
840                mLockscreenDispatchEnabled = enableLockscreenDispatch;
841                mNfcDispatcher.registerLockscreenDispatch(lockscreenDispatch);
842            }
843
844            applyRouting(false);
845        }
846
847        private int computeLockscreenPollMask(int[] techList) {
848
849            Map<Integer, Integer> techCodeToMask = new HashMap<Integer, Integer>();
850
851            techCodeToMask.put(TagTechnology.NFC_A, NfcService.NFC_POLL_A);
852            techCodeToMask.put(TagTechnology.NFC_B,
853                    NfcService.NFC_POLL_B | NfcService.NFC_POLL_B_PRIME);
854            techCodeToMask.put(TagTechnology.NFC_V, NfcService.NFC_POLL_ISO15693);
855            techCodeToMask.put(TagTechnology.NFC_F, NfcService.NFC_POLL_F);
856            techCodeToMask.put(TagTechnology.NFC_BARCODE, NfcService.NFC_POLL_KOVIO);
857
858            int mask = 0;
859
860            for (int i = 0; i < techList.length; i++) {
861                if (techCodeToMask.containsKey(techList[i])) {
862                    mask |= techCodeToMask.get(techList[i]).intValue();
863                }
864            }
865
866            return mask;
867        }
868    }
869
870    final class ReaderModeDeathRecipient implements IBinder.DeathRecipient {
871        @Override
872        public void binderDied() {
873            synchronized (NfcService.this) {
874                if (mReaderModeParams != null) {
875                    mReaderModeParams = null;
876                    applyRouting(false);
877                }
878            }
879        }
880    }
881
882    final class TagService extends INfcTag.Stub {
883        @Override
884        public int close(int nativeHandle) throws RemoteException {
885            NfcPermissions.enforceUserPermissions(mContext);
886
887            TagEndpoint tag = null;
888
889            if (!isNfcEnabled()) {
890                return ErrorCodes.ERROR_NOT_INITIALIZED;
891            }
892
893            /* find the tag in the hmap */
894            tag = (TagEndpoint) findObject(nativeHandle);
895            if (tag != null) {
896                /* Remove the device from the hmap */
897                unregisterObject(nativeHandle);
898                tag.disconnect();
899                return ErrorCodes.SUCCESS;
900            }
901            /* Restart polling loop for notification */
902            applyRouting(true);
903            return ErrorCodes.ERROR_DISCONNECT;
904        }
905
906        @Override
907        public int connect(int nativeHandle, int technology) throws RemoteException {
908            NfcPermissions.enforceUserPermissions(mContext);
909
910            TagEndpoint tag = null;
911
912            if (!isNfcEnabled()) {
913                return ErrorCodes.ERROR_NOT_INITIALIZED;
914            }
915
916            /* find the tag in the hmap */
917            tag = (TagEndpoint) findObject(nativeHandle);
918            if (tag == null) {
919                return ErrorCodes.ERROR_DISCONNECT;
920            }
921
922            if (!tag.isPresent()) {
923                return ErrorCodes.ERROR_DISCONNECT;
924            }
925
926            // Note that on most tags, all technologies are behind a single
927            // handle. This means that the connect at the lower levels
928            // will do nothing, as the tag is already connected to that handle.
929            if (tag.connect(technology)) {
930                return ErrorCodes.SUCCESS;
931            } else {
932                return ErrorCodes.ERROR_DISCONNECT;
933            }
934        }
935
936        @Override
937        public int reconnect(int nativeHandle) throws RemoteException {
938            NfcPermissions.enforceUserPermissions(mContext);
939
940            TagEndpoint tag = null;
941
942            // Check if NFC is enabled
943            if (!isNfcEnabled()) {
944                return ErrorCodes.ERROR_NOT_INITIALIZED;
945            }
946
947            /* find the tag in the hmap */
948            tag = (TagEndpoint) findObject(nativeHandle);
949            if (tag != null) {
950                if (tag.reconnect()) {
951                    return ErrorCodes.SUCCESS;
952                } else {
953                    return ErrorCodes.ERROR_DISCONNECT;
954                }
955            }
956            return ErrorCodes.ERROR_DISCONNECT;
957        }
958
959        @Override
960        public int[] getTechList(int nativeHandle) throws RemoteException {
961            NfcPermissions.enforceUserPermissions(mContext);
962
963            // Check if NFC is enabled
964            if (!isNfcEnabled()) {
965                return null;
966            }
967
968            /* find the tag in the hmap */
969            TagEndpoint tag = (TagEndpoint) findObject(nativeHandle);
970            if (tag != null) {
971                return tag.getTechList();
972            }
973            return null;
974        }
975
976        @Override
977        public boolean isPresent(int nativeHandle) throws RemoteException {
978            TagEndpoint tag = null;
979
980            // Check if NFC is enabled
981            if (!isNfcEnabled()) {
982                return false;
983            }
984
985            /* find the tag in the hmap */
986            tag = (TagEndpoint) findObject(nativeHandle);
987            if (tag == null) {
988                return false;
989            }
990
991            return tag.isPresent();
992        }
993
994        @Override
995        public boolean isNdef(int nativeHandle) throws RemoteException {
996            NfcPermissions.enforceUserPermissions(mContext);
997
998            TagEndpoint tag = null;
999
1000            // Check if NFC is enabled
1001            if (!isNfcEnabled()) {
1002                return false;
1003            }
1004
1005            /* find the tag in the hmap */
1006            tag = (TagEndpoint) findObject(nativeHandle);
1007            int[] ndefInfo = new int[2];
1008            if (tag == null) {
1009                return false;
1010            }
1011            return tag.checkNdef(ndefInfo);
1012        }
1013
1014        @Override
1015        public TransceiveResult transceive(int nativeHandle, byte[] data, boolean raw)
1016                throws RemoteException {
1017            NfcPermissions.enforceUserPermissions(mContext);
1018
1019            TagEndpoint tag = null;
1020            byte[] response;
1021
1022            // Check if NFC is enabled
1023            if (!isNfcEnabled()) {
1024                return null;
1025            }
1026
1027            /* find the tag in the hmap */
1028            tag = (TagEndpoint) findObject(nativeHandle);
1029            if (tag != null) {
1030                // Check if length is within limits
1031                if (data.length > getMaxTransceiveLength(tag.getConnectedTechnology())) {
1032                    return new TransceiveResult(TransceiveResult.RESULT_EXCEEDED_LENGTH, null);
1033                }
1034                int[] targetLost = new int[1];
1035                response = tag.transceive(data, raw, targetLost);
1036                int result;
1037                if (response != null) {
1038                    result = TransceiveResult.RESULT_SUCCESS;
1039                } else if (targetLost[0] == 1) {
1040                    result = TransceiveResult.RESULT_TAGLOST;
1041                } else {
1042                    result = TransceiveResult.RESULT_FAILURE;
1043                }
1044                return new TransceiveResult(result, response);
1045            }
1046            return null;
1047        }
1048
1049        @Override
1050        public NdefMessage ndefRead(int nativeHandle) throws RemoteException {
1051            NfcPermissions.enforceUserPermissions(mContext);
1052
1053            TagEndpoint tag;
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                byte[] buf = tag.readNdef();
1064                if (buf == null) {
1065                    return null;
1066                }
1067
1068                /* Create an NdefMessage */
1069                try {
1070                    return new NdefMessage(buf);
1071                } catch (FormatException e) {
1072                    return null;
1073                }
1074            }
1075            return null;
1076        }
1077
1078        @Override
1079        public int ndefWrite(int nativeHandle, NdefMessage msg) throws RemoteException {
1080            NfcPermissions.enforceUserPermissions(mContext);
1081
1082            TagEndpoint tag;
1083
1084            // Check if NFC is enabled
1085            if (!isNfcEnabled()) {
1086                return ErrorCodes.ERROR_NOT_INITIALIZED;
1087            }
1088
1089            /* find the tag in the hmap */
1090            tag = (TagEndpoint) findObject(nativeHandle);
1091            if (tag == null) {
1092                return ErrorCodes.ERROR_IO;
1093            }
1094
1095            if (msg == null) return ErrorCodes.ERROR_INVALID_PARAM;
1096
1097            if (tag.writeNdef(msg.toByteArray())) {
1098                return ErrorCodes.SUCCESS;
1099            } else {
1100                return ErrorCodes.ERROR_IO;
1101            }
1102
1103        }
1104
1105        @Override
1106        public boolean ndefIsWritable(int nativeHandle) throws RemoteException {
1107            throw new UnsupportedOperationException();
1108        }
1109
1110        @Override
1111        public int ndefMakeReadOnly(int nativeHandle) throws RemoteException {
1112            NfcPermissions.enforceUserPermissions(mContext);
1113
1114            TagEndpoint tag;
1115
1116            // Check if NFC is enabled
1117            if (!isNfcEnabled()) {
1118                return ErrorCodes.ERROR_NOT_INITIALIZED;
1119            }
1120
1121            /* find the tag in the hmap */
1122            tag = (TagEndpoint) findObject(nativeHandle);
1123            if (tag == null) {
1124                return ErrorCodes.ERROR_IO;
1125            }
1126
1127            if (tag.makeReadOnly()) {
1128                return ErrorCodes.SUCCESS;
1129            } else {
1130                return ErrorCodes.ERROR_IO;
1131            }
1132        }
1133
1134        @Override
1135        public int formatNdef(int nativeHandle, byte[] key) throws RemoteException {
1136            NfcPermissions.enforceUserPermissions(mContext);
1137
1138            TagEndpoint tag;
1139
1140            // Check if NFC is enabled
1141            if (!isNfcEnabled()) {
1142                return ErrorCodes.ERROR_NOT_INITIALIZED;
1143            }
1144
1145            /* find the tag in the hmap */
1146            tag = (TagEndpoint) findObject(nativeHandle);
1147            if (tag == null) {
1148                return ErrorCodes.ERROR_IO;
1149            }
1150
1151            if (tag.formatNdef(key)) {
1152                return ErrorCodes.SUCCESS;
1153            } else {
1154                return ErrorCodes.ERROR_IO;
1155            }
1156        }
1157
1158        @Override
1159        public Tag rediscover(int nativeHandle) throws RemoteException {
1160            NfcPermissions.enforceUserPermissions(mContext);
1161
1162            TagEndpoint tag = null;
1163
1164            // Check if NFC is enabled
1165            if (!isNfcEnabled()) {
1166                return null;
1167            }
1168
1169            /* find the tag in the hmap */
1170            tag = (TagEndpoint) findObject(nativeHandle);
1171            if (tag != null) {
1172                // For now the prime usecase for rediscover() is to be able
1173                // to access the NDEF technology after formatting without
1174                // having to remove the tag from the field, or similar
1175                // to have access to NdefFormatable in case low-level commands
1176                // were used to remove NDEF. So instead of doing a full stack
1177                // rediscover (which is poorly supported at the moment anyway),
1178                // we simply remove these two technologies and detect them
1179                // again.
1180                tag.removeTechnology(TagTechnology.NDEF);
1181                tag.removeTechnology(TagTechnology.NDEF_FORMATABLE);
1182                tag.findAndReadNdef();
1183                // Build a new Tag object to return
1184                Tag newTag = new Tag(tag.getUid(), tag.getTechList(),
1185                        tag.getTechExtras(), tag.getHandle(), this);
1186                return newTag;
1187            }
1188            return null;
1189        }
1190
1191        @Override
1192        public int setTimeout(int tech, int timeout) throws RemoteException {
1193            NfcPermissions.enforceUserPermissions(mContext);
1194            boolean success = mDeviceHost.setTimeout(tech, timeout);
1195            if (success) {
1196                return ErrorCodes.SUCCESS;
1197            } else {
1198                return ErrorCodes.ERROR_INVALID_PARAM;
1199            }
1200        }
1201
1202        @Override
1203        public int getTimeout(int tech) throws RemoteException {
1204            NfcPermissions.enforceUserPermissions(mContext);
1205
1206            return mDeviceHost.getTimeout(tech);
1207        }
1208
1209        @Override
1210        public void resetTimeouts() throws RemoteException {
1211            NfcPermissions.enforceUserPermissions(mContext);
1212
1213            mDeviceHost.resetTimeouts();
1214        }
1215
1216        @Override
1217        public boolean canMakeReadOnly(int ndefType) throws RemoteException {
1218            return mDeviceHost.canMakeReadOnly(ndefType);
1219        }
1220
1221        @Override
1222        public int getMaxTransceiveLength(int tech) throws RemoteException {
1223            return mDeviceHost.getMaxTransceiveLength(tech);
1224        }
1225
1226        @Override
1227        public boolean getExtendedLengthApdusSupported() throws RemoteException {
1228            return mDeviceHost.getExtendedLengthApdusSupported();
1229        }
1230    }
1231
1232    boolean isNfcEnabledOrShuttingDown() {
1233        synchronized (this) {
1234            return (mState == NfcAdapter.STATE_ON || mState == NfcAdapter.STATE_TURNING_OFF);
1235        }
1236    }
1237
1238    boolean isNfcEnabled() {
1239        synchronized (this) {
1240            return mState == NfcAdapter.STATE_ON;
1241        }
1242    }
1243
1244    class WatchDogThread extends Thread {
1245        final Object mCancelWaiter = new Object();
1246        final int mTimeout;
1247        boolean mCanceled = false;
1248
1249        public WatchDogThread(String threadName, int timeout) {
1250            super(threadName);
1251            mTimeout = timeout;
1252        }
1253
1254        @Override
1255        public void run() {
1256            try {
1257                synchronized (mCancelWaiter) {
1258                    mCancelWaiter.wait(mTimeout);
1259                    if (mCanceled) {
1260                        return;
1261                    }
1262                }
1263            } catch (InterruptedException e) {
1264                // Should not happen; fall-through to abort.
1265                Log.w(TAG, "Watchdog thread interruped.");
1266                interrupt();
1267            }
1268            Log.e(TAG, "Watchdog triggered, aborting.");
1269            mDeviceHost.doAbort();
1270        }
1271
1272        public synchronized void cancel() {
1273            synchronized (mCancelWaiter) {
1274                mCanceled = true;
1275                mCancelWaiter.notify();
1276            }
1277        }
1278    }
1279
1280    static byte[] hexStringToBytes(String s) {
1281        if (s == null || s.length() == 0) return null;
1282        int len = s.length();
1283        if (len % 2 != 0) {
1284            s = '0' + s;
1285            len++;
1286        }
1287        byte[] data = new byte[len / 2];
1288        for (int i = 0; i < len; i += 2) {
1289            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
1290                    + Character.digit(s.charAt(i + 1), 16));
1291        }
1292        return data;
1293    }
1294
1295    /**
1296     * Read mScreenState and apply NFC-C polling and NFC-EE routing
1297     */
1298    void applyRouting(boolean force) {
1299        synchronized (this) {
1300            if (!isNfcEnabledOrShuttingDown()) {
1301                return;
1302            }
1303            WatchDogThread watchDog = new WatchDogThread("applyRouting", ROUTING_WATCHDOG_MS);
1304            if (mInProvisionMode) {
1305                mInProvisionMode = Settings.Secure.getInt(mContentResolver,
1306                        Settings.Global.DEVICE_PROVISIONED, 0) == 0;
1307                if (!mInProvisionMode) {
1308                    // Notify dispatcher it's fine to dispatch to any package now
1309                    // and allow handover transfers.
1310                    mNfcDispatcher.disableProvisioningMode();
1311                    mHandoverManager.setEnabled(true);
1312                }
1313            }
1314            // Special case: if we're transitioning to unlocked state while
1315            // still talking to a tag, postpone re-configuration.
1316            if (mScreenState == ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED && isTagPresent()) {
1317                Log.d(TAG, "Not updating discovery parameters, tag connected.");
1318                return;
1319            }
1320
1321            try {
1322                watchDog.start();
1323                // Compute new polling parameters
1324                NfcDiscoveryParameters newParams = computeDiscoveryParameters(mScreenState);
1325                if (force || !newParams.equals(mCurrentDiscoveryParameters)) {
1326                    if (newParams.shouldEnableDiscovery()) {
1327                        boolean shouldRestart = mDiscoveryEnabled;
1328                        mDeviceHost.enableDiscovery(newParams, shouldRestart);
1329                        mDiscoveryEnabled = true;
1330                    } else {
1331                        mDeviceHost.disableDiscovery();
1332                        mDiscoveryEnabled = false;
1333                    }
1334                    mCurrentDiscoveryParameters = newParams;
1335                } else {
1336                    Log.d(TAG, "Discovery configuration equal, not updating.");
1337                }
1338            } finally {
1339                watchDog.cancel();
1340            }
1341        }
1342    }
1343
1344    private NfcDiscoveryParameters computeDiscoveryParameters(int screenState) {
1345        // Recompute discovery parameters based on screen state
1346        NfcDiscoveryParameters.Builder paramsBuilder = NfcDiscoveryParameters.newBuilder();
1347        // Polling
1348        if (screenState >= NFC_POLLING_MODE) {
1349            // Check if reader-mode is enabled
1350            if (mReaderModeParams != null) {
1351                int techMask = 0;
1352                if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_A) != 0)
1353                    techMask |= NFC_POLL_A;
1354                if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_B) != 0)
1355                    techMask |= NFC_POLL_B;
1356                if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_F) != 0)
1357                    techMask |= NFC_POLL_F;
1358                if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_V) != 0)
1359                    techMask |= NFC_POLL_ISO15693;
1360                if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_BARCODE) != 0)
1361                    techMask |= NFC_POLL_KOVIO;
1362
1363                paramsBuilder.setTechMask(techMask);
1364                paramsBuilder.setEnableReaderMode(true);
1365            } else {
1366                paramsBuilder.setTechMask(NfcDiscoveryParameters.NFC_POLL_DEFAULT);
1367            }
1368        } else if (screenState == ScreenStateHelper.SCREEN_STATE_ON_LOCKED && mInProvisionMode) {
1369            paramsBuilder.setTechMask(NfcDiscoveryParameters.NFC_POLL_DEFAULT);
1370        } else if (screenState == ScreenStateHelper.SCREEN_STATE_ON_LOCKED &&
1371                mLockscreenDispatchEnabled) {
1372            // For lock-screen tags, no low-power polling
1373            paramsBuilder.setTechMask(mLockscreenPollMask);
1374            paramsBuilder.setEnableLowPowerDiscovery(false);
1375        }
1376
1377        if (mIsHceCapable && mScreenState >= ScreenStateHelper.SCREEN_STATE_ON_LOCKED) {
1378            // Host routing is always enabled at lock screen or later
1379            paramsBuilder.setEnableHostRouting(true);
1380        }
1381        return paramsBuilder.build();
1382    }
1383
1384    private boolean isTagPresent() {
1385        for (Object object : mObjectMap.values()) {
1386            if (object instanceof TagEndpoint) {
1387                return ((TagEndpoint) object).isPresent();
1388            }
1389        }
1390        return false;
1391    }
1392    /**
1393     * Disconnect any target if present
1394     */
1395    void maybeDisconnectTarget() {
1396        if (!isNfcEnabledOrShuttingDown()) {
1397            return;
1398        }
1399        Object[] objectsToDisconnect;
1400        synchronized (this) {
1401            Object[] objectValues = mObjectMap.values().toArray();
1402            // Copy the array before we clear mObjectMap,
1403            // just in case the HashMap values are backed by the same array
1404            objectsToDisconnect = Arrays.copyOf(objectValues, objectValues.length);
1405            mObjectMap.clear();
1406        }
1407        for (Object o : objectsToDisconnect) {
1408            if (DBG) Log.d(TAG, "disconnecting " + o.getClass().getName());
1409            if (o instanceof TagEndpoint) {
1410                // Disconnect from tags
1411                TagEndpoint tag = (TagEndpoint) o;
1412                tag.disconnect();
1413            } else if (o instanceof NfcDepEndpoint) {
1414                // Disconnect from P2P devices
1415                NfcDepEndpoint device = (NfcDepEndpoint) o;
1416                if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
1417                    // Remote peer is target, request disconnection
1418                    device.disconnect();
1419                } else {
1420                    // Remote peer is initiator, we cannot disconnect
1421                    // Just wait for field removal
1422                }
1423            }
1424        }
1425    }
1426
1427    Object findObject(int key) {
1428        synchronized (this) {
1429            Object device = mObjectMap.get(key);
1430            if (device == null) {
1431                Log.w(TAG, "Handle not found");
1432            }
1433            return device;
1434        }
1435    }
1436
1437    void registerTagObject(TagEndpoint tag) {
1438        synchronized (this) {
1439            mObjectMap.put(tag.getHandle(), tag);
1440        }
1441    }
1442
1443    void unregisterObject(int handle) {
1444        synchronized (this) {
1445            mObjectMap.remove(handle);
1446        }
1447    }
1448
1449    /**
1450     * For use by code in this process
1451     */
1452    public LlcpSocket createLlcpSocket(int sap, int miu, int rw, int linearBufferLength)
1453            throws LlcpException {
1454        return mDeviceHost.createLlcpSocket(sap, miu, rw, linearBufferLength);
1455    }
1456
1457    /**
1458     * For use by code in this process
1459     */
1460    public LlcpConnectionlessSocket createLlcpConnectionLessSocket(int sap, String sn)
1461            throws LlcpException {
1462        return mDeviceHost.createLlcpConnectionlessSocket(sap, sn);
1463    }
1464
1465    /**
1466     * For use by code in this process
1467     */
1468    public LlcpServerSocket createLlcpServerSocket(int sap, String sn, int miu, int rw,
1469            int linearBufferLength) throws LlcpException {
1470        return mDeviceHost.createLlcpServerSocket(sap, sn, miu, rw, linearBufferLength);
1471    }
1472
1473    public void sendMockNdefTag(NdefMessage msg) {
1474        sendMessage(MSG_MOCK_NDEF, msg);
1475    }
1476
1477    public void routeAids(String aid, int route) {
1478        Message msg = mHandler.obtainMessage();
1479        msg.what = MSG_ROUTE_AID;
1480        msg.arg1 = route;
1481        msg.obj = aid;
1482        mHandler.sendMessage(msg);
1483    }
1484
1485    public void unrouteAids(String aid) {
1486        sendMessage(MSG_UNROUTE_AID, aid);
1487    }
1488
1489    public void commitRouting() {
1490        mHandler.sendEmptyMessage(MSG_COMMIT_ROUTING);
1491    }
1492
1493    public boolean sendData(byte[] data) {
1494        return mDeviceHost.sendRawFrame(data);
1495    }
1496
1497    void sendMessage(int what, Object obj) {
1498        Message msg = mHandler.obtainMessage();
1499        msg.what = what;
1500        msg.obj = obj;
1501        mHandler.sendMessage(msg);
1502    }
1503
1504    final class NfcServiceHandler extends Handler {
1505        @Override
1506        public void handleMessage(Message msg) {
1507            switch (msg.what) {
1508                case MSG_ROUTE_AID: {
1509                    int route = msg.arg1;
1510                    String aid = (String) msg.obj;
1511                    mDeviceHost.routeAid(hexStringToBytes(aid), route);
1512                    // Restart polling config
1513                    break;
1514                }
1515                case MSG_UNROUTE_AID: {
1516                    String aid = (String) msg.obj;
1517                    mDeviceHost.unrouteAid(hexStringToBytes(aid));
1518                    break;
1519                }
1520                case MSG_INVOKE_BEAM: {
1521                    mP2pLinkManager.onManualBeamInvoke((BeamShareData)msg.obj);
1522                    break;
1523                }
1524                case MSG_COMMIT_ROUTING: {
1525                    applyRouting(true);
1526                    break;
1527                }
1528                case MSG_MOCK_NDEF: {
1529                    NdefMessage ndefMsg = (NdefMessage) msg.obj;
1530                    Bundle extras = new Bundle();
1531                    extras.putParcelable(Ndef.EXTRA_NDEF_MSG, ndefMsg);
1532                    extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, 0);
1533                    extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, Ndef.NDEF_MODE_READ_ONLY);
1534                    extras.putInt(Ndef.EXTRA_NDEF_TYPE, Ndef.TYPE_OTHER);
1535                    Tag tag = Tag.createMockTag(new byte[]{0x00},
1536                            new int[]{TagTechnology.NDEF},
1537                            new Bundle[]{extras});
1538                    Log.d(TAG, "mock NDEF tag, starting corresponding activity");
1539                    Log.d(TAG, tag.toString());
1540                    boolean delivered = mNfcDispatcher.dispatchTag(tag);
1541                    if (delivered) {
1542                        playSound(SOUND_END);
1543                    } else {
1544                        playSound(SOUND_ERROR);
1545                    }
1546                    break;
1547                }
1548
1549                case MSG_NDEF_TAG:
1550                    if (DBG) Log.d(TAG, "Tag detected, notifying applications");
1551                    TagEndpoint tag = (TagEndpoint) msg.obj;
1552                    ReaderModeParams readerParams = null;
1553                    int presenceCheckDelay = DEFAULT_PRESENCE_CHECK_DELAY;
1554                    DeviceHost.TagDisconnectedCallback callback =
1555                            new DeviceHost.TagDisconnectedCallback() {
1556                                @Override
1557                                public void onTagDisconnected(long handle) {
1558                                    applyRouting(false);
1559                                }
1560                            };
1561                    synchronized (NfcService.this) {
1562                        readerParams = mReaderModeParams;
1563                    }
1564                    if (readerParams != null) {
1565                        presenceCheckDelay = readerParams.presenceCheckDelay;
1566                        if ((readerParams.flags & NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK) != 0) {
1567                            if (DBG) Log.d(TAG, "Skipping NDEF detection in reader mode");
1568                            tag.startPresenceChecking(presenceCheckDelay, callback);
1569                            dispatchTagEndpoint(tag, readerParams);
1570                            break;
1571                        }
1572                    }
1573                    if (readerParams == null ||
1574                            (readerParams.flags & NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS) == 0) {
1575                        playSound(SOUND_START);
1576                    }
1577                    if (tag.getConnectedTechnology() == TagTechnology.NFC_BARCODE) {
1578                        // When these tags start containing NDEF, they will require
1579                        // the stack to deal with them in a different way, since
1580                        // they are activated only really shortly.
1581                        // For now, don't consider NDEF on these.
1582                        if (DBG) Log.d(TAG, "Skipping NDEF detection for NFC Barcode");
1583                        tag.startPresenceChecking(presenceCheckDelay, callback);
1584                        dispatchTagEndpoint(tag, readerParams);
1585                        break;
1586                    }
1587                    NdefMessage ndefMsg = tag.findAndReadNdef();
1588
1589                    if (ndefMsg != null) {
1590                        tag.startPresenceChecking(presenceCheckDelay, callback);
1591                        dispatchTagEndpoint(tag, readerParams);
1592                    } else {
1593                        if (tag.reconnect()) {
1594                            tag.startPresenceChecking(presenceCheckDelay, callback);
1595                            dispatchTagEndpoint(tag, readerParams);
1596                        } else {
1597                            tag.disconnect();
1598                            playSound(SOUND_ERROR);
1599                        }
1600                    }
1601                    break;
1602                case MSG_LLCP_LINK_ACTIVATION:
1603                    if (mIsDebugBuild) {
1604                        Intent actIntent = new Intent(ACTION_LLCP_UP);
1605                        mContext.sendBroadcast(actIntent);
1606                    }
1607                    llcpActivated((NfcDepEndpoint) msg.obj);
1608                    break;
1609
1610                case MSG_LLCP_LINK_DEACTIVATED:
1611                    if (mIsDebugBuild) {
1612                        Intent deactIntent = new Intent(ACTION_LLCP_DOWN);
1613                        mContext.sendBroadcast(deactIntent);
1614                    }
1615                    NfcDepEndpoint device = (NfcDepEndpoint) msg.obj;
1616                    boolean needsDisconnect = false;
1617
1618                    Log.d(TAG, "LLCP Link Deactivated message. Restart polling loop.");
1619                    synchronized (NfcService.this) {
1620                        /* Check if the device has been already unregistered */
1621                        if (mObjectMap.remove(device.getHandle()) != null) {
1622                            /* Disconnect if we are initiator */
1623                            if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
1624                                if (DBG) Log.d(TAG, "disconnecting from target");
1625                                needsDisconnect = true;
1626                            } else {
1627                                if (DBG) Log.d(TAG, "not disconnecting from initiator");
1628                            }
1629                        }
1630                    }
1631                    if (needsDisconnect) {
1632                        device.disconnect();  // restarts polling loop
1633                    }
1634
1635                    mP2pLinkManager.onLlcpDeactivated();
1636                    break;
1637                case MSG_LLCP_LINK_FIRST_PACKET:
1638                    mP2pLinkManager.onLlcpFirstPacketReceived();
1639                    break;
1640                default:
1641                    Log.e(TAG, "Unknown message received");
1642                    break;
1643            }
1644        }
1645
1646        private boolean llcpActivated(NfcDepEndpoint device) {
1647            Log.d(TAG, "LLCP Activation message");
1648
1649            if (device.getMode() == NfcDepEndpoint.MODE_P2P_TARGET) {
1650                if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_TARGET");
1651                if (device.connect()) {
1652                    /* Check LLCP compliancy */
1653                    if (mDeviceHost.doCheckLlcp()) {
1654                        /* Activate LLCP Link */
1655                        if (mDeviceHost.doActivateLlcp()) {
1656                            if (DBG) Log.d(TAG, "Initiator Activate LLCP OK");
1657                            synchronized (NfcService.this) {
1658                                // Register P2P device
1659                                mObjectMap.put(device.getHandle(), device);
1660                            }
1661                            mP2pLinkManager.onLlcpActivated();
1662                            return true;
1663                        } else {
1664                            /* should not happen */
1665                            Log.w(TAG, "Initiator LLCP activation failed. Disconnect.");
1666                            device.disconnect();
1667                        }
1668                    } else {
1669                        if (DBG) Log.d(TAG, "Remote Target does not support LLCP. Disconnect.");
1670                        device.disconnect();
1671                    }
1672                } else {
1673                    if (DBG) Log.d(TAG, "Cannot connect remote Target. Polling loop restarted.");
1674                    /*
1675                     * The polling loop should have been restarted in failing
1676                     * doConnect
1677                     */
1678                }
1679            } else if (device.getMode() == NfcDepEndpoint.MODE_P2P_INITIATOR) {
1680                if (DBG) Log.d(TAG, "NativeP2pDevice.MODE_P2P_INITIATOR");
1681                /* Check LLCP compliancy */
1682                if (mDeviceHost.doCheckLlcp()) {
1683                    /* Activate LLCP Link */
1684                    if (mDeviceHost.doActivateLlcp()) {
1685                        if (DBG) Log.d(TAG, "Target Activate LLCP OK");
1686                        synchronized (NfcService.this) {
1687                            // Register P2P device
1688                            mObjectMap.put(device.getHandle(), device);
1689                        }
1690                        mP2pLinkManager.onLlcpActivated();
1691                        return true;
1692                    }
1693                } else {
1694                    Log.w(TAG, "checkLlcp failed");
1695                }
1696            }
1697
1698            return false;
1699        }
1700
1701        private void dispatchTagEndpoint(TagEndpoint tagEndpoint, ReaderModeParams readerParams) {
1702            Tag tag = new Tag(tagEndpoint.getUid(), tagEndpoint.getTechList(),
1703                    tagEndpoint.getTechExtras(), tagEndpoint.getHandle(), mNfcTagService);
1704            registerTagObject(tagEndpoint);
1705            if (readerParams != null) {
1706                try {
1707                    if ((readerParams.flags & NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS) == 0) {
1708                        playSound(SOUND_END);
1709                    }
1710                    if (readerParams.callback != null) {
1711                        readerParams.callback.onTagDiscovered(tag);
1712                        return;
1713                    } else {
1714                        // Follow normal dispatch below
1715                    }
1716                } catch (RemoteException e) {
1717                    Log.e(TAG, "Reader mode remote has died, falling back.", e);
1718                    // Intentional fall-through
1719                } catch (Exception e) {
1720                    // Catch any other exception
1721                    Log.e(TAG, "App exception, not dispatching.", e);
1722                    return;
1723                }
1724            }
1725            if (!mNfcDispatcher.dispatchTag(tag)) {
1726                unregisterObject(tagEndpoint.getHandle());
1727                playSound(SOUND_ERROR);
1728            } else {
1729                playSound(SOUND_END);
1730            }
1731        }
1732    }
1733
1734    private NfcServiceHandler mHandler = new NfcServiceHandler();
1735
1736    class ApplyRoutingTask extends AsyncTask<Integer, Void, Void> {
1737        @Override
1738        protected Void doInBackground(Integer... params) {
1739            synchronized (NfcService.this) {
1740                if (params == null || params.length != 1) {
1741                    // force apply current routing
1742                    applyRouting(true);
1743                    return null;
1744                }
1745                mScreenState = params[0].intValue();
1746
1747                mRoutingWakeLock.acquire();
1748                try {
1749                    applyRouting(false);
1750                } finally {
1751                    mRoutingWakeLock.release();
1752                }
1753                return null;
1754            }
1755        }
1756    }
1757
1758    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
1759        @Override
1760        public void onReceive(Context context, Intent intent) {
1761            String action = intent.getAction();
1762            if (action.equals(Intent.ACTION_SCREEN_ON)
1763                    || action.equals(Intent.ACTION_SCREEN_OFF)
1764                    || action.equals(Intent.ACTION_USER_PRESENT)) {
1765                // Perform applyRouting() in AsyncTask to serialize blocking calls
1766                int screenState = ScreenStateHelper.SCREEN_STATE_OFF;
1767                if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1768                    screenState = ScreenStateHelper.SCREEN_STATE_OFF;
1769                } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
1770                    screenState = mKeyguard.isKeyguardLocked()
1771                            ? ScreenStateHelper.SCREEN_STATE_ON_LOCKED
1772                            : ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED;
1773                } else if (action.equals(Intent.ACTION_USER_PRESENT)) {
1774                    screenState = ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED;
1775                }
1776                new ApplyRoutingTask().execute(Integer.valueOf(screenState));
1777            } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
1778                boolean isAirplaneModeOn = intent.getBooleanExtra("state", false);
1779                // Query the airplane mode from Settings.System just to make sure that
1780                // some random app is not sending this intent
1781                if (isAirplaneModeOn != isAirplaneModeOn()) {
1782                    return;
1783                }
1784                if (!mIsAirplaneSensitive) {
1785                    return;
1786                }
1787                mPrefsEditor.putBoolean(PREF_AIRPLANE_OVERRIDE, false);
1788                mPrefsEditor.apply();
1789                if (isAirplaneModeOn) {
1790                    new EnableDisableTask().execute(TASK_DISABLE);
1791                } else if (!isAirplaneModeOn && mPrefs.getBoolean(PREF_NFC_ON, NFC_ON_DEFAULT)) {
1792                    new EnableDisableTask().execute(TASK_ENABLE);
1793                }
1794            } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
1795                int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
1796                synchronized (this) {
1797                    mUserId = userId;
1798                }
1799                mP2pLinkManager.onUserSwitched(getUserId());
1800                if (mIsHceCapable) {
1801                    mCardEmulationManager.onUserSwitched(getUserId());
1802                }
1803            }
1804        }
1805    };
1806
1807    /**
1808     * Returns true if airplane mode is currently on
1809     */
1810    boolean isAirplaneModeOn() {
1811        return Settings.System.getInt(mContentResolver,
1812                Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
1813    }
1814
1815    /**
1816     * for debugging only - no i18n
1817     */
1818    static String stateToString(int state) {
1819        switch (state) {
1820            case NfcAdapter.STATE_OFF:
1821                return "off";
1822            case NfcAdapter.STATE_TURNING_ON:
1823                return "turning on";
1824            case NfcAdapter.STATE_ON:
1825                return "on";
1826            case NfcAdapter.STATE_TURNING_OFF:
1827                return "turning off";
1828            default:
1829                return "<error>";
1830        }
1831    }
1832
1833    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1834        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
1835                != PackageManager.PERMISSION_GRANTED) {
1836            pw.println("Permission Denial: can't dump nfc from from pid="
1837                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
1838                    + " without permission " + android.Manifest.permission.DUMP);
1839            return;
1840        }
1841
1842        synchronized (this) {
1843            pw.println("mState=" + stateToString(mState));
1844            pw.println("mIsZeroClickRequested=" + mIsNdefPushEnabled);
1845            pw.println("mScreenState=" + ScreenStateHelper.screenStateToString(mScreenState));
1846            pw.println("mIsAirplaneSensitive=" + mIsAirplaneSensitive);
1847            pw.println("mIsAirplaneToggleable=" + mIsAirplaneToggleable);
1848            pw.println(mCurrentDiscoveryParameters);
1849            mP2pLinkManager.dump(fd, pw, args);
1850            if (mIsHceCapable) {
1851                mCardEmulationManager.dump(fd, pw, args);
1852            }
1853            mNfcDispatcher.dump(fd, pw, args);
1854            pw.println(mDeviceHost.dump());
1855        }
1856    }
1857}
1858