• 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.invalidateCache(userId);
158     }
159 
onNfcEnabled()160     public void onNfcEnabled() {
161         // for HCE
162         mAidCache.onNfcEnabled();
163         // for HCE-F
164         mT3tIdentifiersCache.onNfcEnabled();
165     }
166 
onNfcDisabled()167     public void onNfcDisabled() {
168         // for HCE
169         mAidCache.onNfcDisabled();
170         // for HCE-F
171         mHostNfcFEmulationManager.onNfcDisabled();
172         mNfcFServicesCache.onNfcDisabled();
173         mT3tIdentifiersCache.onNfcDisabled();
174         mEnabledNfcFServices.onNfcDisabled();
175     }
176 
dump(FileDescriptor fd, PrintWriter pw, String[] args)177     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
178         mServiceCache.dump(fd, pw, args);
179         mNfcFServicesCache.dump(fd, pw ,args);
180         mPreferredServices.dump(fd, pw, args);
181         mEnabledNfcFServices.dump(fd, pw, args);
182         mAidCache.dump(fd, pw, args);
183         mT3tIdentifiersCache.dump(fd, pw, args);
184         mHostEmulationManager.dump(fd, pw, args);
185         mHostNfcFEmulationManager.dump(fd, pw, args);
186     }
187 
188     @Override
onServicesUpdated(int userId, List<ApduServiceInfo> services)189     public void onServicesUpdated(int userId, List<ApduServiceInfo> services) {
190         // Verify defaults are still sane
191         verifyDefaults(userId, services);
192         // Update the AID cache
193         mAidCache.onServicesUpdated(userId, services);
194         // Update the preferred services list
195         mPreferredServices.onServicesUpdated();
196     }
197 
198     @Override
onNfcFServicesUpdated(int userId, List<NfcFServiceInfo> services)199     public void onNfcFServicesUpdated(int userId, List<NfcFServiceInfo> services) {
200         // Update the T3T identifier cache
201         mT3tIdentifiersCache.onServicesUpdated(userId, services);
202         // Update the enabled services list
203         mEnabledNfcFServices.onServicesUpdated();
204     }
205 
verifyDefaults(int userId, List<ApduServiceInfo> services)206     void verifyDefaults(int userId, List<ApduServiceInfo> services) {
207         ComponentName defaultPaymentService =
208                 getDefaultServiceForCategory(userId, CardEmulation.CATEGORY_PAYMENT, false);
209         if (DBG) Log.d(TAG, "Current default: " + defaultPaymentService);
210         if (defaultPaymentService == null) {
211             // A payment service may have been removed, leaving only one;
212             // in that case, automatically set that app as default.
213             int numPaymentServices = 0;
214             ComponentName lastFoundPaymentService = null;
215             for (ApduServiceInfo service : services) {
216                 if (service.hasCategory(CardEmulation.CATEGORY_PAYMENT))  {
217                     numPaymentServices++;
218                     lastFoundPaymentService = service.getComponent();
219                 }
220             }
221             if (numPaymentServices > 1) {
222                 // More than one service left, leave default unset
223                 if (DBG) Log.d(TAG, "No default set, more than one service left.");
224             } else if (numPaymentServices == 1) {
225                 // Make single found payment service the default
226                 if (DBG) Log.d(TAG, "No default set, making single service default.");
227                 setDefaultServiceForCategoryChecked(userId, lastFoundPaymentService,
228                         CardEmulation.CATEGORY_PAYMENT);
229             } else {
230                 // No payment services left, leave default at null
231                 if (DBG) Log.d(TAG, "No default set, last payment service removed.");
232             }
233         }
234     }
235 
getDefaultServiceForCategory(int userId, String category, boolean validateInstalled)236     ComponentName getDefaultServiceForCategory(int userId, String category,
237              boolean validateInstalled) {
238         if (!CardEmulation.CATEGORY_PAYMENT.equals(category)) {
239             Log.e(TAG, "Not allowing defaults for category " + category);
240             return null;
241         }
242         // Load current payment default from settings
243         String name = Settings.Secure.getStringForUser(
244                 mContext.getContentResolver(), Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT,
245                 userId);
246         if (name != null) {
247             ComponentName service = ComponentName.unflattenFromString(name);
248             if (!validateInstalled || service == null) {
249                 return service;
250             } else {
251                 return mServiceCache.hasService(userId, service) ? service : null;
252              }
253         } else {
254             return null;
255         }
256     }
257 
setDefaultServiceForCategoryChecked(int userId, ComponentName service, String category)258     boolean setDefaultServiceForCategoryChecked(int userId, ComponentName service,
259             String category) {
260         if (!CardEmulation.CATEGORY_PAYMENT.equals(category)) {
261             Log.e(TAG, "Not allowing defaults for category " + category);
262             return false;
263         }
264         // TODO Not really nice to be writing to Settings.Secure here...
265         // ideally we overlay our local changes over whatever is in
266         // Settings.Secure
267         if (service == null || mServiceCache.hasService(userId, service)) {
268             Settings.Secure.putStringForUser(mContext.getContentResolver(),
269                     Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT,
270                     service != null ? service.flattenToString() : null, userId);
271         } else {
272             Log.e(TAG, "Could not find default service to make default: " + service);
273         }
274         return true;
275     }
276 
isServiceRegistered(int userId, ComponentName service)277     boolean isServiceRegistered(int userId, ComponentName service) {
278         boolean serviceFound = mServiceCache.hasService(userId, service);
279         if (!serviceFound) {
280             // If we don't know about this service yet, it may have just been enabled
281             // using PackageManager.setComponentEnabledSetting(). The PackageManager
282             // broadcasts are delayed by 10 seconds in that scenario, which causes
283             // calls to our APIs referencing that service to fail.
284             // Hence, update the cache in case we don't know about the service.
285             if (DBG) Log.d(TAG, "Didn't find passed in service, invalidating cache.");
286             mServiceCache.invalidateCache(userId);
287         }
288         return mServiceCache.hasService(userId, service);
289     }
290 
isNfcFServiceInstalled(int userId, ComponentName service)291     boolean isNfcFServiceInstalled(int userId, ComponentName service) {
292         boolean serviceFound = mNfcFServicesCache.hasService(userId, service);
293         if (!serviceFound) {
294             // If we don't know about this service yet, it may have just been enabled
295             // using PackageManager.setComponentEnabledSetting(). The PackageManager
296             // broadcasts are delayed by 10 seconds in that scenario, which causes
297             // calls to our APIs referencing that service to fail.
298             // Hence, update the cache in case we don't know about the service.
299             if (DBG) Log.d(TAG, "Didn't find passed in service, invalidating cache.");
300             mNfcFServicesCache.invalidateCache(userId);
301         }
302         return mNfcFServicesCache.hasService(userId, service);
303     }
304 
305     /**
306      * Returns whether a service in this package is preferred,
307      * either because it's the default payment app or it's running
308      * in the foreground.
309      */
packageHasPreferredService(String packageName)310     public boolean packageHasPreferredService(String packageName) {
311         return mPreferredServices.packageHasPreferredService(packageName);
312     }
313 
314     /**
315      * This class implements the application-facing APIs and are called
316      * from binder. All calls must be permission-checked.
317      */
318     final class CardEmulationInterface extends INfcCardEmulation.Stub {
319         @Override
isDefaultServiceForCategory(int userId, ComponentName service, String category)320         public boolean isDefaultServiceForCategory(int userId, ComponentName service,
321                 String category) {
322             NfcPermissions.enforceUserPermissions(mContext);
323             NfcPermissions.validateUserId(userId);
324             if (!isServiceRegistered(userId, service)) {
325                 return false;
326             }
327             ComponentName defaultService =
328                     getDefaultServiceForCategory(userId, category, true);
329             return (defaultService != null && defaultService.equals(service));
330         }
331 
332         @Override
isDefaultServiceForAid(int userId, ComponentName service, String aid)333         public boolean isDefaultServiceForAid(int userId,
334                 ComponentName service, String aid) throws RemoteException {
335             NfcPermissions.validateUserId(userId);
336             NfcPermissions.enforceUserPermissions(mContext);
337             if (!isServiceRegistered(userId, service)) {
338                 return false;
339             }
340             return mAidCache.isDefaultServiceForAid(userId, service, aid);
341         }
342 
343         @Override
setDefaultServiceForCategory(int userId, ComponentName service, String category)344         public boolean setDefaultServiceForCategory(int userId,
345                 ComponentName service, String category) throws RemoteException {
346             NfcPermissions.validateUserId(userId);
347             NfcPermissions.enforceAdminPermissions(mContext);
348             if (!isServiceRegistered(userId, service)) {
349                 return false;
350             }
351             return setDefaultServiceForCategoryChecked(userId, service, category);
352         }
353 
354         @Override
setDefaultForNextTap(int userId, ComponentName service)355         public boolean setDefaultForNextTap(int userId, ComponentName service)
356                 throws RemoteException {
357             NfcPermissions.validateUserId(userId);
358             NfcPermissions.enforceAdminPermissions(mContext);
359             if (!isServiceRegistered(userId, service)) {
360                 return false;
361             }
362             return mPreferredServices.setDefaultForNextTap(service);
363         }
364 
365         @Override
registerAidGroupForService(int userId, ComponentName service, AidGroup aidGroup)366         public boolean registerAidGroupForService(int userId,
367                 ComponentName service, AidGroup aidGroup) throws RemoteException {
368             NfcPermissions.validateUserId(userId);
369             NfcPermissions.enforceUserPermissions(mContext);
370             if (!isServiceRegistered(userId, service)) {
371                 return false;
372             }
373             return mServiceCache.registerAidGroupForService(userId, Binder.getCallingUid(), service,
374                     aidGroup);
375         }
376 
377         @Override
getAidGroupForService(int userId, ComponentName service, String category)378         public AidGroup getAidGroupForService(int userId,
379                 ComponentName service, String category) throws RemoteException {
380             NfcPermissions.validateUserId(userId);
381             NfcPermissions.enforceUserPermissions(mContext);
382             if (!isServiceRegistered(userId, service)) {
383                 return null;
384             }
385             return mServiceCache.getAidGroupForService(userId, Binder.getCallingUid(), service,
386                     category);
387         }
388 
389         @Override
removeAidGroupForService(int userId, ComponentName service, String category)390         public boolean removeAidGroupForService(int userId,
391                 ComponentName service, String category) throws RemoteException {
392             NfcPermissions.validateUserId(userId);
393             NfcPermissions.enforceUserPermissions(mContext);
394             if (!isServiceRegistered(userId, service)) {
395                 return false;
396             }
397             return mServiceCache.removeAidGroupForService(userId, Binder.getCallingUid(), service,
398                     category);
399         }
400 
401         @Override
getServices(int userId, String category)402         public List<ApduServiceInfo> getServices(int userId, String category)
403                 throws RemoteException {
404             NfcPermissions.validateUserId(userId);
405             NfcPermissions.enforceAdminPermissions(mContext);
406             return mServiceCache.getServicesForCategory(userId, category);
407         }
408 
409         @Override
setPreferredService(ComponentName service)410         public boolean setPreferredService(ComponentName service)
411                 throws RemoteException {
412             NfcPermissions.enforceUserPermissions(mContext);
413             if (!isServiceRegistered(UserHandle.getCallingUserId(), service)) {
414                 Log.e(TAG, "setPreferredService: unknown component.");
415                 return false;
416             }
417             return mPreferredServices.registerPreferredForegroundService(service,
418                     Binder.getCallingUid());
419         }
420 
421         @Override
unsetPreferredService()422         public boolean unsetPreferredService() throws RemoteException {
423             NfcPermissions.enforceUserPermissions(mContext);
424             return mPreferredServices.unregisteredPreferredForegroundService(
425                     Binder.getCallingUid());
426         }
427 
428         @Override
supportsAidPrefixRegistration()429         public boolean supportsAidPrefixRegistration() throws RemoteException {
430             return mAidCache.supportsAidPrefixRegistration();
431         }
432     }
433 
434     /**
435      * This class implements the application-facing APIs and are called
436      * from binder. All calls must be permission-checked.
437      */
438     final class NfcFCardEmulationInterface extends INfcFCardEmulation.Stub {
439         @Override
getSystemCodeForService(int userId, ComponentName service)440         public String getSystemCodeForService(int userId, ComponentName service)
441                 throws RemoteException {
442             NfcPermissions.validateUserId(userId);
443             NfcPermissions.enforceUserPermissions(mContext);
444             if (!isNfcFServiceInstalled(userId, service)) {
445                 return null;
446             }
447             return mNfcFServicesCache.getSystemCodeForService(
448                     userId, Binder.getCallingUid(), service);
449         }
450 
451         @Override
registerSystemCodeForService(int userId, ComponentName service, String systemCode)452         public boolean registerSystemCodeForService(int userId, ComponentName service,
453                 String systemCode)
454                 throws RemoteException {
455             NfcPermissions.validateUserId(userId);
456             NfcPermissions.enforceUserPermissions(mContext);
457             if (!isNfcFServiceInstalled(userId, service)) {
458                 return false;
459             }
460             return mNfcFServicesCache.registerSystemCodeForService(
461                     userId, Binder.getCallingUid(), service, systemCode);
462         }
463 
464         @Override
removeSystemCodeForService(int userId, ComponentName service)465         public boolean removeSystemCodeForService(int userId, ComponentName service)
466                 throws RemoteException {
467             NfcPermissions.validateUserId(userId);
468             NfcPermissions.enforceUserPermissions(mContext);
469             if (!isNfcFServiceInstalled(userId, service)) {
470                 return false;
471             }
472             return mNfcFServicesCache.removeSystemCodeForService(
473                     userId, Binder.getCallingUid(), service);
474         }
475 
476         @Override
getNfcid2ForService(int userId, ComponentName service)477         public String getNfcid2ForService(int userId, ComponentName service)
478                 throws RemoteException {
479             NfcPermissions.validateUserId(userId);
480             NfcPermissions.enforceUserPermissions(mContext);
481             if (!isNfcFServiceInstalled(userId, service)) {
482                 return null;
483             }
484             return mNfcFServicesCache.getNfcid2ForService(
485                     userId, Binder.getCallingUid(), service);
486         }
487 
488         @Override
setNfcid2ForService(int userId, ComponentName service, String nfcid2)489         public boolean setNfcid2ForService(int userId,
490                 ComponentName service, String nfcid2) throws RemoteException {
491             NfcPermissions.validateUserId(userId);
492             NfcPermissions.enforceUserPermissions(mContext);
493             if (!isNfcFServiceInstalled(userId, service)) {
494                 return false;
495             }
496             return mNfcFServicesCache.setNfcid2ForService(
497                     userId, Binder.getCallingUid(), service, nfcid2);
498         }
499 
500         @Override
enableNfcFForegroundService(ComponentName service)501         public boolean enableNfcFForegroundService(ComponentName service)
502                 throws RemoteException {
503             NfcPermissions.enforceUserPermissions(mContext);
504             if (isNfcFServiceInstalled(UserHandle.getCallingUserId(), service)) {
505                 return mEnabledNfcFServices.registerEnabledForegroundService(service,
506                         Binder.getCallingUid());
507             }
508             return false;
509         }
510 
511         @Override
disableNfcFForegroundService()512         public boolean disableNfcFForegroundService() throws RemoteException {
513             NfcPermissions.enforceUserPermissions(mContext);
514             return mEnabledNfcFServices.unregisteredEnabledForegroundService(
515                     Binder.getCallingUid());
516         }
517 
518         @Override
getNfcFServices(int userId)519         public List<NfcFServiceInfo> getNfcFServices(int userId)
520                 throws RemoteException {
521             NfcPermissions.validateUserId(userId);
522             NfcPermissions.enforceUserPermissions(mContext);
523             return mNfcFServicesCache.getServices(userId);
524         }
525 
526         @Override
getMaxNumOfRegisterableSystemCodes()527         public int getMaxNumOfRegisterableSystemCodes()
528                 throws RemoteException {
529             NfcPermissions.enforceUserPermissions(mContext);
530             return NfcService.getInstance().getLfT3tMax();
531         }
532     }
533 
534     @Override
onPreferredPaymentServiceChanged(ComponentName service)535     public void onPreferredPaymentServiceChanged(ComponentName service) {
536         mAidCache.onPreferredPaymentServiceChanged(service);
537         mHostEmulationManager.onPreferredPaymentServiceChanged(service);
538     }
539 
540     @Override
onPreferredForegroundServiceChanged(ComponentName service)541     public void onPreferredForegroundServiceChanged(ComponentName service) {
542         mAidCache.onPreferredForegroundServiceChanged(service);
543         mHostEmulationManager.onPreferredForegroundServiceChanged(service);
544     }
545 
546     @Override
onEnabledForegroundNfcFServiceChanged(ComponentName service)547     public void onEnabledForegroundNfcFServiceChanged(ComponentName service) {
548         mT3tIdentifiersCache.onEnabledForegroundNfcFServiceChanged(service);
549         mHostNfcFEmulationManager.onEnabledForegroundNfcFServiceChanged(service);
550     }
551 }
552