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