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