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