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