• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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 package com.android.nfc.cardemulation;
17 
18 import java.io.FileDescriptor;
19 import java.io.PrintWriter;
20 import java.util.List;
21 
22 import android.content.ComponentName;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.nfc.INfcCardEmulation;
26 import android.nfc.INfcFCardEmulation;
27 import android.nfc.cardemulation.AidGroup;
28 import android.nfc.cardemulation.ApduServiceInfo;
29 import android.nfc.cardemulation.NfcFServiceInfo;
30 import android.nfc.cardemulation.CardEmulation;
31 import android.nfc.cardemulation.NfcFCardEmulation;
32 import android.os.Binder;
33 import android.os.RemoteException;
34 import android.os.UserHandle;
35 import android.os.PowerManager;
36 import android.os.SystemClock;
37 import android.provider.Settings;
38 import android.util.Log;
39 
40 import com.android.nfc.NfcPermissions;
41 import com.android.nfc.NfcService;
42 import com.android.nfc.cardemulation.RegisteredServicesCache;
43 import com.android.nfc.cardemulation.RegisteredNfcFServicesCache;
44 
45 /**
46  * CardEmulationManager is the central entity
47  * responsible for delegating to individual components
48  * implementing card emulation:
49  * - RegisteredServicesCache keeping track of HCE and SE services on the device
50  * - RegisteredNfcFServicesCache keeping track of HCE-F services on the device
51  * - RegisteredAidCache keeping track of AIDs registered by those services and manages
52  *   the routing table in the NFCC.
53  * - RegisteredT3tIdentifiersCache keeping track of T3T Identifier registered by
54  *   those services and manages the routing table in the NFCC.
55  * - HostEmulationManager handles incoming APDUs for the host and forwards to HCE
56  *   services as necessary.
57  * - HostNfcFEmulationManager handles incoming NFC-F packets for the host and
58  *   forwards to HCE-F services as necessary.
59  */
60 public class CardEmulationManager implements RegisteredServicesCache.Callback,
61         RegisteredNfcFServicesCache.Callback, PreferredServices.Callback,
62         EnabledNfcFServices.Callback {
63     static final String TAG = "CardEmulationManager";
64     static final boolean DBG = false;
65 
66     static final int NFC_HCE_APDU = 0x01;
67     static final int NFC_HCE_NFCF = 0x04;
68 
69     final RegisteredAidCache mAidCache;
70     final RegisteredT3tIdentifiersCache mT3tIdentifiersCache;
71     final RegisteredServicesCache mServiceCache;
72     final RegisteredNfcFServicesCache mNfcFServicesCache;
73     final HostEmulationManager mHostEmulationManager;
74     final HostNfcFEmulationManager mHostNfcFEmulationManager;
75     final PreferredServices mPreferredServices;
76     final EnabledNfcFServices mEnabledNfcFServices;
77     final Context mContext;
78     final CardEmulationInterface mCardEmulationInterface;
79     final NfcFCardEmulationInterface mNfcFCardEmulationInterface;
80     final PowerManager mPowerManager;
81 
CardEmulationManager(Context context)82     public CardEmulationManager(Context context) {
83         mContext = context;
84         mCardEmulationInterface = new CardEmulationInterface();
85         mNfcFCardEmulationInterface = new NfcFCardEmulationInterface();
86         mAidCache = new RegisteredAidCache(context);
87         mT3tIdentifiersCache = new RegisteredT3tIdentifiersCache(context);
88         mHostEmulationManager = new HostEmulationManager(context, mAidCache);
89         mHostNfcFEmulationManager = new HostNfcFEmulationManager(context, mT3tIdentifiersCache);
90         mServiceCache = new RegisteredServicesCache(context, this);
91         mNfcFServicesCache = new RegisteredNfcFServicesCache(context, this);
92         mPreferredServices = new PreferredServices(context, mServiceCache, mAidCache, this);
93         mEnabledNfcFServices = new EnabledNfcFServices(
94                 context, mNfcFServicesCache, mT3tIdentifiersCache, this);
95         mServiceCache.initialize();
96         mNfcFServicesCache.initialize();
97         mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
98     }
99 
getNfcCardEmulationInterface()100     public INfcCardEmulation getNfcCardEmulationInterface() {
101         return mCardEmulationInterface;
102     }
103 
getNfcFCardEmulationInterface()104     public INfcFCardEmulation getNfcFCardEmulationInterface() {
105         return mNfcFCardEmulationInterface;
106     }
107 
108 
onHostCardEmulationActivated(int technology)109     public void onHostCardEmulationActivated(int technology) {
110         if (mPowerManager != null) {
111             mPowerManager.userActivity(SystemClock.uptimeMillis(), PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
112         }
113         if (technology == NFC_HCE_APDU) {
114             mHostEmulationManager.onHostEmulationActivated();
115             mPreferredServices.onHostEmulationActivated();
116         } else if (technology == NFC_HCE_NFCF) {
117             mHostNfcFEmulationManager.onHostEmulationActivated();
118             mNfcFServicesCache.onHostEmulationActivated();
119             mEnabledNfcFServices.onHostEmulationActivated();
120         }
121     }
122 
onHostCardEmulationData(int technology, byte[] data)123     public void onHostCardEmulationData(int technology, byte[] data) {
124         if (mPowerManager != null) {
125             mPowerManager.userActivity(SystemClock.uptimeMillis(), PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
126         }
127         if (technology == NFC_HCE_APDU) {
128             mHostEmulationManager.onHostEmulationData(data);
129         } else if (technology == NFC_HCE_NFCF) {
130             mHostNfcFEmulationManager.onHostEmulationData(data);
131         }
132     }
133 
onHostCardEmulationDeactivated(int technology)134     public void onHostCardEmulationDeactivated(int technology) {
135         if (technology == NFC_HCE_APDU) {
136             mHostEmulationManager.onHostEmulationDeactivated();
137             mPreferredServices.onHostEmulationDeactivated();
138         } else if (technology == NFC_HCE_NFCF) {
139             mHostNfcFEmulationManager.onHostEmulationDeactivated();
140             mNfcFServicesCache.onHostEmulationDeactivated();
141             mEnabledNfcFServices.onHostEmulationDeactivated();
142         }
143     }
144 
onOffHostAidSelected()145     public void onOffHostAidSelected() {
146         mHostEmulationManager.onOffHostAidSelected();
147     }
148 
onUserSwitched(int userId)149     public void onUserSwitched(int userId) {
150         // for HCE
151         mServiceCache.invalidateCache(userId);
152         mPreferredServices.onUserSwitched(userId);
153         // for HCE-F
154         mHostNfcFEmulationManager.onUserSwitched();
155         mT3tIdentifiersCache.onUserSwitched();
156         mEnabledNfcFServices.onUserSwitched(userId);
157         mNfcFServicesCache.onUserSwitched();
158         mNfcFServicesCache.invalidateCache(userId);
159     }
160 
onNfcEnabled()161     public void onNfcEnabled() {
162         // for HCE
163         mAidCache.onNfcEnabled();
164         // for HCE-F
165         mT3tIdentifiersCache.onNfcEnabled();
166     }
167 
onNfcDisabled()168     public void onNfcDisabled() {
169         // for HCE
170         mAidCache.onNfcDisabled();
171         // for HCE-F
172         mHostNfcFEmulationManager.onNfcDisabled();
173         mNfcFServicesCache.onNfcDisabled();
174         mT3tIdentifiersCache.onNfcDisabled();
175         mEnabledNfcFServices.onNfcDisabled();
176     }
177 
dump(FileDescriptor fd, PrintWriter pw, String[] args)178     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
179         mServiceCache.dump(fd, pw, args);
180         mNfcFServicesCache.dump(fd, pw ,args);
181         mPreferredServices.dump(fd, pw, args);
182         mEnabledNfcFServices.dump(fd, pw, args);
183         mAidCache.dump(fd, pw, args);
184         mT3tIdentifiersCache.dump(fd, pw, args);
185         mHostEmulationManager.dump(fd, pw, args);
186         mHostNfcFEmulationManager.dump(fd, pw, args);
187     }
188 
189     @Override
onServicesUpdated(int userId, List<ApduServiceInfo> services)190     public void onServicesUpdated(int userId, List<ApduServiceInfo> services) {
191         // Verify defaults are still sane
192         verifyDefaults(userId, services);
193         // Update the AID cache
194         mAidCache.onServicesUpdated(userId, services);
195         // Update the preferred services list
196         mPreferredServices.onServicesUpdated();
197     }
198 
199     @Override
onNfcFServicesUpdated(int userId, List<NfcFServiceInfo> services)200     public void onNfcFServicesUpdated(int userId, List<NfcFServiceInfo> services) {
201         // Update the T3T identifier cache
202         mT3tIdentifiersCache.onServicesUpdated(userId, services);
203         // Update the enabled services list
204         mEnabledNfcFServices.onServicesUpdated();
205     }
206 
verifyDefaults(int userId, List<ApduServiceInfo> services)207     void verifyDefaults(int userId, List<ApduServiceInfo> services) {
208         ComponentName defaultPaymentService =
209                 getDefaultServiceForCategory(userId, CardEmulation.CATEGORY_PAYMENT, false);
210         if (DBG) Log.d(TAG, "Current default: " + defaultPaymentService);
211         if (defaultPaymentService == null) {
212             // A payment service may have been removed, leaving only one;
213             // in that case, automatically set that app as default.
214             int numPaymentServices = 0;
215             ComponentName lastFoundPaymentService = null;
216             for (ApduServiceInfo service : services) {
217                 if (service.hasCategory(CardEmulation.CATEGORY_PAYMENT))  {
218                     numPaymentServices++;
219                     lastFoundPaymentService = service.getComponent();
220                 }
221             }
222             if (numPaymentServices > 1) {
223                 // More than one service left, leave default unset
224                 if (DBG) Log.d(TAG, "No default set, more than one service left.");
225             } else if (numPaymentServices == 1) {
226                 // Make single found payment service the default
227                 if (DBG) Log.d(TAG, "No default set, making single service default.");
228                 setDefaultServiceForCategoryChecked(userId, lastFoundPaymentService,
229                         CardEmulation.CATEGORY_PAYMENT);
230             } else {
231                 // No payment services left, leave default at null
232                 if (DBG) Log.d(TAG, "No default set, last payment service removed.");
233             }
234         }
235     }
236 
getDefaultServiceForCategory(int userId, String category, boolean validateInstalled)237     ComponentName getDefaultServiceForCategory(int userId, String category,
238              boolean validateInstalled) {
239         if (!CardEmulation.CATEGORY_PAYMENT.equals(category)) {
240             Log.e(TAG, "Not allowing defaults for category " + category);
241             return null;
242         }
243         // Load current payment default from settings
244         String name = Settings.Secure.getStringForUser(
245                 mContext.getContentResolver(), Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT,
246                 userId);
247         if (name != null) {
248             ComponentName service = ComponentName.unflattenFromString(name);
249             if (!validateInstalled || service == null) {
250                 return service;
251             } else {
252                 return mServiceCache.hasService(userId, service) ? service : null;
253              }
254         } else {
255             return null;
256         }
257     }
258 
setDefaultServiceForCategoryChecked(int userId, ComponentName service, String category)259     boolean setDefaultServiceForCategoryChecked(int userId, ComponentName service,
260             String category) {
261         if (!CardEmulation.CATEGORY_PAYMENT.equals(category)) {
262             Log.e(TAG, "Not allowing defaults for category " + category);
263             return false;
264         }
265         // TODO Not really nice to be writing to Settings.Secure here...
266         // ideally we overlay our local changes over whatever is in
267         // Settings.Secure
268         if (service == null || mServiceCache.hasService(userId, service)) {
269             Settings.Secure.putStringForUser(mContext.getContentResolver(),
270                     Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT,
271                     service != null ? service.flattenToString() : null, userId);
272         } else {
273             Log.e(TAG, "Could not find default service to make default: " + service);
274         }
275         return true;
276     }
277 
isServiceRegistered(int userId, ComponentName service)278     boolean isServiceRegistered(int userId, ComponentName service) {
279         boolean serviceFound = mServiceCache.hasService(userId, service);
280         if (!serviceFound) {
281             // If we don't know about this service yet, it may have just been enabled
282             // using PackageManager.setComponentEnabledSetting(). The PackageManager
283             // broadcasts are delayed by 10 seconds in that scenario, which causes
284             // calls to our APIs referencing that service to fail.
285             // Hence, update the cache in case we don't know about the service.
286             if (DBG) Log.d(TAG, "Didn't find passed in service, invalidating cache.");
287             mServiceCache.invalidateCache(userId);
288         }
289         return mServiceCache.hasService(userId, service);
290     }
291 
isNfcFServiceInstalled(int userId, ComponentName service)292     boolean isNfcFServiceInstalled(int userId, ComponentName service) {
293         boolean serviceFound = mNfcFServicesCache.hasService(userId, service);
294         if (!serviceFound) {
295             // If we don't know about this service yet, it may have just been enabled
296             // using PackageManager.setComponentEnabledSetting(). The PackageManager
297             // broadcasts are delayed by 10 seconds in that scenario, which causes
298             // calls to our APIs referencing that service to fail.
299             // Hence, update the cache in case we don't know about the service.
300             if (DBG) Log.d(TAG, "Didn't find passed in service, invalidating cache.");
301             mNfcFServicesCache.invalidateCache(userId);
302         }
303         return mNfcFServicesCache.hasService(userId, service);
304     }
305 
306     /**
307      * Returns whether a service in this package is preferred,
308      * either because it's the default payment app or it's running
309      * in the foreground.
310      */
packageHasPreferredService(String packageName)311     public boolean packageHasPreferredService(String packageName) {
312         return mPreferredServices.packageHasPreferredService(packageName);
313     }
314 
315     /**
316      * This class implements the application-facing APIs and are called
317      * from binder. All calls must be permission-checked.
318      */
319     final class CardEmulationInterface extends INfcCardEmulation.Stub {
320         @Override
isDefaultServiceForCategory(int userId, ComponentName service, String category)321         public boolean isDefaultServiceForCategory(int userId, ComponentName service,
322                 String category) {
323             NfcPermissions.enforceUserPermissions(mContext);
324             NfcPermissions.validateUserId(userId);
325             if (!isServiceRegistered(userId, service)) {
326                 return false;
327             }
328             ComponentName defaultService =
329                     getDefaultServiceForCategory(userId, category, true);
330             return (defaultService != null && defaultService.equals(service));
331         }
332 
333         @Override
isDefaultServiceForAid(int userId, ComponentName service, String aid)334         public boolean isDefaultServiceForAid(int userId,
335                 ComponentName service, String aid) throws RemoteException {
336             NfcPermissions.validateUserId(userId);
337             NfcPermissions.enforceUserPermissions(mContext);
338             if (!isServiceRegistered(userId, service)) {
339                 return false;
340             }
341             return mAidCache.isDefaultServiceForAid(userId, service, aid);
342         }
343 
344         @Override
setDefaultServiceForCategory(int userId, ComponentName service, String category)345         public boolean setDefaultServiceForCategory(int userId,
346                 ComponentName service, String category) throws RemoteException {
347             NfcPermissions.validateUserId(userId);
348             NfcPermissions.enforceAdminPermissions(mContext);
349             if (!isServiceRegistered(userId, service)) {
350                 return false;
351             }
352             return setDefaultServiceForCategoryChecked(userId, service, category);
353         }
354 
355         @Override
setDefaultForNextTap(int userId, ComponentName service)356         public boolean setDefaultForNextTap(int userId, ComponentName service)
357                 throws RemoteException {
358             NfcPermissions.validateUserId(userId);
359             NfcPermissions.enforceAdminPermissions(mContext);
360             if (service != null && !isServiceRegistered(userId, service)) {
361                 return false;
362             }
363             return mPreferredServices.setDefaultForNextTap(service);
364         }
365 
366         @Override
registerAidGroupForService(int userId, ComponentName service, AidGroup aidGroup)367         public boolean registerAidGroupForService(int userId,
368                 ComponentName service, AidGroup aidGroup) throws RemoteException {
369             NfcPermissions.validateUserId(userId);
370             NfcPermissions.enforceUserPermissions(mContext);
371             if (!isServiceRegistered(userId, service)) {
372                 return false;
373             }
374             return mServiceCache.registerAidGroupForService(userId, Binder.getCallingUid(), service,
375                     aidGroup);
376         }
377 
378         @Override
getAidGroupForService(int userId, ComponentName service, String category)379         public AidGroup getAidGroupForService(int userId,
380                 ComponentName service, String category) throws RemoteException {
381             NfcPermissions.validateUserId(userId);
382             NfcPermissions.enforceUserPermissions(mContext);
383             if (!isServiceRegistered(userId, service)) {
384                 return null;
385             }
386             return mServiceCache.getAidGroupForService(userId, Binder.getCallingUid(), service,
387                     category);
388         }
389 
390         @Override
removeAidGroupForService(int userId, ComponentName service, String category)391         public boolean removeAidGroupForService(int userId,
392                 ComponentName service, String category) throws RemoteException {
393             NfcPermissions.validateUserId(userId);
394             NfcPermissions.enforceUserPermissions(mContext);
395             if (!isServiceRegistered(userId, service)) {
396                 return false;
397             }
398             return mServiceCache.removeAidGroupForService(userId, Binder.getCallingUid(), service,
399                     category);
400         }
401 
402         @Override
getServices(int userId, String category)403         public List<ApduServiceInfo> getServices(int userId, String category)
404                 throws RemoteException {
405             NfcPermissions.validateUserId(userId);
406             NfcPermissions.enforceAdminPermissions(mContext);
407             return mServiceCache.getServicesForCategory(userId, category);
408         }
409 
410         @Override
setPreferredService(ComponentName service)411         public boolean setPreferredService(ComponentName service)
412                 throws RemoteException {
413             NfcPermissions.enforceUserPermissions(mContext);
414             if (!isServiceRegistered(UserHandle.getCallingUserId(), service)) {
415                 Log.e(TAG, "setPreferredService: unknown component.");
416                 return false;
417             }
418             return mPreferredServices.registerPreferredForegroundService(service,
419                     Binder.getCallingUid());
420         }
421 
422         @Override
unsetPreferredService()423         public boolean unsetPreferredService() throws RemoteException {
424             NfcPermissions.enforceUserPermissions(mContext);
425             return mPreferredServices.unregisteredPreferredForegroundService(
426                     Binder.getCallingUid());
427         }
428 
429         @Override
supportsAidPrefixRegistration()430         public boolean supportsAidPrefixRegistration() throws RemoteException {
431             return mAidCache.supportsAidPrefixRegistration();
432         }
433     }
434 
435     /**
436      * This class implements the application-facing APIs and are called
437      * from binder. All calls must be permission-checked.
438      */
439     final class NfcFCardEmulationInterface extends INfcFCardEmulation.Stub {
440         @Override
getSystemCodeForService(int userId, ComponentName service)441         public String getSystemCodeForService(int userId, ComponentName service)
442                 throws RemoteException {
443             NfcPermissions.validateUserId(userId);
444             NfcPermissions.enforceUserPermissions(mContext);
445             if (!isNfcFServiceInstalled(userId, service)) {
446                 return null;
447             }
448             return mNfcFServicesCache.getSystemCodeForService(
449                     userId, Binder.getCallingUid(), service);
450         }
451 
452         @Override
registerSystemCodeForService(int userId, ComponentName service, String systemCode)453         public boolean registerSystemCodeForService(int userId, ComponentName service,
454                 String systemCode)
455                 throws RemoteException {
456             NfcPermissions.validateUserId(userId);
457             NfcPermissions.enforceUserPermissions(mContext);
458             if (!isNfcFServiceInstalled(userId, service)) {
459                 return false;
460             }
461             return mNfcFServicesCache.registerSystemCodeForService(
462                     userId, Binder.getCallingUid(), service, systemCode);
463         }
464 
465         @Override
removeSystemCodeForService(int userId, ComponentName service)466         public boolean removeSystemCodeForService(int userId, ComponentName service)
467                 throws RemoteException {
468             NfcPermissions.validateUserId(userId);
469             NfcPermissions.enforceUserPermissions(mContext);
470             if (!isNfcFServiceInstalled(userId, service)) {
471                 return false;
472             }
473             return mNfcFServicesCache.removeSystemCodeForService(
474                     userId, Binder.getCallingUid(), service);
475         }
476 
477         @Override
getNfcid2ForService(int userId, ComponentName service)478         public String getNfcid2ForService(int userId, ComponentName service)
479                 throws RemoteException {
480             NfcPermissions.validateUserId(userId);
481             NfcPermissions.enforceUserPermissions(mContext);
482             if (!isNfcFServiceInstalled(userId, service)) {
483                 return null;
484             }
485             return mNfcFServicesCache.getNfcid2ForService(
486                     userId, Binder.getCallingUid(), service);
487         }
488 
489         @Override
setNfcid2ForService(int userId, ComponentName service, String nfcid2)490         public boolean setNfcid2ForService(int userId,
491                 ComponentName service, String nfcid2) throws RemoteException {
492             NfcPermissions.validateUserId(userId);
493             NfcPermissions.enforceUserPermissions(mContext);
494             if (!isNfcFServiceInstalled(userId, service)) {
495                 return false;
496             }
497             return mNfcFServicesCache.setNfcid2ForService(
498                     userId, Binder.getCallingUid(), service, nfcid2);
499         }
500 
501         @Override
enableNfcFForegroundService(ComponentName service)502         public boolean enableNfcFForegroundService(ComponentName service)
503                 throws RemoteException {
504             NfcPermissions.enforceUserPermissions(mContext);
505             if (isNfcFServiceInstalled(UserHandle.getCallingUserId(), service)) {
506                 return mEnabledNfcFServices.registerEnabledForegroundService(service,
507                         Binder.getCallingUid());
508             }
509             return false;
510         }
511 
512         @Override
disableNfcFForegroundService()513         public boolean disableNfcFForegroundService() throws RemoteException {
514             NfcPermissions.enforceUserPermissions(mContext);
515             return mEnabledNfcFServices.unregisteredEnabledForegroundService(
516                     Binder.getCallingUid());
517         }
518 
519         @Override
getNfcFServices(int userId)520         public List<NfcFServiceInfo> getNfcFServices(int userId)
521                 throws RemoteException {
522             NfcPermissions.validateUserId(userId);
523             NfcPermissions.enforceUserPermissions(mContext);
524             return mNfcFServicesCache.getServices(userId);
525         }
526 
527         @Override
getMaxNumOfRegisterableSystemCodes()528         public int getMaxNumOfRegisterableSystemCodes()
529                 throws RemoteException {
530             NfcPermissions.enforceUserPermissions(mContext);
531             return NfcService.getInstance().getLfT3tMax();
532         }
533     }
534 
535     @Override
onPreferredPaymentServiceChanged(ComponentName service)536     public void onPreferredPaymentServiceChanged(ComponentName service) {
537         mAidCache.onPreferredPaymentServiceChanged(service);
538         mHostEmulationManager.onPreferredPaymentServiceChanged(service);
539     }
540 
541     @Override
onPreferredForegroundServiceChanged(ComponentName service)542     public void onPreferredForegroundServiceChanged(ComponentName service) {
543         mAidCache.onPreferredForegroundServiceChanged(service);
544         mHostEmulationManager.onPreferredForegroundServiceChanged(service);
545     }
546 
547     @Override
onEnabledForegroundNfcFServiceChanged(ComponentName service)548     public void onEnabledForegroundNfcFServiceChanged(ComponentName service) {
549         mT3tIdentifiersCache.onEnabledForegroundNfcFServiceChanged(service);
550         mHostNfcFEmulationManager.onEnabledForegroundNfcFServiceChanged(service);
551     }
552 }
553