• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.nfc.cardemulation;
17 
18 import android.annotation.TargetApi;
19 import android.app.ActivityManager;
20 import android.content.ComponentName;
21 import android.content.Context;
22 import android.database.ContentObserver;
23 import android.net.Uri;
24 import android.nfc.ComponentNameAndUser;
25 import android.nfc.Constants;
26 import android.nfc.PackageAndUser;
27 import android.nfc.cardemulation.ApduServiceInfo;
28 import android.nfc.cardemulation.CardEmulation;
29 import android.nfc.cardemulation.Utils;
30 import android.os.Build;
31 import android.os.Handler;
32 import android.os.Looper;
33 import android.os.UserHandle;
34 import android.os.UserManager;
35 import android.provider.Settings;
36 import android.provider.Settings.SettingNotFoundException;
37 import android.sysprop.NfcProperties;
38 import android.util.Log;
39 import android.util.proto.ProtoOutputStream;
40 
41 import com.android.nfc.ForegroundUtils;
42 
43 import java.io.FileDescriptor;
44 import java.io.PrintWriter;
45 import java.util.ArrayList;
46 import java.util.List;
47 import java.util.Objects;
48 
49 /**
50  * This class keeps track of what HCE/SE-based services are
51  * preferred by the user. It currently has 3 inputs:
52  * 1) The default set in tap&pay menu for payment category
53  * 2) An app in the foreground asking for a specific
54  *    service for a specific category
55  * 3) If we had to disambiguate a previous tap (because no
56  *    preferred service was there), we need to temporarily
57  *    store the user's choice for the next tap.
58  *
59  * This class keeps track of all 3 inputs, and computes a new
60  * preferred services as needed. It then passes this service
61  * (if it changed) through a callback, which allows other components
62  * to adapt as necessary (ie the AID cache can update its AID
63  * mappings and the routing table).
64  */
65 public class PreferredServices implements com.android.nfc.ForegroundUtils.Callback {
66     static final String TAG = "PreferredCardEmulationServices";
67     static final boolean DBG = NfcProperties.debug_enabled().orElse(true);
68     static final Uri paymentDefaultUri = Settings.Secure.getUriFor(
69             Constants.SETTINGS_SECURE_NFC_PAYMENT_DEFAULT_COMPONENT);
70     static final Uri paymentForegroundUri = Settings.Secure.getUriFor(
71             Constants.SETTINGS_SECURE_NFC_PAYMENT_FOREGROUND);
72 
73     final SettingsObserver mSettingsObserver;
74     final Context mContext;
75     final WalletRoleObserver mWalletRoleObserver;
76     final RegisteredServicesCache mServiceCache;
77     final RegisteredAidCache mAidCache;
78     final Callback mCallback;
79     final ForegroundUtils mForegroundUtils;
80     final Handler mHandler = new Handler(Looper.getMainLooper());
81 
82     final class PaymentDefaults {
83         boolean preferForeground; // The current selection mode for this category
84         ComponentName settingsDefault; // The component preferred in settings (eg Tap&Pay)
85         ComponentName currentPreferred; // The computed preferred component
86         UserHandle mUserHandle;
87     }
88 
89     final Object mLock = new Object();
90     // Variables below synchronized on mLock
91     PaymentDefaults mPaymentDefaults = new PaymentDefaults();
92 
93     ComponentName mForegroundRequested; // The component preferred by fg app
94     int mForegroundUid; // The UID of the fg app, or -1 if fg app didn't request
95 
96     ComponentName mNextTapDefault; // The component preferred by active disambig dialog
97     int mNextTapDefaultUserId;
98     boolean mClearNextTapDefault = false; // Set when the next tap default must be cleared
99 
100     ComponentName mForegroundCurrent; // The currently computed foreground component
101     int mForegroundCurrentUid; // The UID of the currently computed foreground component
102 
103     ComponentName mDefaultWalletHolderPaymentService;
104 
105     int mUserIdDefaultWalletHolder;
106 
107     public interface Callback {
108         /**
109          * Notify when preferred payment service is changed
110          */
onPreferredPaymentServiceChanged(ComponentNameAndUser service)111         void onPreferredPaymentServiceChanged(ComponentNameAndUser service);
112         /**
113          * Notify when preferred foreground service is changed
114          */
onPreferredForegroundServiceChanged(ComponentNameAndUser service)115         void onPreferredForegroundServiceChanged(ComponentNameAndUser service);
116     }
117 
PreferredServices(Context context, RegisteredServicesCache serviceCache, RegisteredAidCache aidCache, WalletRoleObserver walletRoleObserver, Callback callback)118     public PreferredServices(Context context, RegisteredServicesCache serviceCache,
119             RegisteredAidCache aidCache, WalletRoleObserver walletRoleObserver,
120             Callback callback) {
121         mContext = context;
122         mWalletRoleObserver = walletRoleObserver;
123         mForegroundUtils = ForegroundUtils.getInstance(
124                 context.getSystemService(ActivityManager.class));
125         mServiceCache = serviceCache;
126         mAidCache = aidCache;
127         mCallback = callback;
128         mSettingsObserver = new SettingsObserver(mHandler);
129         mContext.getContentResolver().registerContentObserverAsUser(
130                 paymentDefaultUri,
131                 true, mSettingsObserver, UserHandle.ALL);
132 
133         mContext.getContentResolver().registerContentObserverAsUser(
134                 paymentForegroundUri,
135                 true, mSettingsObserver, UserHandle.ALL);
136 
137         int currentUserId = ActivityManager.getCurrentUser();
138 
139         // Load current settings defaults for payments
140         loadDefaultsFromSettings(currentUserId, false);
141 
142         if (mWalletRoleObserver.isWalletRoleFeatureEnabled()) {
143             PackageAndUser holder = mWalletRoleObserver.getDefaultWalletRoleHolder(
144                     currentUserId);
145             onWalletRoleHolderChanged(holder.getPackage(), holder.getUserId());
146         }
147     }
148 
149     private final class SettingsObserver extends ContentObserver {
SettingsObserver(Handler handler)150         public SettingsObserver(Handler handler) {
151             super(handler);
152         }
153 
154         @Override
onChange(boolean selfChange, Uri uri)155         public void onChange(boolean selfChange, Uri uri) {
156             super.onChange(selfChange, uri);
157             // Do it just for the current user. If it was in fact
158             // a change made for another user, we'll sync it down
159             // on user switch.
160             int currentUser = ActivityManager.getCurrentUser();
161             loadDefaultsFromSettings(currentUser, false);
162         }
163     };
164 
165     @TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
onWalletRoleHolderChanged(String defaultWalletHolderPackageName, int userId)166     public void onWalletRoleHolderChanged(String defaultWalletHolderPackageName, int userId) {
167         if (defaultWalletHolderPackageName == null) {
168             mDefaultWalletHolderPaymentService = null;
169             mUserIdDefaultWalletHolder = userId;
170             mCallback.onPreferredPaymentServiceChanged(new ComponentNameAndUser(userId, null));
171             return;
172         }
173         List<ApduServiceInfo> serviceInfos = mServiceCache.getInstalledServices(userId);
174         List<ComponentName> roleHolderPaymentServices = new ArrayList<>();
175         int servicesCount = serviceInfos.size();
176         for (int i = 0; i < servicesCount; i++) {
177             ApduServiceInfo serviceInfo = serviceInfos.get(i);
178             ComponentName componentName = serviceInfo.getComponent();
179             if (componentName.getPackageName()
180                     .equals(defaultWalletHolderPackageName)) {
181                 List<String> aids = serviceInfo.getAids();
182                 int aidsCount = aids.size();
183                 for (int j = 0; j < aidsCount; j++) {
184                     String aid = aids.get(j);
185                     if (serviceInfo.getCategoryForAid(aid)
186                             .equals(CardEmulation.CATEGORY_PAYMENT)) {
187                         roleHolderPaymentServices.add(componentName);
188                         break;
189                     }
190                 }
191             }
192         }
193         ComponentName candidate = !roleHolderPaymentServices.isEmpty()
194                 ? roleHolderPaymentServices.get(0) : null;
195         if (!Objects.equals(candidate, mDefaultWalletHolderPaymentService) ||
196                 userId != mUserIdDefaultWalletHolder) {
197             mDefaultWalletHolderPaymentService = candidate;
198             mUserIdDefaultWalletHolder = userId;
199             mCallback.onPreferredPaymentServiceChanged(new ComponentNameAndUser(userId, candidate));
200         }
201     }
202 
loadDefaultsFromSettings(int userId, boolean force)203     void loadDefaultsFromSettings(int userId, boolean force) {
204         boolean paymentDefaultChanged = false;
205         boolean paymentPreferForegroundChanged = false;
206         // Load current payment default from settings
207         UserHandle currentUser = UserHandle.of(ActivityManager.getCurrentUser());
208         UserManager um = mContext.createContextAsUser(currentUser, /*flags=*/0)
209                 .getSystemService(UserManager.class);
210         List<UserHandle> userHandles = um.getEnabledProfiles();
211 
212         String name = null;
213         String newDefaultName = null;
214         UserHandle newUser = null;
215         // search for default payment setting within enabled profiles
216         for (UserHandle uh : userHandles) {
217             try {
218                 name = Settings.Secure.getString(
219                         mContext.createContextAsUser(uh, 0).getContentResolver(),
220                         Constants.SETTINGS_SECURE_NFC_PAYMENT_DEFAULT_COMPONENT);
221             } catch (IllegalStateException e) {
222                 Log.d(TAG,
223                         "loadDefaultsFromSettings: Fail to get default payment component for user: "
224                                 + uh);
225                 continue;
226             }
227 
228             if (name != null) {
229                 newUser = uh;
230                 newDefaultName = name;
231             }
232             if (uh.getIdentifier() == userId) {
233                 currentUser = uh;
234             }
235         }
236         if (currentUser == null) {
237             Log.e(TAG, "loadDefaultsFromSettings: NULL/ Error fetching currentUser info");
238             return;
239         }
240         // no default payment setting in all profles
241         if (newUser == null) {
242             newUser = currentUser;
243         }
244         ComponentName newDefault = newDefaultName != null
245                 ? ComponentName.unflattenFromString(newDefaultName) : null;
246         boolean preferForeground = false;
247         try {
248             // get the setting from the main user instead of from the user profiles.
249             preferForeground = mWalletRoleObserver.isWalletRoleFeatureEnabled()
250                     || Settings.Secure.getInt(mContext
251                             .createContextAsUser(currentUser, 0).getContentResolver(),
252                     Constants.SETTINGS_SECURE_NFC_PAYMENT_FOREGROUND) != 0;
253         } catch (SettingNotFoundException e) {
254         }
255         synchronized (mLock) {
256             paymentPreferForegroundChanged = (preferForeground != mPaymentDefaults.preferForeground);
257             mPaymentDefaults.preferForeground = preferForeground;
258 
259             mPaymentDefaults.settingsDefault = newDefault;
260             if (newDefault != null && (!newDefault.equals(mPaymentDefaults.currentPreferred)
261                     || mPaymentDefaults.mUserHandle.getIdentifier() != newUser.getIdentifier())) {
262                 paymentDefaultChanged = true;
263                 mPaymentDefaults.currentPreferred = newDefault;
264                 mPaymentDefaults.mUserHandle = newUser;
265             } else if (newDefault == null && mPaymentDefaults.currentPreferred != null) {
266                 paymentDefaultChanged = true;
267                 mPaymentDefaults.currentPreferred = newDefault;
268                 mPaymentDefaults.mUserHandle = newUser;
269             } else {
270                 // Same default as before
271             }
272         }
273         // Notify if anything changed
274         if (!mWalletRoleObserver.isWalletRoleFeatureEnabled() && (paymentDefaultChanged || force)) {
275             mCallback.onPreferredPaymentServiceChanged(
276                     new ComponentNameAndUser(newUser.getIdentifier(), newDefault));
277         }
278         if (paymentPreferForegroundChanged || force) {
279             computePreferredForegroundService();
280         }
281     }
282 
computePreferredForegroundService()283     void computePreferredForegroundService() {
284         ComponentName preferredService = null;
285         int preferredServiceUserId;
286         boolean changed = false;
287         synchronized (mLock) {
288             // Prio 1: next tap default
289             preferredService = mNextTapDefault;
290             preferredServiceUserId = mNextTapDefaultUserId;
291             if (preferredService == null) {
292                 // Prio 2: foreground requested by app
293                 preferredService = mForegroundRequested;
294                 preferredServiceUserId =
295                         UserHandle.getUserHandleForUid(mForegroundUid).getIdentifier();
296             }
297             if (preferredService != null && (!preferredService.equals(mForegroundCurrent)
298                     || preferredServiceUserId
299                     != UserHandle.getUserHandleForUid(mForegroundCurrentUid).getIdentifier())) {
300                 mForegroundCurrent = preferredService;
301                 mForegroundCurrentUid = mForegroundUid;
302                 changed = true;
303             } else if (preferredService == null && mForegroundCurrent != null) {
304                 mForegroundCurrent = preferredService;
305                 mForegroundCurrentUid = mForegroundUid;
306                 changed = true;
307             }
308         }
309         // Notify if anything changed
310         if (changed) {
311             mCallback.onPreferredForegroundServiceChanged(
312                     new ComponentNameAndUser(preferredServiceUserId, preferredService));
313         }
314     }
315 
316     /**
317      *  Set default service for next tap
318      */
setDefaultForNextTap(int userId, ComponentName service)319     public boolean setDefaultForNextTap(int userId, ComponentName service) {
320         // This is a trusted API, so update without checking
321         synchronized (mLock) {
322             mNextTapDefault = service;
323             mNextTapDefaultUserId = userId;
324         }
325         computePreferredForegroundService();
326         return true;
327     }
328 
onServicesUpdated()329     public void onServicesUpdated() {
330         // If this service is the current foreground service, verify
331         // there are no conflicts
332         boolean foregroundChanged = false;
333         synchronized (mLock) {
334             // Check if the current foreground service is still allowed to override;
335             // it could have registered new AIDs that make it conflict with user
336             // preferences.
337             if (mForegroundCurrent != null) {
338                 if (!isForegroundAllowedLocked(mForegroundCurrent, mForegroundCurrentUid))  {
339                     Log.d(TAG, "onServicesUpdated: Removing foreground preferred service.");
340                     mForegroundRequested = null;
341                     mForegroundUid = -1;
342                     mForegroundCurrentUid = -1;
343                     foregroundChanged = true;
344                 }
345             } else {
346                 // Don't care about this service
347             }
348         }
349         if (foregroundChanged) {
350             computePreferredForegroundService();
351         }
352 
353         if (mWalletRoleObserver.isWalletRoleFeatureEnabled()
354                 && mUserIdDefaultWalletHolder >= 0) {
355             PackageAndUser roleHolder = mWalletRoleObserver
356                     .getDefaultWalletRoleHolder(mUserIdDefaultWalletHolder);
357             onWalletRoleHolderChanged(roleHolder.getPackage(), roleHolder.getUserId());
358         }
359     }
360 
361     // Verifies whether a service is allowed to register as preferred
isForegroundAllowedLocked(ComponentName service, int callingUid)362     boolean isForegroundAllowedLocked(ComponentName service, int callingUid) {
363         if (service.equals(mPaymentDefaults.currentPreferred)) {
364             // If the requester is already the payment default, allow it to request foreground
365             // override as well (it could use this to make sure it handles AIDs of category OTHER)
366             return true;
367         }
368         ApduServiceInfo serviceInfo = mServiceCache.getService(
369                 UserHandle.getUserHandleForUid(callingUid).getIdentifier(), service);
370         if (serviceInfo == null) {
371             Log.d(TAG, "isForegroundAllowedLocked: Requested foreground service "
372                     + "unexpectedly removed");
373             return false;
374         }
375         // Do some quick checking
376         if (!mPaymentDefaults.preferForeground) {
377             // Foreground apps are not allowed to override payment default
378             // Check if this app registers payment AIDs, in which case we'll fail anyway
379             if (serviceInfo.hasCategory(CardEmulation.CATEGORY_PAYMENT)) {
380                 Log.d(TAG, "isForegroundAllowedLocked: User doesn't allow payment "
381                         + "services to be overridden");
382                 return false;
383             }
384             // If no payment AIDs, get AIDs of category other, and see if there's any
385             // conflict with payment AIDs of current default payment app. That means
386             // the current default payment app said this was a payment AID, and the
387             // foreground app says it was not. In this case we'll still prefer the payment
388             // app, since that is the one that the user has explicitly selected (and said
389             // it's not allowed to be overridden).
390             final List<String> otherAids = serviceInfo.getAids();
391             ApduServiceInfo paymentServiceInfo = mServiceCache.getService(
392                     mPaymentDefaults.mUserHandle.getIdentifier(),
393                     mPaymentDefaults.currentPreferred);
394             if (paymentServiceInfo != null && otherAids != null && otherAids.size() > 0) {
395                 for (String aid : otherAids) {
396                     RegisteredAidCache.AidResolveInfo resolveInfo = mAidCache.resolveAid(aid);
397                     if (CardEmulation.CATEGORY_PAYMENT.equals(resolveInfo.category) &&
398                             paymentServiceInfo.equals(resolveInfo.defaultService)) {
399                         if (DBG) {
400                             Log.d(TAG, "isForegroundAllowedLocked: AID " + aid
401                                     + " is handled by the default payment app,"
402                                     + " and the user has not allowed payments to be overridden.");
403                         }
404                         return false;
405                     }
406                 }
407                 return true;
408             } else {
409                 // Could not find payment service or fg app doesn't register other AIDs;
410                 // okay to proceed.
411                 return true;
412             }
413         } else {
414             // Payment allows override, so allow anything.
415             return true;
416         }
417     }
418 
registerPreferredForegroundService(ComponentName service, int callingUid)419     public boolean registerPreferredForegroundService(ComponentName service, int callingUid) {
420         boolean success = false;
421         synchronized (mLock) {
422             if (isForegroundAllowedLocked(service, callingUid)) {
423                 if (mForegroundUtils.registerUidToBackgroundCallback(this, callingUid)) {
424                     mForegroundRequested = service;
425                     mForegroundUid = callingUid;
426                     success = true;
427                 } else {
428                     Log.e(TAG, "registerPreferredForegroundService: Calling UID is not in "
429                             + "the foreground, ignoring!");
430                     success = false;
431                 }
432             } else {
433                 Log.e(TAG, "registerPreferredForegroundService: Requested foreground service "
434                         + "conflicts or was removed");
435             }
436         }
437         if (success) {
438             computePreferredForegroundService();
439         }
440         return success;
441     }
442 
unregisterForegroundService(int uid)443     boolean unregisterForegroundService(int uid) {
444         boolean success = false;
445         synchronized (mLock) {
446             if (mForegroundUid == uid) {
447                 mForegroundRequested = null;
448                 mForegroundUid = -1;
449                 success = true;
450             } // else, other UID in foreground
451         }
452         if (success) {
453             computePreferredForegroundService();
454         }
455         return success;
456     }
457 
unregisteredPreferredForegroundService(int callingUid)458     public boolean unregisteredPreferredForegroundService(int callingUid) {
459         // Verify the calling UID is in the foreground
460         if (mForegroundUtils.isInForeground(callingUid)) {
461             return unregisterForegroundService(callingUid);
462         } else {
463             Log.e(TAG, "unregisteredPreferredForegroundService: Calling UID is not in "
464                     + "the foreground, ignoring!");
465             return false;
466         }
467     }
468 
469     @Override
onUidToBackground(int uid)470     public void onUidToBackground(int uid) {
471         unregisterForegroundService(uid);
472     }
473 
onHostEmulationActivated()474     public void onHostEmulationActivated() {
475         synchronized (mLock) {
476             mClearNextTapDefault = (mNextTapDefault != null);
477         }
478     }
479 
onHostEmulationDeactivated()480     public void onHostEmulationDeactivated() {
481         // If we had any next tap defaults set, clear them out
482         boolean changed = false;
483         synchronized (mLock) {
484             if (mClearNextTapDefault) {
485                 // The reason we need to check this boolean is because the next tap
486                 // default may have been set while the user held the phone
487                 // on the reader; when the user then removes his phone from
488                 // the reader (causing the "onHostEmulationDeactivated" event),
489                 // the next tap default would immediately be cleared
490                 // again. Instead, clear out defaults only if a next tap default
491                 // had already been set at time of activation, which is captured
492                 // by mClearNextTapDefault.
493                 if (mNextTapDefault != null) {
494                     mNextTapDefault = null;
495                     changed = true;
496                 }
497                 mClearNextTapDefault = false;
498             }
499         }
500         if (changed) {
501             computePreferredForegroundService();
502         }
503     }
504 
onUserSwitched(int userId)505     public void onUserSwitched(int userId) {
506         loadDefaultsFromSettings(userId, true);
507     }
508 
packageHasPreferredService(String packageName)509     public boolean packageHasPreferredService(String packageName) {
510         if (packageName == null) return false;
511         synchronized (mLock) {
512             if (mPaymentDefaults.currentPreferred != null
513                     && packageName.equals(mPaymentDefaults.currentPreferred.getPackageName())) {
514                 return true;
515             }
516             return (mForegroundCurrent != null
517                     && packageName.equals(mForegroundCurrent.getPackageName()));
518         }
519     }
520 
dump(FileDescriptor fd, PrintWriter pw, String[] args)521     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
522         synchronized (mLock) {
523             pw.println("Preferred services (in order of importance): ");
524             pw.println("    *** Current preferred foreground service: " + mForegroundCurrent
525                     + " (UID:" + mForegroundCurrentUid + ")");
526             if (mWalletRoleObserver.isWalletRoleFeatureEnabled()) {
527                 boolean roleNotSet = mDefaultWalletHolderPaymentService == null;
528                 pw.println("    *** Current wallet payment service: "
529                         + (roleNotSet ? "null" :
530                         mDefaultWalletHolderPaymentService) + "("
531                         + (roleNotSet ? "no user"
532                         : getUserName(UserHandle.of(mUserIdDefaultWalletHolder))) + ")");
533             }
534             pw.println("    *** Current preferred payment service: "
535                     + mPaymentDefaults.currentPreferred + "("
536                     + getUserName(mPaymentDefaults.mUserHandle) + ")");
537             pw.println("        Next tap default: " + mNextTapDefault
538                     + " (" + getUserName(UserHandle.of(mNextTapDefaultUserId)) + ")");
539             pw.println("        Default for foreground app (UID: " + mForegroundUid
540                     + "): " + mForegroundRequested);
541             if (!mWalletRoleObserver.isWalletRoleFeatureEnabled()) {
542                 pw.println("        Default in payment settings: " + mPaymentDefaults.settingsDefault
543                         + "(" + getUserName(mPaymentDefaults.mUserHandle) + ")");
544                 pw.println("        Payment settings allows override: "
545                         + mPaymentDefaults.preferForeground);
546             }
547             pw.println("");
548         }
549     }
550 
getUserName(UserHandle uh)551     private String getUserName(UserHandle uh) {
552         if (uh == null) {
553             return null;
554         }
555         UserManager um = mContext.createContextAsUser(
556                 uh, /*flags=*/0).getSystemService(UserManager.class);
557         if (um == null) {
558             return null;
559         }
560         return com.android.nfc.Utils.maskSubstring(um.getUserName(), 3);
561     }
562 
563     /**
564      * Dump debugging information as a PreferredServicesProto
565      *
566      * Note:
567      * See proto definition in frameworks/base/core/proto/android/nfc/card_emulation.proto
568      * When writing a nested message, must call {@link ProtoOutputStream#start(long)} before and
569      * {@link ProtoOutputStream#end(long)} after.
570      * Never reuse a proto field number. When removing a field, mark it as reserved.
571      */
dumpDebug(ProtoOutputStream proto)572     void dumpDebug(ProtoOutputStream proto) {
573         synchronized (mLock) {
574             if (mForegroundCurrent != null) {
575                 Utils.dumpDebugComponentName(
576                         mForegroundCurrent, proto, PreferredServicesProto.FOREGROUND_CURRENT);
577             }
578             if (mPaymentDefaults.currentPreferred != null) {
579                 Utils.dumpDebugComponentName(
580                         mPaymentDefaults.currentPreferred, proto,
581                         PreferredServicesProto.FOREGROUND_CURRENT);
582             }
583             if (mWalletRoleObserver.isWalletRoleFeatureEnabled()) {
584                 if (mDefaultWalletHolderPaymentService != null) {
585                     Utils.dumpDebugComponentName(
586                             mDefaultWalletHolderPaymentService, proto,
587                             PreferredServicesProto.WALLET_ROLE_HOLDER_PAYMENT_SERVICE);
588                 }
589             }
590             if (mNextTapDefault != null) {
591                 Utils.dumpDebugComponentName(
592                         mNextTapDefault, proto, PreferredServicesProto.NEXT_TAP_DEFAULT);
593             }
594             proto.write(PreferredServicesProto.FOREGROUND_UID, mForegroundUid);
595             if (mForegroundRequested != null) {
596                 Utils.dumpDebugComponentName(
597                         mForegroundRequested, proto, PreferredServicesProto.FOREGROUND_REQUESTED);
598             }
599             if (!mWalletRoleObserver.isWalletRoleFeatureEnabled()) {
600                 if (mPaymentDefaults.settingsDefault != null) {
601                     Utils.dumpDebugComponentName(
602                             mPaymentDefaults.settingsDefault, proto,
603                             PreferredServicesProto.SETTINGS_DEFAULT);
604                 }
605                 proto.write(PreferredServicesProto.PREFER_FOREGROUND,
606                         mPaymentDefaults.preferForeground);
607             }
608         }
609     }
610 }
611