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