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.os.PowerManager;
36import android.os.SystemClock;
37import android.provider.Settings;
38import android.util.Log;
39
40import com.android.nfc.NfcPermissions;
41import com.android.nfc.NfcService;
42import com.android.nfc.cardemulation.RegisteredServicesCache;
43import 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 */
60public 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.invalidateCache(userId);
158    }
159
160    public void onNfcEnabled() {
161        // for HCE
162        mAidCache.onNfcEnabled();
163        // for HCE-F
164        mT3tIdentifiersCache.onNfcEnabled();
165    }
166
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
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
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
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
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
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
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
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
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     */
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
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
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
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
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
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
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
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
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
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
422        public boolean unsetPreferredService() throws RemoteException {
423            NfcPermissions.enforceUserPermissions(mContext);
424            return mPreferredServices.unregisteredPreferredForegroundService(
425                    Binder.getCallingUid());
426        }
427
428        @Override
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
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
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
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
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
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
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
512        public boolean disableNfcFForegroundService() throws RemoteException {
513            NfcPermissions.enforceUserPermissions(mContext);
514            return mEnabledNfcFServices.unregisteredEnabledForegroundService(
515                    Binder.getCallingUid());
516        }
517
518        @Override
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
527        public int getMaxNumOfRegisterableSystemCodes()
528                throws RemoteException {
529            NfcPermissions.enforceUserPermissions(mContext);
530            return NfcService.getInstance().getLfT3tMax();
531        }
532    }
533
534    @Override
535    public void onPreferredPaymentServiceChanged(ComponentName service) {
536        mAidCache.onPreferredPaymentServiceChanged(service);
537        mHostEmulationManager.onPreferredPaymentServiceChanged(service);
538    }
539
540    @Override
541    public void onPreferredForegroundServiceChanged(ComponentName service) {
542        mAidCache.onPreferredForegroundServiceChanged(service);
543        mHostEmulationManager.onPreferredForegroundServiceChanged(service);
544    }
545
546    @Override
547    public void onEnabledForegroundNfcFServiceChanged(ComponentName service) {
548        mT3tIdentifiersCache.onEnabledForegroundNfcFServiceChanged(service);
549        mHostNfcFEmulationManager.onEnabledForegroundNfcFServiceChanged(service);
550    }
551}
552