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