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