• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 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 
17 package com.android.nfc.cardemulation;
18 
19 import static com.android.nfc.module.flags.Flags.nfcHceLatencyEvents;
20 
21 import android.annotation.FlaggedApi;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.annotation.TargetApi;
25 import android.annotation.UserIdInt;
26 import android.app.ActivityManager;
27 import android.app.KeyguardManager;
28 import android.app.compat.CompatChanges;
29 import android.compat.annotation.ChangeId;
30 import android.compat.annotation.EnabledSince;
31 import android.content.ComponentName;
32 import android.content.Context;
33 import android.content.Intent;
34 import android.content.ServiceConnection;
35 import android.content.pm.PackageManager;
36 import android.nfc.ComponentNameAndUser;
37 import android.nfc.INfcOemExtensionCallback;
38 import android.nfc.NfcAdapter;
39 import android.nfc.OemLogItems;
40 import android.nfc.cardemulation.ApduServiceInfo;
41 import android.nfc.cardemulation.CardEmulation;
42 import android.nfc.cardemulation.HostApduService;
43 import android.nfc.cardemulation.PollingFrame;
44 import android.nfc.cardemulation.Utils;
45 import android.os.Bundle;
46 import android.os.Handler;
47 import android.os.IBinder;
48 import android.os.Looper;
49 import android.os.Message;
50 import android.os.Messenger;
51 import android.os.PowerManager;
52 import android.os.RemoteException;
53 import android.os.SystemClock;
54 import android.os.Trace;
55 import android.os.UserHandle;
56 import android.sysprop.NfcProperties;
57 import android.util.ArraySet;
58 import android.util.Log;
59 import android.util.Pair;
60 import android.util.proto.ProtoOutputStream;
61 
62 import androidx.annotation.VisibleForTesting;
63 
64 import com.android.nfc.DeviceConfigFacade;
65 import com.android.nfc.ForegroundUtils;
66 import com.android.nfc.NfcInjector;
67 import com.android.nfc.NfcService;
68 import com.android.nfc.NfcStatsLog;
69 import com.android.nfc.PerfettoTrigger;
70 import com.android.nfc.cardemulation.RegisteredAidCache.AidResolveInfo;
71 import com.android.nfc.cardemulation.util.StatsdUtils;
72 import com.android.nfc.flags.Flags;
73 import com.android.nfc.proto.NfcEventProto;
74 
75 import java.io.FileDescriptor;
76 import java.io.PrintWriter;
77 import java.nio.ByteBuffer;
78 import java.util.ArrayList;
79 import java.util.Arrays;
80 import java.util.HashMap;
81 import java.util.HexFormat;
82 import java.util.List;
83 import java.util.Locale;
84 import java.util.Map;
85 import java.util.Objects;
86 import java.util.Random;
87 import java.util.Set;
88 import java.util.regex.Pattern;
89 
90 public class HostEmulationManager {
91     static final String TAG = "HostEmulationManager";
92     static final boolean DBG = NfcProperties.debug_enabled().orElse(true);
93 
94     static final int STATE_IDLE = 0;
95     static final int STATE_W4_SELECT = 1;
96     static final int STATE_W4_SERVICE = 2;
97     static final int STATE_W4_DEACTIVATE = 3;
98     static final int STATE_XFER = 4;
99     static final int STATE_POLLING_LOOP = 5;
100 
101     /** Minimum AID length as per ISO7816 */
102     static final int MINIMUM_AID_LENGTH = 5;
103 
104     /** Length of Select APDU header including length byte */
105     static final int SELECT_APDU_HDR_LENGTH = 5;
106 
107     static final byte INSTR_SELECT = (byte)0xA4;
108 
109     static final String ANDROID_HCE_AID = "A000000476416E64726F6964484345";
110     static final String NDEF_V1_AID = "D2760000850100";
111     static final String NDEF_V2_AID = "D2760000850101";
112     static final byte[] ANDROID_HCE_RESPONSE = {0x14, (byte)0x81, 0x00, 0x00, (byte)0x90, 0x00};
113 
114     static final byte[] AID_NOT_FOUND = {0x6A, (byte)0x82};
115     static final byte[] UNKNOWN_ERROR = {0x6F, 0x00};
116 
117     static final int CE_HCE_PAYMENT =
118             NfcStatsLog.NFC_CARDEMULATION_OCCURRED__CATEGORY__HCE_PAYMENT;
119     static final int CE_HCE_OTHER =
120             NfcStatsLog.NFC_CARDEMULATION_OCCURRED__CATEGORY__HCE_OTHER;
121     static final String DATA_KEY = "data";
122     static final int FIELD_OFF_IDLE_DELAY_MS = 2000;
123     static final int RE_ENABLE_OBSERVE_MODE_DELAY_MS = 2000;
124     static final int UNBIND_SERVICES_DELAY_MS = 10_000;
125 
126     static final String EVENT_HCE_ACTIVATED = "hce_active";
127     static final String EVENT_HCE_BIND_PAYMENT_SERVICE = "hce_bind_payment_service";
128     static final String EVENT_HCE_BIND_SERVICE = "hce_bind_service";
129     static final String EVENT_HCE_COMMAND_APDU = "hce_command_apdu";
130     static final String EVENT_POLLING_FRAMES = "hce_polling_frames";
131     static final String TRIGGER_NAME_SLOW_TAP = "android.nfc.slow-tap";
132 
133     final Context mContext;
134     final RegisteredAidCache mAidCache;
135     final Messenger mMessenger = new Messenger (new MessageHandler());
136     final KeyguardManager mKeyguard;
137     final Object mLock;
138     final PowerManager mPowerManager;
139     private final Looper mLooper;
140     final DeviceConfigFacade mDeviceConfig;
141 
142     @Nullable
143     private final StatsdUtils mStatsdUtils;
144 
145     private final Random mCookieRandom = new Random(System.currentTimeMillis());
146 
147     @ChangeId
148     @EnabledSince(targetSdkVersion = 36 /*Build.VERSION_CODES.BAKLAVA*/)
149     static final long DONT_IMMEDIATELY_UNBIND_SERVICES = 365533082L;
150 
151     INfcOemExtensionCallback mNfcOemExtensionCallback;
152 
153     long mFieldOnTime;
154 
155     // All variables below protected by mLock
156 
157     // Variables below are for a non-payment service,
158     // that is typically only bound in the STATE_XFER state.
159     Messenger mService;
160 
161     static class HostEmulationConnection {
162         @UserIdInt int mUserId;
163         ComponentName mComponentName;
164         ServiceConnection mServiceConnection;
165         Messenger mMessenger;
166 
HostEmulationConnection(@serIdInt int userId, ComponentName componentName, ServiceConnection serviceConnection)167         HostEmulationConnection(@UserIdInt int userId,
168                                 ComponentName componentName,
169                                 ServiceConnection serviceConnection) {
170             this(userId, componentName, serviceConnection, null);
171         }
172 
HostEmulationConnection( @serIdInt int userId, ComponentName componentName, ServiceConnection serviceConnection, Messenger messenger)173         HostEmulationConnection(
174             @UserIdInt int userId,
175                 ComponentName componentName,
176                 ServiceConnection serviceConnection,
177                 Messenger messenger) {
178             mUserId = userId;
179             mComponentName = componentName;
180             mServiceConnection = serviceConnection;
181             mMessenger = messenger;
182         }
183 
184         @Override
toString()185         public String toString() {
186             return "{" + mComponentName + "(" + mUserId + "): "
187                 + mMessenger + ", " + mServiceConnection + "}";
188         }
189     }
190 
191     Map<ComponentNameAndUser, HostEmulationConnection> mComponentNameToConnectionsMap =
192             new HashMap<>();
193     boolean mServiceBound = false;
194     ComponentName mServiceName = null;
195     @UserIdInt int mServiceUserId; // The UserId of the non-payment service
196     ArrayList<PollingFrame> mPendingPollingLoopFrames = null;
197     ArrayList<PollingFrame> mUnprocessedPollingFrames = null;
198     Map<ComponentName, ArrayList<PollingFrame>> mPollingFramesToSend = null;
199     private Map<Integer, Map<String, List<ApduServiceInfo>>> mPollingLoopFilters;
200     private Map<Integer, Map<Pattern, List<ApduServiceInfo>>> mPollingLoopPatternFilters;
201     AutoDisableObserveModeRunnable mAutoDisableObserveModeRunnable = null;
202 
203     // Variables below are for a payment service,
204     // which is typically bound persistently to improve on
205     // latency.
206     Messenger mPaymentService;
207     boolean mPaymentServiceBound = false;
208 
209     boolean mEnableObserveModeAfterTransaction = false;
210     boolean mEnableObserveModeOnFieldOff = false;
211     PollingFrame mFirmwareExitFrame = null;
212     ComponentName mPaymentServiceName = null;
213     @UserIdInt int mPaymentServiceUserId; // The userId of the payment service
214     ComponentName mLastBoundPaymentServiceName;
215 
216     // mActiveService denotes the service interface
217     // that is the current active one, until a new SELECT AID
218     // comes in that may be resolved to a different service.
219     // On deactivation, mActiveService stops being valid.
220     Messenger mActiveService;
221     ComponentName mActiveServiceName;
222     @UserIdInt int mActiveServiceUserId; // The UserId of the current active one
223 
224     String mLastSelectedAid;
225     int mState;
226     byte[] mSelectApdu;
227     Handler mHandler;
228 
229 
230     enum PollingLoopState {
231         EVALUATING_POLLING_LOOP,
232         FILTER_MATCHED,
233         DELIVERING_TO_PREFERRED
234     };
235 
236     PollingLoopState mPollingLoopState = PollingLoopState.EVALUATING_POLLING_LOOP;
237 
238     // Runnable to return to an IDLE_STATE and reset preferred service. This should be run after we
239     // have left a field and gone a period of time without any HCE or polling frame data.
240     Runnable mReturnToIdleStateRunnable = new Runnable() {
241         @Override
242         public void run() {
243             synchronized (mLock) {
244                 Log.d(TAG, "Have been outside field, returning to idle state");
245                 returnToIdleStateLocked();
246             }
247         }
248     };
249 
250     Runnable mUnbindInactiveServicesRunnable =
251             new Runnable() {
252                 @Override
253                 public void run() {
254                     synchronized (mLock) {
255                         if (isHostCardEmulationActivated()) {
256                             // Skip in active state
257                             rescheduleInactivityChecks();
258                         } else {
259                             unbindInactiveServicesLocked();
260                         }
261                     }
262                 }
263 
264                 void unbindInactiveServicesLocked() {
265                     ComponentNameAndUser preferredNameAndUser = mAidCache.getPreferredService();
266                     Map<ComponentNameAndUser, HostEmulationConnection> retainedConnections =
267                             new HashMap<>();
268                     mComponentNameToConnectionsMap.keySet().forEach((key) -> {
269                         if (!preferredNameAndUser.equals(key)) {
270                             HostEmulationConnection connection =
271                                 mComponentNameToConnectionsMap.get(key);
272                             if (connection.mMessenger != null) {
273                                 try {
274                                     mContext.unbindService(connection.mServiceConnection);
275                                 } catch (IllegalArgumentException iae) {
276                                     Log.wtf(TAG,
277                                             "unbindInactiveServicesLocked: "
278                                                     + "Exception while unbinding "
279                                                     + key.getComponentName()
280                                                     + " service connection",
281                                             iae);
282                                 }
283                             }
284                         } else {
285                             retainedConnections.put(key, mComponentNameToConnectionsMap.get(key));
286                         }
287                     });
288                     mComponentNameToConnectionsMap = retainedConnections;
289                 }
290             };
291 
292     // Runnable to re-enable observe mode after a transaction. This should be delayed after
293     // HCE is deactivated to ensure we don't receive another select AID.
294     Runnable mEnableObserveModeAfterTransactionRunnable = new Runnable() {
295         @Override
296         public void run() {
297             synchronized (mLock) {
298                 Log.d(TAG, "mEnableObserveModeAfterTransactionRunnable.run");
299                 if (!mEnableObserveModeAfterTransaction && !mEnableObserveModeOnFieldOff) {
300                     return;
301                 }
302                 mEnableObserveModeAfterTransaction = false;
303                 mEnableObserveModeOnFieldOff = false;
304             }
305             NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
306             if (adapter == null) {
307                 Log.e(TAG, "mEnableObserveModeAfterTransactionRunnable.run: "
308                         + "adapter is null, returning");
309                 return;
310             }
311             adapter.setObserveModeEnabled(true);
312         }
313     };
314 
HostEmulationManager(Context context, Looper looper, RegisteredAidCache aidCache, NfcInjector nfcInjector)315     public HostEmulationManager(Context context, Looper looper, RegisteredAidCache aidCache,
316             NfcInjector nfcInjector) {
317         this(context, looper, aidCache, nfcInjector.getStatsdUtilsContext() != null ?
318             new StatsdUtils(StatsdUtils.SE_NAME_HCE, nfcInjector.getStatsdUtilsContext()) : null,
319             nfcInjector);
320     }
321 
322     @VisibleForTesting
HostEmulationManager(Context context, Looper looper, RegisteredAidCache aidCache, StatsdUtils statsdUtils, NfcInjector nfcInjector)323     HostEmulationManager(Context context, Looper looper, RegisteredAidCache aidCache,
324                          StatsdUtils statsdUtils, NfcInjector nfcInjector) {
325         mContext = context;
326         mLooper = looper;
327         mHandler = new Handler(looper);
328         mLock = new Object();
329         mAidCache = aidCache;
330         mState = STATE_IDLE;
331         mPollingLoopState = PollingLoopState.EVALUATING_POLLING_LOOP;
332         mKeyguard = context.getSystemService(KeyguardManager.class);
333         mPowerManager = context.getSystemService(PowerManager.class);
334         mStatsdUtils = Flags.statsdCeEventsFlag() ? statsdUtils : null;
335         mPollingLoopFilters = new HashMap<Integer, Map<String, List<ApduServiceInfo>>>();
336         mPollingLoopPatternFilters = new HashMap<Integer, Map<Pattern, List<ApduServiceInfo>>>();
337         mDeviceConfig = nfcInjector.getDeviceConfigFacade();
338 
339         if (isMultipleBindingSupported()) {
340             mHandler.postDelayed(mUnbindInactiveServicesRunnable, UNBIND_SERVICES_DELAY_MS);
341         }
342     }
343 
setOemExtension(@ullable INfcOemExtensionCallback nfcOemExtensionCallback)344     public void setOemExtension(@Nullable INfcOemExtensionCallback nfcOemExtensionCallback) {
345         mNfcOemExtensionCallback = nfcOemExtensionCallback;
346     }
347 
onBootCompleted()348     public void onBootCompleted() {
349         if (!mPaymentServiceBound) {
350             ComponentNameAndUser preferredPaymentService = mAidCache.getPreferredPaymentService();
351             // getPreferredPaymentService returns a non-null object even if there is no role holder,
352             // check for package name explicitly.
353             ComponentName preferredPaymentServiceName = preferredPaymentService.getComponentName();
354             if (preferredPaymentServiceName != null) {
355                 Log.d(TAG, "onBootCompleted, payment service not bound, binding");
356                 onPreferredPaymentServiceChanged(preferredPaymentService);
357             }
358         }
359     }
360 
361     /**
362      *  Preferred payment service changed
363      */
onPreferredPaymentServiceChanged(final ComponentNameAndUser service)364     public void onPreferredPaymentServiceChanged(final ComponentNameAndUser service) {
365         mHandler.post(() -> {
366             synchronized (mLock) {
367                 if (!isHostCardEmulationActivated()) {
368                     Log.d(TAG, "onPreferredPaymentServiceChanged: resetting active service");
369                     resetActiveService();
370                 }
371 
372                 if (service != null && service.getComponentName() != null) {
373                     bindPaymentServiceLocked(service.getUserId(), service.getComponentName());
374                 } else {
375                     unbindPaymentServiceLocked();
376                 }
377             }
378         });
379     }
380 
getForegroundServiceOrDefault()381     private Messenger getForegroundServiceOrDefault() {
382         Pair<Messenger, ComponentName> pair = getForegroundServiceAndNameOrDefault();
383         if (pair == null) {
384             return null;
385         }
386         return pair.first;
387     }
388 
getForegroundServiceAndNameOrDefault()389     private Pair<Messenger, ComponentName> getForegroundServiceAndNameOrDefault() {
390         ComponentNameAndUser preferredService = mAidCache.getPreferredService();
391         int preferredServiceUserId = preferredService.getUserId();
392         ComponentName preferredServiceName = preferredService.getComponentName();
393 
394         if (preferredServiceName == null || preferredServiceUserId < 0) {
395             return null;
396         }
397 
398         return new Pair<>(bindServiceIfNeededLocked(preferredServiceUserId, preferredServiceName),
399             preferredServiceName);
400     }
401 
402 
403     @TargetApi(35)
updateForShouldDefaultToObserveMode(boolean enabled)404     public void updateForShouldDefaultToObserveMode(boolean enabled) {
405         synchronized (mLock) {
406             if (isHostCardEmulationActivated()) {
407                 mEnableObserveModeAfterTransaction = enabled;
408                 return;
409             }
410             if (mHandler.hasCallbacks(mEnableObserveModeAfterTransactionRunnable)) {
411                 if (enabled) {
412                     return;
413                 } else {
414                     mHandler.removeCallbacks(mEnableObserveModeAfterTransactionRunnable);
415                 }
416             }
417             mEnableObserveModeAfterTransaction = false;
418             mEnableObserveModeOnFieldOff = false;
419         }
420         NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
421         adapter.setObserveModeEnabled(enabled);
422     }
423 
424 
425     @TargetApi(35)
updatePollingLoopFilters(@serIdInt int userId, List<ApduServiceInfo> services)426     public void updatePollingLoopFilters(@UserIdInt int userId, List<ApduServiceInfo> services) {
427         HashMap<String, List<ApduServiceInfo>> pollingLoopFilters =
428                 new HashMap<String, List<ApduServiceInfo>>();
429         HashMap<Pattern, List<ApduServiceInfo>> pollingLoopPatternFilters =
430                 new HashMap<Pattern, List<ApduServiceInfo>>();
431         for (ApduServiceInfo serviceInfo : services) {
432             for (String plf : serviceInfo.getPollingLoopFilters()) {
433                 List<ApduServiceInfo> list =
434                         pollingLoopFilters.getOrDefault(plf, new ArrayList<ApduServiceInfo>());
435                 list.add(serviceInfo);
436                 pollingLoopFilters.putIfAbsent(plf, list);
437 
438             }
439             for (Pattern plpf : serviceInfo.getPollingLoopPatternFilters()) {
440                 List<ApduServiceInfo> list =
441                         pollingLoopPatternFilters.getOrDefault(plpf,
442                         new ArrayList<ApduServiceInfo>());
443                 list.add(serviceInfo);
444                 pollingLoopPatternFilters.putIfAbsent(plpf, list);
445 
446             }
447         }
448         mPollingLoopFilters.put(Integer.valueOf(userId), pollingLoopFilters);
449         mPollingLoopPatternFilters.put(Integer.valueOf(userId), pollingLoopPatternFilters);
450     }
451 
onObserveModeStateChange(boolean enabled)452     public void onObserveModeStateChange(boolean enabled) {
453         synchronized(mLock) {
454             if (!enabled && mAutoDisableObserveModeRunnable != null) {
455                 mHandler.removeCallbacks(mAutoDisableObserveModeRunnable);
456                 mAutoDisableObserveModeRunnable = null;
457             }
458         }
459     }
460 
461     class AutoDisableObserveModeRunnable implements Runnable {
462         Set<String> mServicePackageNames;
AutoDisableObserveModeRunnable(ComponentName componentName)463         AutoDisableObserveModeRunnable(ComponentName componentName) {
464             mServicePackageNames = new ArraySet<>(1);
465             addServiceToList(componentName);
466         }
467 
468         @Override
run()469         public void run() {
470             synchronized(mLock) {
471                 NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
472                 if (!adapter.isObserveModeEnabled()) {
473                     return;
474                 }
475                 if (arePackagesInForeground()) {
476                     return;
477                 }
478                 Log.w(TAG,
479                         "AutoDisableObserveModeRunnable: Observe mode not disabled and "
480                                 + "no application from the following "
481                                 + "packages are in the foreground: "
482                                 + String.join(", ", mServicePackageNames));
483                 allowOneTransaction();
484             }
485         }
486 
487 
addServiceToList(ComponentName service)488         void addServiceToList(ComponentName service) {
489             mServicePackageNames.add(service.getPackageName());
490         }
491 
arePackagesInForeground()492         boolean arePackagesInForeground() {
493             ActivityManager am = mContext.getSystemService(ActivityManager.class);
494             if (am == null) {
495                 return false;
496             }
497             ForegroundUtils foregroundUtils = ForegroundUtils.getInstance(am);
498             if (foregroundUtils == null) {
499                 return false;
500             }
501             PackageManager packageManager = mContext.getPackageManager();
502             if (packageManager == null) {
503                 return false;
504             }
505             List<Integer> uids = foregroundUtils.getForegroundUids();
506             if (uids != null && mServicePackageNames != null) {
507                 for (Integer uid : uids) {
508                     String[] packageNames = packageManager.getPackagesForUid(uid);
509                     if (packageNames != null) {
510                         for (String packageName :  packageNames) {
511                             if (packageName != null) {
512                                 for (String servicePackageName : mServicePackageNames) {
513                                     if (Objects.equals(servicePackageName, packageName)) {
514                                         return true;
515                                     }
516                                 }
517                             }
518                         }
519                     }
520                 }
521             }
522             return false;
523         }
524     }
525 
sendFrameToServiceLocked(Messenger service, ComponentName name, PollingFrame frame)526     private void sendFrameToServiceLocked(Messenger service, ComponentName name,
527         PollingFrame frame) {
528         sendFramesToServiceLocked(service, name, Arrays.asList(frame));
529     }
530 
sendFramesToServiceLocked(Messenger service, ComponentName name, List<PollingFrame> frames)531     private void sendFramesToServiceLocked(Messenger service, ComponentName name,
532             List<PollingFrame> frames) {
533         if (service != null) {
534             sendPollingFramesToServiceLocked(service, new ArrayList<>(frames));
535         } else {
536             mUnprocessedPollingFrames = new ArrayList<PollingFrame>();
537             if (mPollingFramesToSend == null) {
538                 mPollingFramesToSend = new HashMap<ComponentName, ArrayList<PollingFrame>>();
539             }
540             if (mPollingFramesToSend.containsKey(name)) {
541                 mPollingFramesToSend.get(name).addAll(frames);
542             } else {
543                 mPollingFramesToSend.put(name, new ArrayList<>(frames));
544             }
545         }
546         if (Flags.autoDisableObserveMode()) {
547             if (mAutoDisableObserveModeRunnable == null) {
548                 mAutoDisableObserveModeRunnable = new AutoDisableObserveModeRunnable(name);
549                 mHandler.postDelayed(mAutoDisableObserveModeRunnable, 3000);
550             } else {
551                 mAutoDisableObserveModeRunnable.addServiceToList(name);
552             }
553         }
554     }
555 
rescheduleInactivityChecks()556     void rescheduleInactivityChecks() {
557         mHandler.removeCallbacks(mReturnToIdleStateRunnable);
558         if (isMultipleBindingSupported()) {
559             mHandler.removeCallbacks(mUnbindInactiveServicesRunnable);
560             mHandler.postDelayed(mUnbindInactiveServicesRunnable, UNBIND_SERVICES_DELAY_MS);
561         }
562     }
563 
setPollingLoopStateLocked(PollingLoopState state)564     private void setPollingLoopStateLocked(PollingLoopState state) {
565         Log.d(TAG, "setPollingLoopStateLocked: " + mPollingLoopState + " -> " + state);
566         mPollingLoopState = state;
567     }
568 
569     @TargetApi(35)
onPollingLoopDetected(List<PollingFrame> pollingFrames)570     public void onPollingLoopDetected(List<PollingFrame> pollingFrames) {
571         Log.d(TAG, "onPollingLoopDetected: size: " + pollingFrames.size());
572         synchronized (mLock) {
573             rescheduleInactivityChecks();
574             // We need to have this check here in addition to the one in onFieldChangeDetected,
575             // because we can receive an OFF frame after the field change is detected.
576             if (!pollingFrames.isEmpty()
577                     && pollingFrames.getLast().getType() == PollingFrame.POLLING_LOOP_TYPE_OFF) {
578                 mHandler.postDelayed(mReturnToIdleStateRunnable, FIELD_OFF_IDLE_DELAY_MS);
579             }
580 
581             if (mState == STATE_IDLE) {
582                 mState = STATE_POLLING_LOOP;
583             }
584             int onCount = 0;
585             int offCount = 0;
586             int aCount = 0;
587             int bCount = 0;
588             if (mPendingPollingLoopFrames == null) {
589                 mPendingPollingLoopFrames = new ArrayList<PollingFrame>(1);
590             }
591             for (PollingFrame pollingFrame : pollingFrames) {
592                 if (mUnprocessedPollingFrames != null) {
593                     mUnprocessedPollingFrames.add(pollingFrame);
594                 } else if (pollingFrame.getType()
595                         == PollingFrame.POLLING_LOOP_TYPE_F) {
596                     Pair<Messenger, ComponentName> serviceAndName =
597                         getForegroundServiceAndNameOrDefault();
598                     if (serviceAndName != null) {
599                         sendFrameToServiceLocked(serviceAndName.first, serviceAndName.second,
600                             pollingFrame);
601                     }
602                 } else if (pollingFrame.getType()
603                         == PollingFrame.POLLING_LOOP_TYPE_UNKNOWN) {
604                     byte[] data = pollingFrame.getData();
605                     String dataStr = HexFormat.of().formatHex(data).toUpperCase(Locale.ROOT);
606                     List<ApduServiceInfo> serviceInfos =
607                             mPollingLoopFilters.get(ActivityManager.getCurrentUser()).get(dataStr);
608                     Map<Pattern, List<ApduServiceInfo>> patternMappingForUser =
609                             mPollingLoopPatternFilters.get(ActivityManager.getCurrentUser());
610                     Set<Pattern> patternSet = patternMappingForUser.keySet();
611                     List<Pattern> matchedPatterns = patternSet.stream()
612                             .filter(p -> p.matcher(dataStr).matches()).toList();
613                     if (!matchedPatterns.isEmpty()) {
614                         if (serviceInfos == null) {
615                             serviceInfos = new ArrayList<ApduServiceInfo>();
616                         }
617                         for (Pattern matchedPattern : matchedPatterns) {
618                             serviceInfos.addAll(patternMappingForUser.get(matchedPattern));
619                         }
620                     }
621                     if (serviceInfos != null && serviceInfos.size() > 0) {
622                         ApduServiceInfo serviceInfo;
623                         if (serviceInfos.size() == 1) {
624                             serviceInfo = serviceInfos.get(0);
625                         } else {
626                             serviceInfo = mAidCache.resolvePollingLoopFilterConflict(serviceInfos);
627                             if (serviceInfo == null) {
628                                 /*  If neither the foreground or payments service can handle the plf,
629                                 *  pick the first in the list. */
630                                 serviceInfo = serviceInfos.get(0);
631                             }
632                         }
633                         if (serviceInfo.getShouldAutoTransact(dataStr)) {
634                             if (mStatsdUtils != null) {
635                                 mStatsdUtils.logAutoTransactReported(
636                                     StatsdUtils.PROCESSOR_HOST, data);
637                                 mStatsdUtils.setNextObserveModeTriggerSource(
638                                     StatsdUtils.TRIGGER_SOURCE_AUTO_TRANSACT);
639                             }
640                             if (mFirmwareExitFrame != null && Arrays.equals(
641                                     mFirmwareExitFrame.getData(), pollingFrame.getData())) {
642                                 mFirmwareExitFrame = null;
643                                 mEnableObserveModeAfterTransaction = true;
644                                 Log.d(TAG,
645                                         "Polling frame matches exit frame, leaving observe mode "
646                                                 + "disabled");
647                             } else {
648                                 allowOneTransaction();
649                             }
650                             pollingFrame.setTriggeredAutoTransact(true);
651                         }
652                         UserHandle user = UserHandle.getUserHandleForUid(serviceInfo.getUid());
653                         if (serviceInfo.isOnHost()) {
654                             Messenger service = bindServiceIfNeededLocked(user.getIdentifier(),
655                                     serviceInfo.getComponent());
656                             setPollingLoopStateLocked(PollingLoopState.FILTER_MATCHED);
657                             sendFrameToServiceLocked(service, serviceInfo.getComponent(),
658                                 pollingFrame);
659                         }
660                     } else {
661                         Pair<Messenger, ComponentName> serviceAndName =
662                                 getForegroundServiceAndNameOrDefault();
663                         if (serviceAndName != null) {
664                             sendFrameToServiceLocked(serviceAndName.first, serviceAndName.second,
665                                 pollingFrame);
666                         }
667                     }
668 
669                     if (mStatsdUtils != null) {
670                         mStatsdUtils.tallyPollingFrame(dataStr, pollingFrame);
671                     }
672                 } else {
673                     mPendingPollingLoopFrames.add(pollingFrame);
674                 }
675                 if (mStatsdUtils != null) {
676                     mStatsdUtils.logPollingFrames();
677                 }
678             }
679             mFirmwareExitFrame = null;
680 
681             if (mPollingLoopState == PollingLoopState.EVALUATING_POLLING_LOOP) {
682                 if (mPendingPollingLoopFrames.size() >= 3) {
683                     for (PollingFrame frame : mPendingPollingLoopFrames) {
684                         int type = frame.getType();
685                         switch (type) {
686                             case PollingFrame.POLLING_LOOP_TYPE_A:
687                                 aCount++;
688                                 if (aCount > 3) {
689                                     setPollingLoopStateLocked(
690                                             PollingLoopState.DELIVERING_TO_PREFERRED);
691                                 }
692                                 break;
693                             case PollingFrame.POLLING_LOOP_TYPE_B:
694                                 bCount++;
695                                 if (bCount > 3) {
696                                     setPollingLoopStateLocked(
697                                             PollingLoopState.DELIVERING_TO_PREFERRED);
698                                 }
699                                 break;
700                             case PollingFrame.POLLING_LOOP_TYPE_ON:
701                                 onCount++;
702                                 break;
703                             case PollingFrame.POLLING_LOOP_TYPE_OFF:
704                                 // Send the loop data if we've seen at least one on before an off.
705                                 offCount++;
706                                 if (onCount >= 2 && offCount >=2) {
707                                     setPollingLoopStateLocked(
708                                             PollingLoopState.DELIVERING_TO_PREFERRED);
709                                 }
710                                 break;
711                             default:
712                         }
713                         if (mPollingLoopState != PollingLoopState.EVALUATING_POLLING_LOOP) {
714                             break;
715                         }
716                     }
717                 }
718             }
719 
720             if (mPollingLoopState == PollingLoopState.DELIVERING_TO_PREFERRED) {
721                 Pair<Messenger, ComponentName> serviceAndName =
722                         getForegroundServiceAndNameOrDefault();
723                 if (serviceAndName != null) {
724                     sendFramesToServiceLocked(serviceAndName.first, serviceAndName.second,
725                         mPendingPollingLoopFrames);
726                     mPendingPollingLoopFrames = null;
727                 } else {
728                     Log.i(TAG, "onPollingLoopDetected: No preferred service to deliver "
729                             + "polling frames to, allowing transaction");
730                     allowOneTransaction();
731                 }
732             }
733         }
734     }
735 
allowOneTransaction()736     private void allowOneTransaction() {
737         Log.d(TAG, "allowOneTransaction");
738         mEnableObserveModeAfterTransaction = true;
739         NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
740         mHandler.post(() -> adapter.setObserveModeEnabled(false));
741     }
742 
743     /**
744      * Observe mode was disabled in firmware, we shouldn't autotransact on the next frame.
745      *
746      * This assumes the exit frame will be in the next batch of processed polling frames.
747      */
onObserveModeDisabledInFirmware(PollingFrame exitFrame)748     public void onObserveModeDisabledInFirmware(PollingFrame exitFrame) {
749         mFirmwareExitFrame = exitFrame;
750     }
751 
752     /**
753      *  Preferred foreground service changed
754      */
onPreferredForegroundServiceChanged(ComponentNameAndUser serviceAndUser)755     public void onPreferredForegroundServiceChanged(ComponentNameAndUser serviceAndUser) {
756         synchronized (mLock) {
757             int userId = serviceAndUser.getUserId();
758             ComponentName service = serviceAndUser.getComponentName();
759 
760             mAidCache.onPreferredForegroundServiceChanged(serviceAndUser);
761 
762             if (!isHostCardEmulationActivated()) {
763                 Log.d(TAG, "onPreferredForegroundServiceChanged: resetting active service");
764                 resetActiveService();
765             }
766             if (service != null) {
767                 bindServiceIfNeededLocked(userId, service);
768             } else {
769                 unbindServiceIfNeededLocked();
770             }
771          }
772      }
773 
onFieldChangeDetected(boolean fieldOn)774     public void onFieldChangeDetected(boolean fieldOn) {
775         rescheduleInactivityChecks();
776         if (!fieldOn) {
777             mHandler.postDelayed(mReturnToIdleStateRunnable, FIELD_OFF_IDLE_DELAY_MS);
778         }
779         if (!fieldOn && mEnableObserveModeOnFieldOff && mEnableObserveModeAfterTransaction) {
780             Log.d(TAG, "onFieldChangeDetected: re-enable observe mode");
781             mHandler.postDelayed(mEnableObserveModeAfterTransactionRunnable,
782                 RE_ENABLE_OBSERVE_MODE_DELAY_MS);
783         }
784 
785         if (fieldOn && nfcHceLatencyEvents()) {
786             mFieldOnTime = SystemClock.elapsedRealtime();
787         }
788     }
789 
onHostEmulationActivated()790     public void onHostEmulationActivated() {
791         Log.d(TAG, "onHostEmulationActivated");
792         synchronized (mLock) {
793             if (nfcHceLatencyEvents()) {
794                 Trace.beginAsyncSection(EVENT_HCE_ACTIVATED, 0);
795             }
796             rescheduleInactivityChecks();
797             // Regardless of what happens, if we're having a tap again
798             // activity up, close it
799             Intent intent = new Intent(TapAgainDialog.ACTION_CLOSE);
800             intent.setPackage(NfcInjector.getInstance().getNfcPackageName());
801             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
802             if (mState != STATE_IDLE && mState != STATE_POLLING_LOOP) {
803                 Log.e(TAG, "onHostEmulationActivated: Got activation event in non-idle state");
804             }
805             mState = STATE_W4_SELECT;
806         }
807     }
808 
809     static private class UnroutableAidBugReportRunnable implements Runnable {
810         List<String> mUnroutedAids;
811 
UnroutableAidBugReportRunnable(String aid)812         UnroutableAidBugReportRunnable(String aid) {
813             mUnroutedAids = new ArrayList<String>(1);
814             mUnroutedAids.add(aid);
815         }
816 
addAid(String aid)817         void addAid(String aid) {
818             mUnroutedAids.add(aid);
819         }
820         @Override
run()821         public void run() {
822             NfcService.getInstance().mNfcDiagnostics.takeBugReport(
823                     "NFC tap failed."
824                         + " (If you weren't using NFC, "
825                         + "no need to submit this report.)",
826                     "Couldn't route " + String.join(", ", mUnroutedAids));
827         }
828     }
829 
830     UnroutableAidBugReportRunnable mUnroutableAidBugReportRunnable = null;
831 
onHostEmulationData(byte[] data)832     public void onHostEmulationData(byte[] data) {
833         Log.d(TAG, "onHostEmulationData");
834         mHandler.removeCallbacks(mEnableObserveModeAfterTransactionRunnable);
835         rescheduleInactivityChecks();
836         String selectAid = findSelectAid(data);
837         ComponentName resolvedService = null;
838         ApduServiceInfo resolvedServiceInfo = null;
839         AidResolveInfo resolveInfo = null;
840         synchronized (mLock) {
841             if (mState == STATE_IDLE) {
842                 Log.e(TAG, "onHostEmulationData: Got data in idle state.");
843                 return;
844             } else if (mState == STATE_W4_DEACTIVATE) {
845                 Log.e(TAG, "onHostEmulationData: Dropping APDU in STATE_W4_DECTIVATE");
846                 return;
847             }
848             if (selectAid != null) {
849                 if (selectAid.equals(ANDROID_HCE_AID)) {
850                     NfcService.getInstance().sendData(ANDROID_HCE_RESPONSE);
851                     return;
852                 }
853                 resolveInfo = mAidCache.resolveAid(selectAid);
854                 if (resolveInfo == null || resolveInfo.services.size() == 0) {
855                     if (selectAid.equals(NDEF_V1_AID) || selectAid.equals(NDEF_V2_AID)) {
856                         Log.w(TAG,
857                                 "onHostEmulationData: Can't route NDEF AID, sending AID_NOT_FOUND");
858                     } else if (!mPowerManager.isScreenOn()) {
859                       Log.i(TAG,
860                               "onHostEmulationData: Screen is off, sending AID_NOT_FOUND, "
861                                       + "but not triggering bug report");
862                     } else {
863                         Log.w(TAG, "onHostEmulationData: Can't handle AID " + selectAid
864                                 + " sending AID_NOT_FOUND");
865                         if (android.nfc.Flags.nfcEventListener()) {
866                             notifyAidNotRoutedListener(selectAid);
867                         }
868                         if (mUnroutableAidBugReportRunnable != null) {
869                             mUnroutableAidBugReportRunnable.addAid(selectAid);
870                         } else {
871                             mUnroutableAidBugReportRunnable =
872                                     new UnroutableAidBugReportRunnable(selectAid);
873                             /* Wait 1s to see if there is an alternate AID we can route before
874                              * taking a bug report */
875                             mHandler.postDelayed(mUnroutableAidBugReportRunnable, 1000);
876                         }
877                     }
878                     NfcInjector.getInstance().getNfcEventLog().logEvent(
879                             NfcEventProto.EventType.newBuilder()
880                                     .setCeUnroutableAid(
881                                         NfcEventProto.NfcCeUnroutableAid.newBuilder()
882                                             .setAid(selectAid)
883                                             .build())
884                                     .build());
885                     // Tell the remote we don't handle this AID
886                     NfcService.getInstance().sendData(AID_NOT_FOUND);
887                     return;
888                 } else if (mUnroutableAidBugReportRunnable != null) {
889                     /* If there is a pending bug report runnable, cancel it. */
890                     mHandler.removeCallbacks(mUnroutableAidBugReportRunnable);
891                     mUnroutableAidBugReportRunnable = null;
892                 }
893                 mLastSelectedAid = selectAid;
894                 if (resolveInfo.defaultService != null) {
895                     // Resolve to default
896                     // Check if resolvedService requires unlock
897                     ApduServiceInfo defaultServiceInfo = resolveInfo.defaultService;
898                     if (mStatsdUtils != null) {
899                         mStatsdUtils.setCardEmulationEventCategory(resolveInfo.category);
900                         mStatsdUtils.setCardEmulationEventUid(defaultServiceInfo.getUid());
901                     }
902                     if ((defaultServiceInfo.requiresUnlock()
903                             || NfcService.getInstance().isSecureNfcEnabled())
904                           && NfcInjector.getInstance().isDeviceLocked()) {
905                         NfcService.getInstance().sendRequireUnlockIntent();
906                         NfcService.getInstance().sendData(AID_NOT_FOUND);
907                         if (DBG) Log.d(TAG, "onHostEmulationData: requiresUnlock()! show toast");
908                         if (mStatsdUtils != null) {
909                             mStatsdUtils.logCardEmulationWrongSettingEvent();
910                         }
911                         launchTapAgain(resolveInfo.defaultService, resolveInfo.category);
912                         return;
913                     }
914                     if (defaultServiceInfo.requiresScreenOn() && !mPowerManager.isScreenOn()) {
915                         NfcService.getInstance().sendData(AID_NOT_FOUND);
916                         if (DBG) Log.d(TAG, "onHostEmulationData: requiresScreenOn()!");
917                         if (mStatsdUtils != null) {
918                             mStatsdUtils.logCardEmulationWrongSettingEvent();
919                         }
920                         return;
921                     }
922                     // In no circumstance should this be an OffHostService -
923                     // we should never get this AID on the host in the first place
924                     if (!defaultServiceInfo.isOnHost()) {
925                         Log.e(TAG, "onHostEmulationData: AID that was meant to go off-host was "
926                                 + "routed to host. Check routing table configuration.");
927                         NfcService.getInstance().sendData(AID_NOT_FOUND);
928                         if (mStatsdUtils != null) {
929                             mStatsdUtils.logCardEmulationNoRoutingEvent();
930                         }
931                         return;
932                     }
933                     resolvedService = defaultServiceInfo.getComponent();
934                     resolvedServiceInfo = defaultServiceInfo;
935                 } else if (mActiveServiceName != null) {
936                     for (ApduServiceInfo serviceInfo : resolveInfo.services) {
937                         if (mActiveServiceName.equals(serviceInfo.getComponent())) {
938                             resolvedService = mActiveServiceName;
939                             resolvedServiceInfo = serviceInfo;
940                             break;
941                         }
942                     }
943                 }
944                 if (resolvedService == null) {
945                     // We have no default, and either one or more services.
946                     // Ask the user to confirm.
947                     // Just ignore all future APDUs until we resolve to only one
948                     mState = STATE_W4_DEACTIVATE;
949                     NfcStatsLog.write(NfcStatsLog.NFC_AID_CONFLICT_OCCURRED, selectAid);
950                     if (android.nfc.Flags.nfcEventListener()) {
951                         notifyAidConflictListener(selectAid);
952                     }
953                     if (mStatsdUtils != null) {
954                         mStatsdUtils.setCardEmulationEventCategory(CardEmulation.CATEGORY_OTHER);
955                         mStatsdUtils.logCardEmulationWrongSettingEvent();
956                     }
957                     launchResolver(selectAid, (ArrayList<ApduServiceInfo>)resolveInfo.services,
958                         null, resolveInfo.category);
959                     return;
960                 }
961             }
962             switch (mState) {
963                 case STATE_W4_SELECT:
964                     if (selectAid != null) {
965                         int uid = resolvedServiceInfo.getUid();
966                         if (mStatsdUtils != null) {
967                             mStatsdUtils.setCardEmulationEventUid(uid);
968                             mStatsdUtils.setCardEmulationEventCategory(resolveInfo.category);
969                         }
970                         UserHandle user =
971                                 UserHandle.getUserHandleForUid(uid);
972                         Messenger existingService =
973                                 bindServiceIfNeededLocked(user.getIdentifier(), resolvedService);
974                         if (existingService != null) {
975                             Log.d(TAG, "onHostEmulationData: Send data to existing service");
976                             NfcInjector.getInstance().getNfcEventLog().logEvent(
977                                     NfcEventProto.EventType.newBuilder()
978                                             .setCeRoutedAid(
979                                                 NfcEventProto.NfcCeRoutedAid.newBuilder()
980                                                     .setAid(selectAid)
981                                                     .setComponentInfo(
982                                                         NfcEventProto.NfcComponentInfo.newBuilder()
983                                                             .setPackageName(
984                                                                 resolvedService.getPackageName())
985                                                             .setClassName(
986                                                                 resolvedService.getClassName())
987                                                             .build())
988                                                     .build())
989                                             .build());
990                             sendDataToServiceLocked(existingService, data);
991                         } else {
992                             // Waiting for service to be bound
993                             Log.d(TAG, "onHostEmulationData: Waiting for new service.");
994                             // Queue SELECT APDU to be used
995                             mSelectApdu = data;
996                             mState = STATE_W4_SERVICE;
997                         }
998                         if (mStatsdUtils != null) {
999                             mStatsdUtils.notifyCardEmulationEventWaitingForResponse();
1000                         } else {
1001                             int statsdCategory =
1002                                     resolveInfo.category.equals(CardEmulation.CATEGORY_PAYMENT)
1003                                             ? CE_HCE_PAYMENT
1004                                             : CE_HCE_OTHER;
1005                             NfcStatsLog.write(
1006                                     NfcStatsLog.NFC_CARDEMULATION_OCCURRED,
1007                                     statsdCategory,
1008                                     "HCE",
1009                                     uid);
1010                         }
1011                     } else {
1012                         Log.d(TAG, "onHostEmulationData: Dropping non-select APDU "
1013                                 + "in STATE_W4_SELECT");
1014                         NfcService.getInstance().sendData(UNKNOWN_ERROR);
1015                     }
1016                     break;
1017                 case STATE_W4_SERVICE:
1018                     Log.d(TAG, "onHostEmulationData: Unexpected APDU in STATE_W4_SERVICE");
1019                     break;
1020                 case STATE_XFER:
1021                     if (selectAid != null) {
1022                         UserHandle user =
1023                                 UserHandle.getUserHandleForUid(resolvedServiceInfo.getUid());
1024                         Messenger existingService =
1025                                 bindServiceIfNeededLocked(user.getIdentifier(), resolvedService);
1026                         if (existingService != null) {
1027                             sendDataToServiceLocked(existingService, data);
1028                         } else {
1029                             // Waiting for service to be bound
1030                             mSelectApdu = data;
1031                             mState = STATE_W4_SERVICE;
1032                         }
1033                     } else if (mActiveService != null) {
1034                         // Regular APDU data
1035                         sendDataToServiceLocked(mActiveService, data);
1036                     } else {
1037                         // No SELECT AID and no active service.
1038                         Log.d(TAG, "onHostEmulationData: Service no longer bound, dropping APDU");
1039                     }
1040                     break;
1041             }
1042         }
1043     }
1044 
onHostEmulationDeactivated()1045     public void onHostEmulationDeactivated() {
1046         Log.d(TAG, "onHostEmulationDeactivated");
1047         synchronized (mLock) {
1048             if (mState == STATE_IDLE) {
1049                 Log.e(TAG, "onHostEmulationDeactivated: Got deactivation "
1050                         + "event while in idle state");
1051             }
1052             sendDeactivateToActiveServiceLocked(HostApduService.DEACTIVATION_LINK_LOSS);
1053             unbindServiceIfNeededLocked();
1054             returnToIdleStateLocked();
1055 
1056             if (mAutoDisableObserveModeRunnable != null) {
1057                 mHandler.removeCallbacks(mAutoDisableObserveModeRunnable);
1058                 mAutoDisableObserveModeRunnable = null;
1059             }
1060 
1061             if (mEnableObserveModeAfterTransaction) {
1062                 Log.d(TAG, "onHostEmulationDeactivated: re-enable observe mode.");
1063                 mHandler.postDelayed(mEnableObserveModeAfterTransactionRunnable,
1064                     RE_ENABLE_OBSERVE_MODE_DELAY_MS);
1065             }
1066 
1067             if (mStatsdUtils != null) {
1068                 mStatsdUtils.logCardEmulationDeactivatedEvent();
1069             }
1070 
1071             if (nfcHceLatencyEvents()) {
1072                 Trace.endAsyncSection(EVENT_HCE_ACTIVATED, 0);
1073 
1074                 long endTime = SystemClock.elapsedRealtime();
1075                 long tapDuration = endTime - mFieldOnTime;
1076                 if (tapDuration > mDeviceConfig.getSlowTapThresholdMillis()) {
1077                     PerfettoTrigger.trigger(TRIGGER_NAME_SLOW_TAP);
1078                 }
1079             }
1080         }
1081     }
1082 
isHostCardEmulationActivated()1083     public boolean isHostCardEmulationActivated() {
1084         synchronized (mLock) {
1085             return mState != STATE_IDLE && mState != STATE_POLLING_LOOP;
1086         }
1087     }
1088 
onOffHostAidSelected()1089     public void onOffHostAidSelected() {
1090         Log.d(TAG, "onOffHostAidSelected");
1091         synchronized (mLock) {
1092             mHandler.removeCallbacks(mEnableObserveModeAfterTransactionRunnable);
1093             rescheduleInactivityChecks();
1094             if (mState != STATE_XFER || mActiveService == null) {
1095                 // Don't bother telling, we're not bound to any service yet
1096             } else {
1097                 sendDeactivateToActiveServiceLocked(HostApduService.DEACTIVATION_DESELECTED);
1098             }
1099             if (mEnableObserveModeAfterTransaction) {
1100                 Log.i(TAG, "onOffHostAidSelected: OffHost AID selected, "
1101                         + "waiting for Field off to reenable observe mode");
1102                 mEnableObserveModeOnFieldOff = true;
1103             }
1104             resetActiveService();
1105             unbindServiceIfNeededLocked();
1106             mState = STATE_W4_SELECT;
1107 
1108             //close the TapAgainDialog
1109             Intent intent = new Intent(TapAgainDialog.ACTION_CLOSE);
1110             intent.setPackage(NfcInjector.getInstance().getNfcPackageName());
1111             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1112         }
1113     }
1114 
bindServiceIfNeededLocked(@serIdInt int userId, ComponentName service)1115     Messenger bindServiceIfNeededLocked(@UserIdInt int userId, ComponentName service) {
1116         if (service == null) {
1117             Log.e(TAG, "bindServiceIfNeededLocked: service ComponentName is null");
1118             return null;
1119         }
1120 
1121         ComponentNameAndUser preferredPaymentService = mAidCache.getPreferredPaymentService();
1122         int preferredPaymentUserId = preferredPaymentService.getUserId();
1123         ComponentName preferredPaymentServiceName = preferredPaymentService.getComponentName();
1124         ComponentNameAndUser newServiceAndUser = new ComponentNameAndUser(userId, service);
1125 
1126         if (mPaymentServiceName != null && mPaymentServiceName.equals(service)
1127                 && mPaymentServiceUserId == userId) {
1128             Log.d(TAG, "bindServiceIfNeededLocked: Service already bound as payment service.");
1129             return mPaymentService;
1130         } else if (!mPaymentServiceBound && preferredPaymentServiceName != null
1131                 && preferredPaymentServiceName.equals(service)
1132                 && preferredPaymentUserId == userId) {
1133             Log.d(TAG, "bindServiceIfNeededLocked: Service should be bound as "
1134                     + "payment service but is not, binding now");
1135             bindPaymentServiceLocked(userId, preferredPaymentServiceName);
1136             return null;
1137         } else if (!isMultipleBindingSupported()
1138                 && mServiceName != null
1139                 && mServiceName.equals(service)
1140                 && mServiceUserId == userId) {
1141             Log.d(TAG, "bindServiceIfNeededLocked: Service already bound as regular service.");
1142             return mService;
1143         } else if (isMultipleBindingSupported()
1144                 && mComponentNameToConnectionsMap.containsKey(newServiceAndUser)
1145                 && mComponentNameToConnectionsMap.get(newServiceAndUser).mMessenger != null) {
1146             Log.d(TAG, "bindServiceIfNeededLocked: Service" + service
1147                     + " already bound as regular service.");
1148             return mComponentNameToConnectionsMap.get(newServiceAndUser).mMessenger;
1149         } else {
1150             Log.d(TAG, "bindServiceIfNeededLocked: Binding to service " + service + " for userId:"
1151                     + userId);
1152             if (nfcHceLatencyEvents()) {
1153                 Trace.beginAsyncSection(EVENT_HCE_BIND_SERVICE, 0);
1154             }
1155             if (mStatsdUtils != null) {
1156                 mStatsdUtils.notifyCardEmulationEventWaitingForService();
1157             }
1158             unbindServiceIfNeededLocked();
1159             Intent aidIntent = new Intent(HostApduService.SERVICE_INTERFACE);
1160             aidIntent.setComponent(service);
1161             try {
1162                 ServiceConnection connection = mConnection;
1163                 if (isMultipleBindingSupported()) {
1164                     connection = new HostEmulationServiceConnection(userId);
1165                     mComponentNameToConnectionsMap.put(
1166                         new ComponentNameAndUser(userId, service),
1167                         new HostEmulationConnection(userId, service, connection));
1168                 }
1169                 boolean serviceBound =
1170                         mContext.bindServiceAsUser(
1171                                 aidIntent,
1172                                 connection,
1173                                 Context.BIND_AUTO_CREATE
1174                                         | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS,
1175                                 UserHandle.of(userId));
1176                 if (!isMultipleBindingSupported()) {
1177                     mServiceBound = serviceBound;
1178                 }
1179                 if (!serviceBound) {
1180                     if (nfcHceLatencyEvents()) {
1181                         Trace.endAsyncSection(EVENT_HCE_BIND_SERVICE, 0);
1182                     }
1183                     Log.e(TAG, "bindServiceIfNeededLocked: Could not bind service.");
1184                 } else {
1185                     mServiceUserId = userId;
1186                 }
1187             } catch (SecurityException e) {
1188                 if (nfcHceLatencyEvents()) {
1189                     Trace.endAsyncSection(EVENT_HCE_BIND_SERVICE, 0);
1190                 }
1191                 Log.e(TAG, "bindServiceIfNeededLocked: Could not bind service "
1192                         + "due to security exception.");
1193             }
1194             return null;
1195         }
1196     }
1197 
generateApduAckCookie()1198     private int generateApduAckCookie() {
1199         byte[] token = new byte[Integer.BYTES];
1200         mCookieRandom.nextBytes(token);
1201         return ByteBuffer.wrap(token).getInt();
1202     }
1203 
sendDataToServiceLocked(Messenger service, byte[] data)1204     void sendDataToServiceLocked(Messenger service, byte[] data) {
1205         mState = STATE_XFER;
1206 
1207         int cookie = 0;
1208         if (nfcHceLatencyEvents()) {
1209             cookie = generateApduAckCookie();
1210             Trace.beginAsyncSection(EVENT_HCE_COMMAND_APDU, cookie);
1211         }
1212 
1213         if (!Objects.equals(service, mActiveService)) {
1214             sendDeactivateToActiveServiceLocked(HostApduService.DEACTIVATION_DESELECTED);
1215             mActiveService = service;
1216             if (service.equals(mPaymentService)) {
1217                 mActiveServiceName = mPaymentServiceName;
1218                 mActiveServiceUserId = mPaymentServiceUserId;
1219             } else {
1220                 if (isMultipleBindingSupported()) {
1221                     for (Map.Entry<ComponentNameAndUser, HostEmulationConnection> entry :
1222                         mComponentNameToConnectionsMap.entrySet()) {
1223                         if (service.equals(entry.getValue().mMessenger)) {
1224                             mActiveServiceName = entry.getKey().getComponentName();
1225                             mActiveServiceUserId = entry.getKey().getUserId();
1226                             break;
1227                         }
1228                     }
1229                 } else {
1230                     mActiveServiceName = mServiceName;
1231                     mActiveServiceUserId = mServiceUserId;
1232                 }
1233             }
1234         }
1235         Message msg = Message.obtain(null, HostApduService.MSG_COMMAND_APDU);
1236         Bundle dataBundle = new Bundle();
1237         dataBundle.putByteArray(DATA_KEY, data);
1238         msg.setData(dataBundle);
1239         msg.replyTo = mMessenger;
1240         if (nfcHceLatencyEvents()) {
1241             msg.arg1 = cookie;
1242         }
1243         try {
1244             NfcService.getInstance().notifyOemLogEvent(new OemLogItems
1245                     .Builder(OemLogItems.LOG_ACTION_HCE_DATA)
1246                     .setApduCommand(data)
1247                     .build());
1248             mActiveService.send(msg);
1249         } catch (RemoteException e) {
1250             if (nfcHceLatencyEvents()) {
1251                 Trace.endAsyncSection(EVENT_HCE_COMMAND_APDU, cookie);
1252             }
1253             Log.e(TAG, "sendDataToServiceLocked: Remote service " + mActiveServiceName
1254                     + " has died, dropping APDU", e);
1255             if (Objects.equals(mActiveService, mPaymentService)) {
1256                 Log.wtf(TAG, "sendDataToServiceLocked: Rebinding payment service", e);
1257                 bindPaymentServiceLocked(mPaymentServiceUserId, mLastBoundPaymentServiceName);
1258             }
1259         }
1260     }
1261 
sendPollingFramesToServiceLocked(Messenger service, ArrayList<PollingFrame> pollingFrames)1262     void sendPollingFramesToServiceLocked(Messenger service,
1263             ArrayList<PollingFrame> pollingFrames) {
1264         if (!Objects.equals(service, mActiveService)) {
1265             if (!isMultipleBindingSupported()) {
1266                 sendDeactivateToActiveServiceLocked(HostApduService.DEACTIVATION_DESELECTED);
1267             }
1268             mActiveService = service;
1269             if (service.equals(mPaymentService)) {
1270                 mActiveServiceName = mPaymentServiceName;
1271                 mActiveServiceUserId = mPaymentServiceUserId;
1272             } else {
1273                 mActiveServiceName = mServiceName;
1274                 mActiveServiceUserId = mServiceUserId;
1275             }
1276         }
1277         Message msg = Message.obtain(null, HostApduService.MSG_POLLING_LOOP);
1278         Bundle msgData = new Bundle();
1279         msgData.putParcelableArrayList(HostApduService.KEY_POLLING_LOOP_FRAMES_BUNDLE,
1280                 pollingFrames);
1281         msg.setData(msgData);
1282         msg.replyTo = mMessenger;
1283         if (mState == STATE_IDLE) {
1284             mState = STATE_POLLING_LOOP;
1285         }
1286         if (nfcHceLatencyEvents()) {
1287             int cookie = generateApduAckCookie();
1288             msg.arg1 = cookie;
1289             Trace.beginAsyncSection(EVENT_POLLING_FRAMES, cookie);
1290         }
1291         try {
1292             mActiveService.send(msg);
1293         } catch (RemoteException e) {
1294             Log.e(TAG, "sendPollingFramesToServiceLocked: Remote service " + mActiveServiceName
1295                     + " has died, dropping frames", e);
1296             allowOneTransaction();
1297             if (Objects.equals(mActiveService, mPaymentService)) {
1298                 Log.wtf(TAG, "sendPollingFramesToServiceLocked: Rebinding payment service", e);
1299                 bindPaymentServiceLocked(mPaymentServiceUserId, mLastBoundPaymentServiceName);
1300             }
1301         }
1302     }
1303 
sendDeactivateToActiveServiceLocked(int reason)1304     void sendDeactivateToActiveServiceLocked(int reason) {
1305         if (mActiveService == null) return;
1306         Message msg = Message.obtain(null, HostApduService.MSG_DEACTIVATED);
1307         msg.arg1 = reason;
1308         try {
1309             mActiveService.send(msg);
1310         } catch (RemoteException e) {
1311             // Don't care
1312         }
1313     }
1314 
unbindPaymentServiceLocked()1315     void unbindPaymentServiceLocked() {
1316         Log.d(TAG, "unbindPaymentServiceLocked");
1317         if (mPaymentServiceBound) {
1318             try {
1319                 mContext.unbindService(mPaymentConnection);
1320                 if (isMultipleBindingSupported()) {
1321                     mComponentNameToConnectionsMap.remove(
1322                         new ComponentNameAndUser(mPaymentServiceUserId, mPaymentServiceName));
1323                 }
1324             } catch (Exception e) {
1325                 Log.w(TAG, "unbindPaymentServiceLocked: Failed to unbind: " + mPaymentServiceName,
1326                         e);
1327             }
1328             mPaymentServiceBound = false;
1329         }
1330 
1331         mPaymentService = null;
1332         mPaymentServiceName = null;
1333         mPaymentServiceUserId = -1;
1334     }
1335 
bindPaymentServiceLocked(@serIdInt int userId, ComponentName serviceName)1336     void bindPaymentServiceLocked(@UserIdInt int userId, ComponentName serviceName) {
1337         if (nfcHceLatencyEvents()) {
1338             Trace.beginAsyncSection(EVENT_HCE_BIND_PAYMENT_SERVICE, 0);
1339         }
1340         unbindPaymentServiceLocked();
1341 
1342         Log.d(TAG, "bindPaymentServiceLocked:" + serviceName + " for userId:" + userId);
1343         Intent intent = new Intent(HostApduService.SERVICE_INTERFACE);
1344         intent.setComponent(serviceName);
1345         try {
1346             if (isMultipleBindingSupported()) {
1347                 mComponentNameToConnectionsMap.put(
1348                         new ComponentNameAndUser(userId, serviceName),
1349                         new HostEmulationConnection(userId, serviceName, mPaymentConnection));
1350             }
1351             if (mContext.bindServiceAsUser(intent, mPaymentConnection,
1352                     Context.BIND_AUTO_CREATE | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS,
1353                     UserHandle.of(userId))) {
1354                 mPaymentServiceBound = true;
1355                 mPaymentServiceUserId = userId;
1356                 mLastBoundPaymentServiceName = serviceName;
1357             } else {
1358                 if (nfcHceLatencyEvents()) {
1359                     Trace.endAsyncSection(EVENT_HCE_BIND_PAYMENT_SERVICE, 0);
1360                 }
1361                 Log.e(TAG, "bindPaymentServiceLocked: Could not bind (persistent) "
1362                         + "payment service");
1363             }
1364         } catch (SecurityException e) {
1365             if (nfcHceLatencyEvents()) {
1366                 Trace.endAsyncSection(EVENT_HCE_BIND_PAYMENT_SERVICE, 0);
1367             }
1368             Log.e(TAG, "bindPaymentServiceLocked: Could not bind service "
1369                     + "due to security exception");
1370         }
1371     }
1372 
unbindServiceIfNeededLocked()1373     void unbindServiceIfNeededLocked() {
1374         if (isMultipleBindingSupported()) {
1375             if (mServiceName == null
1376                     || CompatChanges.isChangeEnabled(
1377                         DONT_IMMEDIATELY_UNBIND_SERVICES,
1378                         mServiceName.getPackageName(),
1379                         UserHandle.of(mServiceUserId))) {
1380                 return;
1381             }
1382             if (mServiceName != null) {
1383                 mComponentNameToConnectionsMap.remove(
1384                         new ComponentNameAndUser(mServiceUserId, mServiceName));
1385             }
1386         }
1387 
1388         if (mServiceBound) {
1389             Log.d(TAG, "unbindServiceIfNeededLocked: service " + mServiceName);
1390             try {
1391                 mContext.unbindService(mConnection);
1392             } catch (Exception e) {
1393                 Log.w(TAG, "unbindServiceIfNeededLocked: Failed to unbind " + mServiceName, e);
1394             }
1395             mServiceBound = false;
1396         }
1397 
1398         mService = null;
1399         mServiceName = null;
1400         mServiceUserId = -1;
1401     }
1402 
launchTapAgain(ApduServiceInfo service, String category)1403     void launchTapAgain(ApduServiceInfo service, String category) {
1404         if (mNfcOemExtensionCallback != null) {
1405             try {
1406                 mNfcOemExtensionCallback.onLaunchHceTapAgainActivity(service, category);
1407                 return;
1408             } catch (RemoteException e) {
1409                 Log.e(TAG, "launchTapAgain: onLaunchHceTapAgainActivity failed", e);
1410             }
1411         }
1412         Intent dialogIntent = new Intent(mContext, TapAgainDialog.class);
1413         dialogIntent.putExtra(TapAgainDialog.EXTRA_CATEGORY, category);
1414         dialogIntent.putExtra(TapAgainDialog.EXTRA_APDU_SERVICE, service);
1415         dialogIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
1416         mContext.startActivityAsUser(dialogIntent,
1417                 UserHandle.getUserHandleForUid(service.getUid()));
1418     }
1419 
launchResolver(String selectedAid, ArrayList<ApduServiceInfo> services, ComponentName failedComponent, String category)1420     void launchResolver(String selectedAid, ArrayList<ApduServiceInfo> services,
1421         ComponentName failedComponent, String category) {
1422         if (mNfcOemExtensionCallback != null) {
1423             try {
1424                 mNfcOemExtensionCallback.onLaunchHceAppChooserActivity(
1425                     selectedAid, services, failedComponent, category);
1426                 return;
1427             } catch (RemoteException e) {
1428                 Log.e(TAG, "launchResolver: onLaunchHceAppChooserActivity failed", e);
1429             }
1430         }
1431         Intent intent = new Intent(mContext, AppChooserActivity.class);
1432         intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
1433         intent.putParcelableArrayListExtra(AppChooserActivity.EXTRA_APDU_SERVICES, services);
1434         intent.putExtra(AppChooserActivity.EXTRA_CATEGORY, category);
1435         if (failedComponent != null) {
1436             intent.putExtra(AppChooserActivity.EXTRA_FAILED_COMPONENT, failedComponent);
1437         }
1438         mContext.startActivityAsUser(intent, UserHandle.CURRENT);
1439     }
1440 
findSelectAid(byte[] data)1441     String findSelectAid(byte[] data) {
1442         if (data == null || data.length < SELECT_APDU_HDR_LENGTH + MINIMUM_AID_LENGTH) {
1443             if (DBG) Log.d(TAG, "findSelectAid: Data size too small for SELECT APDU");
1444             return null;
1445         }
1446         // To accept a SELECT AID for dispatch, we require the following:
1447         // Class byte must be 0x00: logical channel set to zero, no secure messaging, no chaining
1448         // Instruction byte must be 0xA4: SELECT instruction
1449         // P1: must be 0x04: select by application identifier
1450         // P2: File control information is only relevant for higher-level application,
1451         //     and we only support "first or only occurrence".
1452         if (data[0] == 0x00 && data[1] == INSTR_SELECT && data[2] == 0x04) {
1453             if (data[3] != 0x00) {
1454                 Log.d(TAG, "findSelectAid: Selecting next, last or previous "
1455                         + "AID occurrence is not supported");
1456             }
1457             int aidLength = Byte.toUnsignedInt(data[4]);
1458             if (data.length < SELECT_APDU_HDR_LENGTH + aidLength) {
1459                 return null;
1460             }
1461             return bytesToString(data, SELECT_APDU_HDR_LENGTH, aidLength);
1462         }
1463         return null;
1464     }
1465 
1466     @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
1467     interface NfcAidRoutingListener {
onAidConflict(@onNull String aid)1468         void onAidConflict(@NonNull String aid);
onAidNotRouted(@onNull String aid)1469         void onAidNotRouted(@NonNull String aid);
1470     }
1471 
1472     @Nullable
1473     private NfcAidRoutingListener mAidRoutingListener = null;
1474 
1475     @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
setAidRoutingListener(@ullable NfcAidRoutingListener listener)1476     void setAidRoutingListener(@Nullable NfcAidRoutingListener listener) {
1477         mAidRoutingListener = listener;
1478     }
1479 
1480     @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
notifyAidConflictListener(String aid)1481     private void notifyAidConflictListener(String aid) {
1482         if (mAidRoutingListener != null && aid != null) {
1483             mAidRoutingListener.onAidConflict(aid);
1484         }
1485     }
1486 
1487     @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
notifyAidNotRoutedListener(String aid)1488     private void notifyAidNotRoutedListener(String aid) {
1489         if (mAidRoutingListener != null && aid != null) {
1490             mAidRoutingListener.onAidNotRouted(aid);
1491         }
1492     }
1493 
returnToIdleStateLocked()1494     private void returnToIdleStateLocked() {
1495         mPendingPollingLoopFrames = null;
1496         mPollingFramesToSend = null;
1497         mUnprocessedPollingFrames = null;
1498         resetActiveService();
1499         setPollingLoopStateLocked(PollingLoopState.EVALUATING_POLLING_LOOP);
1500         mState = STATE_IDLE;
1501     }
1502 
resetActiveService()1503     private void resetActiveService() {
1504         mActiveService = null;
1505         mActiveServiceName = null;
1506         mActiveServiceUserId = -1;
1507     }
1508 
1509     private ServiceConnection mPaymentConnection = new ServiceConnection() {
1510         @Override
1511         public void onServiceConnected(ComponentName name, IBinder service) {
1512             ComponentName paymentServiceName = new ComponentName("", "");
1513             synchronized (mLock) {
1514                 /* Preferred Payment Service has been changed. */
1515                 if (!mLastBoundPaymentServiceName.equals(name)) {
1516                     Log.i(TAG, "onServiceConnected: Ignoring bound payment service, " + name
1517                             + " != " + mLastBoundPaymentServiceName);
1518                     return;
1519                 }
1520                 mPaymentServiceName = name;
1521                 mPaymentService = new Messenger(service);
1522                 paymentServiceName = mPaymentServiceName;
1523                 if (isMultipleBindingSupported()) {
1524                     if (mComponentNameToConnectionsMap.containsKey(
1525                         new ComponentNameAndUser(mPaymentServiceUserId, name))) {
1526                             mComponentNameToConnectionsMap.get(
1527                             new ComponentNameAndUser(mPaymentServiceUserId, name)).mMessenger =
1528                             mPaymentService;
1529                     } else {
1530                         mComponentNameToConnectionsMap.put(
1531                             new ComponentNameAndUser(mPaymentServiceUserId, name),
1532                             new HostEmulationConnection(mPaymentServiceUserId, name,
1533                                     this, mPaymentService));
1534                     }
1535                 }
1536                 Log.i(TAG, "onServiceConnected: Payment service bound: " + name);
1537                 if (nfcHceLatencyEvents()) {
1538                     Trace.endAsyncSection(EVENT_HCE_BIND_PAYMENT_SERVICE, 0);
1539                 }
1540             }
1541             NfcInjector.getInstance().getNfcEventLog().logEvent(
1542                     NfcEventProto.EventType.newBuilder()
1543                             .setPaymentServiceBindState(
1544                                 NfcEventProto.NfcPaymentServiceBindState.newBuilder()
1545                                     .setBindState(NfcEventProto.BindState.SERVICE_CONNECTED)
1546                                     .setComponentInfo(
1547                                         NfcEventProto.NfcComponentInfo.newBuilder()
1548                                             .setPackageName(
1549                                                 paymentServiceName.getPackageName())
1550                                             .setClassName(
1551                                                 paymentServiceName.getClassName())
1552                                             .build())
1553                                     .build())
1554                             .build());
1555 
1556             if (mPollingFramesToSend != null && mPollingFramesToSend.containsKey(name)) {
1557                 sendPollingFramesToServiceLocked(mPaymentService, mPollingFramesToSend.get(name));
1558                 mPollingFramesToSend.remove(name);
1559                 if (mUnprocessedPollingFrames != null) {
1560                     ArrayList unprocessedPollingFrames = mUnprocessedPollingFrames;
1561                     mUnprocessedPollingFrames = null;
1562                     onPollingLoopDetected(unprocessedPollingFrames);
1563                 }
1564             }
1565         }
1566 
1567         @Override
1568         public void onServiceDisconnected(ComponentName name) {
1569             Log.i(TAG, "onServiceDisconnected: " + name);
1570             ComponentName paymentServiceName = new ComponentName("", "");
1571             synchronized (mLock) {
1572                 if (isMultipleBindingSupported()) {
1573                     ComponentNameAndUser nameAndUser =
1574                             new ComponentNameAndUser(mPaymentServiceUserId, name);
1575                     mComponentNameToConnectionsMap.remove(nameAndUser);
1576                 }
1577                 paymentServiceName = mPaymentServiceName;
1578                 mPaymentService = null;
1579                 mPaymentServiceName = null;
1580             }
1581             NfcInjector.getInstance().getNfcEventLog().logEvent(
1582                     NfcEventProto.EventType.newBuilder()
1583                             .setPaymentServiceBindState(
1584                                 NfcEventProto.NfcPaymentServiceBindState.newBuilder()
1585                                     .setBindState(NfcEventProto.BindState.SERVICE_DISCONNECTED)
1586                                     .setComponentInfo(
1587                                         NfcEventProto.NfcComponentInfo.newBuilder()
1588                                             .setPackageName(
1589                                                 paymentServiceName.getPackageName())
1590                                             .setClassName(
1591                                                 paymentServiceName.getClassName())
1592                                             .build())
1593                                     .build())
1594                             .build());
1595         }
1596 
1597         @Override
1598         public void onBindingDied(ComponentName name) {
1599             Log.i(TAG, "onBindingDied: " + name);
1600             ComponentName paymentServiceName = new ComponentName("", "");
1601             synchronized (mLock) {
1602                 if (mPaymentServiceName != null) paymentServiceName = mPaymentServiceName;
1603                 if (mPaymentServiceUserId >= 0) {
1604                     bindPaymentServiceLocked(mPaymentServiceUserId, mLastBoundPaymentServiceName);
1605                 }
1606             }
1607             NfcInjector.getInstance().getNfcEventLog().logEvent(
1608                     NfcEventProto.EventType.newBuilder()
1609                             .setPaymentServiceBindState(
1610                                 NfcEventProto.NfcPaymentServiceBindState.newBuilder()
1611                                     .setBindState(NfcEventProto.BindState.SERVICE_BINDING_DIED)
1612                                     .setComponentInfo(
1613                                         NfcEventProto.NfcComponentInfo.newBuilder()
1614                                             .setPackageName(
1615                                                 paymentServiceName.getPackageName())
1616                                             .setClassName(
1617                                                 paymentServiceName.getClassName())
1618                                             .build())
1619                                     .build())
1620                             .build());
1621         }
1622     };
1623 
1624     class HostEmulationServiceConnection implements ServiceConnection {
1625         @UserIdInt int mUserId;
1626 
HostEmulationServiceConnection(@serIdInt int userId)1627         HostEmulationServiceConnection(@UserIdInt int userId) {
1628             mUserId = userId;
1629         }
1630 
1631         @Override
onServiceConnected(ComponentName name, IBinder service)1632         public void onServiceConnected(ComponentName name, IBinder service) {
1633             synchronized (mLock) {
1634                 ComponentNameAndUser preferredUserAndService = mAidCache.getPreferredService();
1635                 ComponentName preferredServiceName =
1636                         preferredUserAndService == null ? null :
1637                                 preferredUserAndService.getComponentName();
1638                 /* Service is already deactivated and not preferred, don't bind */
1639                 if (mState == STATE_IDLE && !name.equals(preferredServiceName)) {
1640                     return;
1641                 }
1642                 Messenger messenger = new Messenger(service);
1643                 if (isMultipleBindingSupported()) {
1644                     ComponentNameAndUser key = new ComponentNameAndUser(mUserId, name);
1645                     if (mComponentNameToConnectionsMap.containsKey(key)) {
1646                         mComponentNameToConnectionsMap.get(key).mMessenger = messenger;
1647                     } else {
1648                         mComponentNameToConnectionsMap.put(key,
1649                             new HostEmulationConnection(mUserId, name, this, messenger));
1650                     }
1651                 } else {
1652                     mService = messenger;
1653                     mServiceName = name;
1654                     mServiceBound = true;
1655                 }
1656 
1657                 if (nfcHceLatencyEvents()) {
1658                     Trace.endAsyncSection(EVENT_HCE_BIND_SERVICE, 0);
1659                 }
1660                 Log.d(TAG, "onServiceConnected: Service bound: " + name);
1661 
1662                 // Send pending select APDU
1663                 if (mSelectApdu != null) {
1664                     if (mStatsdUtils != null) {
1665                         mStatsdUtils.notifyCardEmulationEventServiceBound();
1666                     }
1667                     NfcInjector.getInstance().getNfcEventLog().logEvent(
1668                             NfcEventProto.EventType.newBuilder()
1669                                     .setCeRoutedAid(
1670                                         NfcEventProto.NfcCeRoutedAid.newBuilder()
1671                                             .setAid(mLastSelectedAid == null
1672                                                         ? "" : mLastSelectedAid)
1673                                             .setComponentInfo(
1674                                                 NfcEventProto.NfcComponentInfo.newBuilder()
1675                                                     .setPackageName(
1676                                                         name.getPackageName())
1677                                                     .setClassName(
1678                                                         name.getClassName())
1679                                                     .build())
1680                                             .build())
1681                                     .build());
1682                     sendDataToServiceLocked(messenger, mSelectApdu);
1683                     mSelectApdu = null;
1684                 } else if (mPollingFramesToSend != null && mPollingFramesToSend.containsKey(name)) {
1685                     sendPollingFramesToServiceLocked(messenger, mPollingFramesToSend.get(name));
1686                     mPollingFramesToSend.remove(name);
1687                     if (mUnprocessedPollingFrames != null) {
1688                         ArrayList unprocessedPollingFrames = mUnprocessedPollingFrames;
1689                         mUnprocessedPollingFrames = null;
1690                         onPollingLoopDetected(unprocessedPollingFrames);
1691                     }
1692                 } else {
1693                     Log.d(TAG, "onServiceConnected: bound with nothing to send");
1694                 }
1695             }
1696         }
1697 
1698         @Override
onServiceDisconnected(ComponentName name)1699         public void onServiceDisconnected(ComponentName name) {
1700             synchronized (mLock) {
1701                 Log.d(TAG, "onServiceDisconnected: unbound: " + name);
1702                 if (isMultipleBindingSupported()) {
1703                     ComponentNameAndUser nameAndUser = new ComponentNameAndUser(mUserId, name);
1704                     mComponentNameToConnectionsMap.remove(nameAndUser);
1705                 } else {
1706                     mService = null;
1707                     mServiceName = null;
1708                     mServiceBound = false;
1709                 }
1710             }
1711         }
1712     };
1713 
1714     private ServiceConnection mConnection =
1715         new HostEmulationServiceConnection(UserHandle.CURRENT.getIdentifier());
1716 
1717     class MessageHandler extends Handler {
1718         @Override
handleMessage(Message msg)1719         public void handleMessage(Message msg) {
1720             synchronized(mLock) {
1721                 if (mActiveService == null) {
1722                     Log.d(TAG, "handleMessage: Dropping service response message; "
1723                             + "service no longer active.");
1724                     return;
1725                 } else if (!msg.replyTo.getBinder().equals(mActiveService.getBinder())) {
1726                     Log.d(TAG, "handleMessage: Dropping service response message; "
1727                             + "service no longer bound.");
1728                     return;
1729                 }
1730             }
1731             if (msg.what == HostApduService.MSG_RESPONSE_APDU) {
1732                 Bundle dataBundle = msg.getData();
1733                 if (dataBundle == null) {
1734                     return;
1735                 }
1736                 byte[] data = dataBundle.getByteArray(DATA_KEY);
1737                 if (data == null || data.length == 0) {
1738                     Log.e(TAG, "handleMessage: Dropping empty R-APDU");
1739                     return;
1740                 }
1741                 int state;
1742                 synchronized(mLock) {
1743                     state = mState;
1744                 }
1745                 if (state == STATE_XFER) {
1746                     Log.d(TAG, "handleMessage: Sending data");
1747                     NfcService.getInstance().sendData(data);
1748                     if (mStatsdUtils != null) {
1749                         mStatsdUtils.notifyCardEmulationEventResponseReceived();
1750                     }
1751                 } else {
1752                     Log.d(TAG,
1753                             "handleMessage: Dropping data, wrong state " + Integer.toString(state));
1754                 }
1755 
1756                 if (nfcHceLatencyEvents()) {
1757                     try {
1758                         Message ackMsg = Message.obtain(null,
1759                                 HostApduService.MSG_RESPONSE_APDU_ACK);
1760                         ackMsg.arg1 = msg.arg1;
1761                         ackMsg.replyTo = mMessenger;
1762                         msg.replyTo.send(ackMsg);
1763                     } catch (RemoteException e) {
1764                         Log.e(TAG, "handleMessage: Failed to acknowledge MSG_RESPONSE_APDU", e);
1765                     }
1766                 }
1767             } else if (msg.what == HostApduService.MSG_UNHANDLED) {
1768                 synchronized (mLock) {
1769                     Log.d(TAG, "handleMessage: Received MSG_UNHANDLED");
1770                     AidResolveInfo resolveInfo = mAidCache.resolveAid(mLastSelectedAid);
1771 
1772                     if (resolveInfo.services.size() > 0) {
1773                         NfcStatsLog.write(NfcStatsLog.NFC_AID_CONFLICT_OCCURRED, mLastSelectedAid);
1774                         if (android.nfc.Flags.nfcEventListener()) {
1775                             notifyAidConflictListener(mLastSelectedAid);
1776                         }
1777                         launchResolver(mLastSelectedAid,
1778                             (ArrayList<ApduServiceInfo>)resolveInfo.services,
1779                             mActiveServiceName, resolveInfo.category);
1780                     }
1781                 }
1782             } else if (msg.what == HostApduService.MSG_COMMAND_APDU_ACK) {
1783                 if (nfcHceLatencyEvents()) {
1784                     Trace.endAsyncSection(EVENT_HCE_COMMAND_APDU, msg.arg1);
1785                 }
1786             } else if (msg.what == HostApduService.MSG_POLLING_LOOP_ACK) {
1787                 if (nfcHceLatencyEvents()) {
1788                     Trace.endAsyncSection(EVENT_POLLING_FRAMES, msg.arg1);
1789                 }
1790             }
1791         }
1792     }
1793 
bytesToString(byte[] bytes, int offset, int length)1794     static String bytesToString(byte[] bytes, int offset, int length) {
1795         final char[] hexChars = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
1796         char[] chars = new char[length * 2];
1797         int byteValue;
1798         for (int j = 0; j < length; j++) {
1799             byteValue = bytes[offset + j] & 0xFF;
1800             chars[j * 2] = hexChars[byteValue >>> 4];
1801             chars[j * 2 + 1] = hexChars[byteValue & 0x0F];
1802         }
1803         return new String(chars);
1804     }
1805 
dump(FileDescriptor fd, PrintWriter pw, String[] args)1806     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1807         pw.println("Bound HCE-A/HCE-B services: ");
1808         if (mPaymentServiceBound) {
1809             pw.println("    payment: " + mPaymentServiceName);
1810         }
1811         if (isMultipleBindingSupported() && !mComponentNameToConnectionsMap.isEmpty()) {
1812             pw.println("    others: ");
1813             for (Map.Entry<ComponentNameAndUser, HostEmulationConnection> entry :
1814                mComponentNameToConnectionsMap.entrySet()) {
1815                 pw.println("            " + entry.getKey());
1816             }
1817         } else if (mServiceBound) {
1818             pw.println("    other: " + mServiceName);
1819         }
1820     }
1821 
1822     /**
1823      * Dump debugging information as a HostEmulationManagerProto
1824      *
1825      * Note:
1826      * See proto definition in frameworks/base/core/proto/android/nfc/card_emulation.proto
1827      * When writing a nested message, must call {@link ProtoOutputStream#start(long)} before and
1828      * {@link ProtoOutputStream#end(long)} after.
1829      * Never reuse a proto field number. When removing a field, mark it as reserved.
1830      */
dumpDebug(ProtoOutputStream proto)1831     void dumpDebug(ProtoOutputStream proto) {
1832         if (mPaymentServiceBound) {
1833             Utils.dumpDebugComponentName(
1834                     mPaymentServiceName, proto, HostEmulationManagerProto.PAYMENT_SERVICE_NAME);
1835         }
1836         // TODO make this a repeated field and return all the services
1837         if (mServiceBound) {
1838             Utils.dumpDebugComponentName(
1839                     mServiceName, proto, HostEmulationManagerProto.SERVICE_NAME);
1840         }
1841     }
1842 
isMultipleBindingSupported()1843     boolean isMultipleBindingSupported() {
1844         return Flags.allowMultipleHceBindings();
1845     }
1846 
1847     @VisibleForTesting
getState()1848     public int getState() {
1849         return mState;
1850     }
1851 
1852     @VisibleForTesting
getServiceConnection()1853     public ServiceConnection getServiceConnection() {
1854         return mConnection;
1855     }
1856 
1857     @VisibleForTesting
getPaymentConnection()1858     public ServiceConnection getPaymentConnection() {
1859         return mPaymentConnection;
1860     }
1861 
1862     @VisibleForTesting
getMessenger()1863     public IBinder getMessenger() {
1864         if (mActiveService != null) {
1865             return mActiveService.getBinder();
1866         }
1867         return null;
1868     }
1869 
1870     @VisibleForTesting
getLocalMessenger()1871     public Messenger getLocalMessenger() {
1872         return mMessenger;
1873     }
1874 
1875     @VisibleForTesting
getServiceName()1876     public ComponentName getServiceName() {
1877         return mLastBoundPaymentServiceName;
1878     }
1879 
1880     @VisibleForTesting
isServiceBounded(@serIdInt int userId, ComponentName componentName)1881     public Boolean isServiceBounded(@UserIdInt int userId, ComponentName componentName) {
1882         if (isMultipleBindingSupported()) {
1883             return mComponentNameToConnectionsMap.containsKey(
1884                     new ComponentNameAndUser(userId, componentName));
1885         } else {
1886             return mServiceBound;
1887         }
1888     }
1889 
1890     @VisibleForTesting
getPollingLoopFilters()1891     public Map<Integer, Map<String, List<ApduServiceInfo>>> getPollingLoopFilters() {
1892         return mPollingLoopFilters;
1893     }
1894 
1895     @VisibleForTesting
getPollingLoopPatternFilters()1896     public Map<Integer, Map<Pattern, List<ApduServiceInfo>>> getPollingLoopPatternFilters() {
1897         return mPollingLoopPatternFilters;
1898     }
1899 }
1900