Home | History | Annotate | Download | only in cardemulation
      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 
     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 
    100     public INfcCardEmulation getNfcCardEmulationInterface() {
    101         return mCardEmulationInterface;
    102     }
    103 
    104     public INfcFCardEmulation getNfcFCardEmulationInterface() {
    105         return mNfcFCardEmulationInterface;
    106     }
    107 
    108 
    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 
    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 
    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 
    145     public void onOffHostAidSelected() {
    146         mHostEmulationManager.onOffHostAidSelected();
    147     }
    148 
    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 
    161     public void onNfcEnabled() {
    162         // for HCE
    163         mAidCache.onNfcEnabled();
    164         // for HCE-F
    165         mT3tIdentifiersCache.onNfcEnabled();
    166     }
    167 
    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 
    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
    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
    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 
    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 
    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 
    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 
    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 
    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      */
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    423         public boolean unsetPreferredService() throws RemoteException {
    424             NfcPermissions.enforceUserPermissions(mContext);
    425             return mPreferredServices.unregisteredPreferredForegroundService(
    426                     Binder.getCallingUid());
    427         }
    428 
    429         @Override
    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
    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
    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
    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
    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
    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
    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
    513         public boolean disableNfcFForegroundService() throws RemoteException {
    514             NfcPermissions.enforceUserPermissions(mContext);
    515             return mEnabledNfcFServices.unregisteredEnabledForegroundService(
    516                     Binder.getCallingUid());
    517         }
    518 
    519         @Override
    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
    528         public int getMaxNumOfRegisterableSystemCodes()
    529                 throws RemoteException {
    530             NfcPermissions.enforceUserPermissions(mContext);
    531             return NfcService.getInstance().getLfT3tMax();
    532         }
    533     }
    534 
    535     @Override
    536     public void onPreferredPaymentServiceChanged(ComponentName service) {
    537         mAidCache.onPreferredPaymentServiceChanged(service);
    538         mHostEmulationManager.onPreferredPaymentServiceChanged(service);
    539     }
    540 
    541     @Override
    542     public void onPreferredForegroundServiceChanged(ComponentName service) {
    543         mAidCache.onPreferredForegroundServiceChanged(service);
    544         mHostEmulationManager.onPreferredForegroundServiceChanged(service);
    545     }
    546 
    547     @Override
    548     public void onEnabledForegroundNfcFServiceChanged(ComponentName service) {
    549         mT3tIdentifiersCache.onEnabledForegroundNfcFServiceChanged(service);
    550         mHostNfcFEmulationManager.onEnabledForegroundNfcFServiceChanged(service);
    551     }
    552 }
    553