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.Constants; 25 import android.nfc.cardemulation.ApduServiceInfo; 26 import android.nfc.cardemulation.CardEmulation; 27 import android.nfc.cardemulation.Utils; 28 import android.os.Build; 29 import android.os.Handler; 30 import android.os.Looper; 31 import android.os.UserHandle; 32 import android.os.UserManager; 33 import android.permission.flags.Flags; 34 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(int userId, ComponentName service)111 void onPreferredPaymentServiceChanged(int userId, ComponentName service); 112 /** 113 * Notify when preferred foreground service is changed 114 */ onPreferredForegroundServiceChanged(int userId, ComponentName service)115 void onPreferredForegroundServiceChanged(int userId, ComponentName 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 String holder = mWalletRoleObserver.getDefaultWalletRoleHolder(currentUserId); 144 onWalletRoleHolderChanged(holder, currentUserId); 145 } 146 } 147 148 private final class SettingsObserver extends ContentObserver { SettingsObserver(Handler handler)149 public SettingsObserver(Handler handler) { 150 super(handler); 151 } 152 153 @Override onChange(boolean selfChange, Uri uri)154 public void onChange(boolean selfChange, Uri uri) { 155 super.onChange(selfChange, uri); 156 // Do it just for the current user. If it was in fact 157 // a change made for another user, we'll sync it down 158 // on user switch. 159 int currentUser = ActivityManager.getCurrentUser(); 160 loadDefaultsFromSettings(currentUser, false); 161 } 162 }; 163 164 @TargetApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) onWalletRoleHolderChanged(String defaultWalletHolderPackageName, int userId)165 public void onWalletRoleHolderChanged(String defaultWalletHolderPackageName, int userId) { 166 if (defaultWalletHolderPackageName == null) { 167 mDefaultWalletHolderPaymentService = null; 168 mCallback.onPreferredPaymentServiceChanged(userId, null); 169 return; 170 } 171 List<ApduServiceInfo> serviceInfos = mServiceCache.getInstalledServices(userId); 172 List<ComponentName> roleHolderPaymentServices = new ArrayList<>(); 173 int servicesCount = serviceInfos.size(); 174 for(int i = 0; i < servicesCount; i++) { 175 ApduServiceInfo serviceInfo = serviceInfos.get(i); 176 ComponentName componentName = serviceInfo.getComponent(); 177 if (componentName.getPackageName() 178 .equals(defaultWalletHolderPackageName)) { 179 List<String> aids = serviceInfo.getAids(); 180 int aidsCount = aids.size(); 181 for (int j = 0; j < aidsCount; j++) { 182 String aid = aids.get(j); 183 if (serviceInfo.getCategoryForAid(aid) 184 .equals(CardEmulation.CATEGORY_PAYMENT)) { 185 roleHolderPaymentServices.add(componentName); 186 break; 187 } 188 } 189 } 190 } 191 mUserIdDefaultWalletHolder = userId; 192 ComponentName candidate = !roleHolderPaymentServices.isEmpty() 193 ? roleHolderPaymentServices.get(0) : null; 194 if (!Objects.equals(candidate, mDefaultWalletHolderPaymentService)) { 195 mCallback.onPreferredPaymentServiceChanged(userId, candidate); 196 } 197 mDefaultWalletHolderPaymentService = candidate; 198 } 199 loadDefaultsFromSettings(int userId, boolean force)200 void loadDefaultsFromSettings(int userId, boolean force) { 201 boolean paymentDefaultChanged = false; 202 boolean paymentPreferForegroundChanged = false; 203 // Load current payment default from settings 204 UserHandle currentUser = UserHandle.of(ActivityManager.getCurrentUser()); 205 UserManager um = mContext.createContextAsUser(currentUser, /*flags=*/0) 206 .getSystemService(UserManager.class); 207 List<UserHandle> userHandles = um.getEnabledProfiles(); 208 209 String name = null; 210 String newDefaultName = null; 211 UserHandle newUser = null; 212 // search for default payment setting within enabled profiles 213 for (UserHandle uh : userHandles) { 214 try { 215 name = Settings.Secure.getString( 216 mContext.createContextAsUser(uh, 0).getContentResolver(), 217 Constants.SETTINGS_SECURE_NFC_PAYMENT_DEFAULT_COMPONENT); 218 } catch (IllegalStateException e) { 219 Log.d(TAG, "Fail to get PackageManager for user: " + uh); 220 continue; 221 } 222 223 if (name != null) { 224 newUser = uh; 225 newDefaultName = name; 226 } 227 if (uh.getIdentifier() == userId) { 228 currentUser = uh; 229 } 230 } 231 if (currentUser == null) { 232 Log.e(TAG, "NULL/ Error fetching currentUser info"); 233 return; 234 } 235 // no default payment setting in all profles 236 if (newUser == null) { 237 newUser = currentUser; 238 } 239 ComponentName newDefault = newDefaultName != null 240 ? ComponentName.unflattenFromString(newDefaultName) : null; 241 boolean preferForeground = false; 242 try { 243 // get the setting from the main user instead of from the user profiles. 244 preferForeground = mWalletRoleObserver.isWalletRoleFeatureEnabled() 245 || Settings.Secure.getInt(mContext 246 .createContextAsUser(currentUser, 0).getContentResolver(), 247 Constants.SETTINGS_SECURE_NFC_PAYMENT_FOREGROUND) != 0; 248 } catch (SettingNotFoundException e) { 249 } 250 synchronized (mLock) { 251 paymentPreferForegroundChanged = (preferForeground != mPaymentDefaults.preferForeground); 252 mPaymentDefaults.preferForeground = preferForeground; 253 254 mPaymentDefaults.settingsDefault = newDefault; 255 if (newDefault != null && (!newDefault.equals(mPaymentDefaults.currentPreferred) 256 || mPaymentDefaults.mUserHandle.getIdentifier() != newUser.getIdentifier())) { 257 paymentDefaultChanged = true; 258 mPaymentDefaults.currentPreferred = newDefault; 259 mPaymentDefaults.mUserHandle = newUser; 260 } else if (newDefault == null && mPaymentDefaults.currentPreferred != null) { 261 paymentDefaultChanged = true; 262 mPaymentDefaults.currentPreferred = newDefault; 263 mPaymentDefaults.mUserHandle = newUser; 264 } else { 265 // Same default as before 266 } 267 } 268 // Notify if anything changed 269 if (!mWalletRoleObserver.isWalletRoleFeatureEnabled() && (paymentDefaultChanged || force)) { 270 mCallback.onPreferredPaymentServiceChanged(newUser.getIdentifier(), newDefault); 271 } 272 if (paymentPreferForegroundChanged || force) { 273 computePreferredForegroundService(); 274 } 275 } 276 computePreferredForegroundService()277 void computePreferredForegroundService() { 278 ComponentName preferredService = null; 279 int preferredServiceUserId; 280 boolean changed = false; 281 synchronized (mLock) { 282 // Prio 1: next tap default 283 preferredService = mNextTapDefault; 284 preferredServiceUserId = mNextTapDefaultUserId; 285 if (preferredService == null) { 286 // Prio 2: foreground requested by app 287 preferredService = mForegroundRequested; 288 preferredServiceUserId = 289 UserHandle.getUserHandleForUid(mForegroundUid).getIdentifier(); 290 } 291 if (preferredService != null && (!preferredService.equals(mForegroundCurrent) 292 || preferredServiceUserId 293 != UserHandle.getUserHandleForUid(mForegroundCurrentUid).getIdentifier())) { 294 mForegroundCurrent = preferredService; 295 mForegroundCurrentUid = mForegroundUid; 296 changed = true; 297 } else if (preferredService == null && mForegroundCurrent != null){ 298 mForegroundCurrent = preferredService; 299 mForegroundCurrentUid = mForegroundUid; 300 changed = true; 301 } 302 } 303 // Notify if anything changed 304 if (changed) { 305 mCallback.onPreferredForegroundServiceChanged(preferredServiceUserId, preferredService); 306 } 307 } 308 309 /** 310 * Set default service for next tap 311 */ setDefaultForNextTap(int userId, ComponentName service)312 public boolean setDefaultForNextTap(int userId, ComponentName service) { 313 // This is a trusted API, so update without checking 314 synchronized (mLock) { 315 mNextTapDefault = service; 316 mNextTapDefaultUserId = userId; 317 } 318 computePreferredForegroundService(); 319 return true; 320 } 321 onServicesUpdated()322 public void onServicesUpdated() { 323 // If this service is the current foreground service, verify 324 // there are no conflicts 325 boolean foregroundChanged = false; 326 synchronized (mLock) { 327 // Check if the current foreground service is still allowed to override; 328 // it could have registered new AIDs that make it conflict with user 329 // preferences. 330 if (mForegroundCurrent != null) { 331 if (!isForegroundAllowedLocked(mForegroundCurrent, mForegroundCurrentUid)) { 332 Log.d(TAG, "Removing foreground preferred service."); 333 mForegroundRequested = null; 334 mForegroundUid = -1; 335 mForegroundCurrentUid = -1; 336 foregroundChanged = true; 337 } 338 } else { 339 // Don't care about this service 340 } 341 } 342 if (foregroundChanged) { 343 computePreferredForegroundService(); 344 } 345 346 if(mWalletRoleObserver.isWalletRoleFeatureEnabled() 347 && mUserIdDefaultWalletHolder >= 0) { 348 onWalletRoleHolderChanged(mWalletRoleObserver 349 .getDefaultWalletRoleHolder(mUserIdDefaultWalletHolder), 350 mUserIdDefaultWalletHolder); 351 } 352 } 353 354 // Verifies whether a service is allowed to register as preferred isForegroundAllowedLocked(ComponentName service, int callingUid)355 boolean isForegroundAllowedLocked(ComponentName service, int callingUid) { 356 if (service.equals(mPaymentDefaults.currentPreferred)) { 357 // If the requester is already the payment default, allow it to request foreground 358 // override as well (it could use this to make sure it handles AIDs of category OTHER) 359 return true; 360 } 361 ApduServiceInfo serviceInfo = mServiceCache.getService( 362 UserHandle.getUserHandleForUid(callingUid).getIdentifier(), service); 363 if (serviceInfo == null) { 364 Log.d(TAG, "Requested foreground service unexpectedly removed"); 365 return false; 366 } 367 // Do some quick checking 368 if (!mPaymentDefaults.preferForeground) { 369 // Foreground apps are not allowed to override payment default 370 // Check if this app registers payment AIDs, in which case we'll fail anyway 371 if (serviceInfo.hasCategory(CardEmulation.CATEGORY_PAYMENT)) { 372 Log.d(TAG, "User doesn't allow payment services to be overridden."); 373 return false; 374 } 375 // If no payment AIDs, get AIDs of category other, and see if there's any 376 // conflict with payment AIDs of current default payment app. That means 377 // the current default payment app said this was a payment AID, and the 378 // foreground app says it was not. In this case we'll still prefer the payment 379 // app, since that is the one that the user has explicitly selected (and said 380 // it's not allowed to be overridden). 381 final List<String> otherAids = serviceInfo.getAids(); 382 ApduServiceInfo paymentServiceInfo = mServiceCache.getService( 383 mPaymentDefaults.mUserHandle.getIdentifier(), 384 mPaymentDefaults.currentPreferred); 385 if (paymentServiceInfo != null && otherAids != null && otherAids.size() > 0) { 386 for (String aid : otherAids) { 387 RegisteredAidCache.AidResolveInfo resolveInfo = mAidCache.resolveAid(aid); 388 if (CardEmulation.CATEGORY_PAYMENT.equals(resolveInfo.category) && 389 paymentServiceInfo.equals(resolveInfo.defaultService)) { 390 if (DBG) Log.d(TAG, "AID " + aid + " is handled by the default payment app," 391 + " and the user has not allowed payments to be overridden."); 392 return false; 393 } 394 } 395 return true; 396 } else { 397 // Could not find payment service or fg app doesn't register other AIDs; 398 // okay to proceed. 399 return true; 400 } 401 } else { 402 // Payment allows override, so allow anything. 403 return true; 404 } 405 } 406 registerPreferredForegroundService(ComponentName service, int callingUid)407 public boolean registerPreferredForegroundService(ComponentName service, int callingUid) { 408 boolean success = false; 409 synchronized (mLock) { 410 if (isForegroundAllowedLocked(service, callingUid)) { 411 if (mForegroundUtils.registerUidToBackgroundCallback(this, callingUid)) { 412 mForegroundRequested = service; 413 mForegroundUid = callingUid; 414 success = true; 415 } else { 416 Log.e(TAG, "Calling UID is not in the foreground, ignorning!"); 417 success = false; 418 } 419 } else { 420 Log.e(TAG, "Requested foreground service conflicts or was removed."); 421 } 422 } 423 if (success) { 424 computePreferredForegroundService(); 425 } 426 return success; 427 } 428 unregisterForegroundService(int uid)429 boolean unregisterForegroundService(int uid) { 430 boolean success = false; 431 synchronized (mLock) { 432 if (mForegroundUid == uid) { 433 mForegroundRequested = null; 434 mForegroundUid = -1; 435 success = true; 436 } // else, other UID in foreground 437 } 438 if (success) { 439 computePreferredForegroundService(); 440 } 441 return success; 442 } 443 unregisteredPreferredForegroundService(int callingUid)444 public boolean unregisteredPreferredForegroundService(int callingUid) { 445 // Verify the calling UID is in the foreground 446 if (mForegroundUtils.isInForeground(callingUid)) { 447 return unregisterForegroundService(callingUid); 448 } else { 449 Log.e(TAG, "Calling UID is not in the foreground, ignorning!"); 450 return false; 451 } 452 } 453 454 @Override onUidToBackground(int uid)455 public void onUidToBackground(int uid) { 456 unregisterForegroundService(uid); 457 } 458 onHostEmulationActivated()459 public void onHostEmulationActivated() { 460 synchronized (mLock) { 461 mClearNextTapDefault = (mNextTapDefault != null); 462 } 463 } 464 onHostEmulationDeactivated()465 public void onHostEmulationDeactivated() { 466 // If we had any next tap defaults set, clear them out 467 boolean changed = false; 468 synchronized (mLock) { 469 if (mClearNextTapDefault) { 470 // The reason we need to check this boolean is because the next tap 471 // default may have been set while the user held the phone 472 // on the reader; when the user then removes his phone from 473 // the reader (causing the "onHostEmulationDeactivated" event), 474 // the next tap default would immediately be cleared 475 // again. Instead, clear out defaults only if a next tap default 476 // had already been set at time of activation, which is captured 477 // by mClearNextTapDefault. 478 if (mNextTapDefault != null) { 479 mNextTapDefault = null; 480 changed = true; 481 } 482 mClearNextTapDefault = false; 483 } 484 } 485 if (changed) { 486 computePreferredForegroundService(); 487 } 488 } 489 onUserSwitched(int userId)490 public void onUserSwitched(int userId) { 491 loadDefaultsFromSettings(userId, true); 492 } 493 packageHasPreferredService(String packageName)494 public boolean packageHasPreferredService(String packageName) { 495 if (packageName == null) return false; 496 synchronized (mLock) { 497 if (mPaymentDefaults.currentPreferred != null 498 && packageName.equals(mPaymentDefaults.currentPreferred.getPackageName())) { 499 return true; 500 } 501 return (mForegroundCurrent != null 502 && packageName.equals(mForegroundCurrent.getPackageName())); 503 } 504 } 505 dump(FileDescriptor fd, PrintWriter pw, String[] args)506 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 507 synchronized (mLock) { 508 pw.println("Preferred services (in order of importance): "); 509 pw.println(" *** Current preferred foreground service: " + mForegroundCurrent 510 + " (UID:" + mForegroundCurrentUid + ")"); 511 if (mWalletRoleObserver.isWalletRoleFeatureEnabled()) { 512 boolean roleNotSet = mDefaultWalletHolderPaymentService == null; 513 pw.println(" *** Current wallet payment service: " 514 + (roleNotSet ? "null" : 515 mDefaultWalletHolderPaymentService) + "(" 516 + (roleNotSet ? "no user" 517 : getUserName(UserHandle.of(mUserIdDefaultWalletHolder))) + ")"); 518 } 519 pw.println(" *** Current preferred payment service: " 520 + mPaymentDefaults.currentPreferred + "(" 521 + getUserName(mPaymentDefaults.mUserHandle) + ")"); 522 pw.println(" Next tap default: " + mNextTapDefault 523 + " (" + getUserName(UserHandle.of(mNextTapDefaultUserId)) + ")"); 524 pw.println(" Default for foreground app (UID: " + mForegroundUid 525 + "): " + mForegroundRequested); 526 if (!mWalletRoleObserver.isWalletRoleFeatureEnabled()) { 527 pw.println(" Default in payment settings: " + mPaymentDefaults.settingsDefault 528 + "(" + getUserName(mPaymentDefaults.mUserHandle) + ")"); 529 pw.println(" Payment settings allows override: " 530 + mPaymentDefaults.preferForeground); 531 } 532 pw.println(""); 533 } 534 } 535 getUserName(UserHandle uh)536 private String getUserName(UserHandle uh) { 537 if (uh == null) { 538 return null; 539 } 540 UserManager um = mContext.createContextAsUser( 541 uh, /*flags=*/0).getSystemService(UserManager.class); 542 if (um == null) { 543 return null; 544 } 545 return com.android.nfc.Utils.maskSubstring(um.getUserName(), 3); 546 } 547 548 /** 549 * Dump debugging information as a PreferredServicesProto 550 * 551 * Note: 552 * See proto definition in frameworks/base/core/proto/android/nfc/card_emulation.proto 553 * When writing a nested message, must call {@link ProtoOutputStream#start(long)} before and 554 * {@link ProtoOutputStream#end(long)} after. 555 * Never reuse a proto field number. When removing a field, mark it as reserved. 556 */ dumpDebug(ProtoOutputStream proto)557 void dumpDebug(ProtoOutputStream proto) { 558 synchronized (mLock) { 559 if (mForegroundCurrent != null) { 560 Utils.dumpDebugComponentName( 561 mForegroundCurrent, proto, PreferredServicesProto.FOREGROUND_CURRENT); 562 } 563 if (mPaymentDefaults.currentPreferred != null) { 564 Utils.dumpDebugComponentName( 565 mPaymentDefaults.currentPreferred, proto, 566 PreferredServicesProto.FOREGROUND_CURRENT); 567 } 568 if (mWalletRoleObserver.isWalletRoleFeatureEnabled()) { 569 if (mDefaultWalletHolderPaymentService != null) { 570 Utils.dumpDebugComponentName( 571 mDefaultWalletHolderPaymentService, proto, 572 PreferredServicesProto.WALLET_ROLE_HOLDER_PAYMENT_SERVICE); 573 } 574 } 575 if (mNextTapDefault != null) { 576 Utils.dumpDebugComponentName( 577 mNextTapDefault, proto, PreferredServicesProto.NEXT_TAP_DEFAULT); 578 } 579 proto.write(PreferredServicesProto.FOREGROUND_UID, mForegroundUid); 580 if (mForegroundRequested != null) { 581 Utils.dumpDebugComponentName( 582 mForegroundRequested, proto, PreferredServicesProto.FOREGROUND_REQUESTED); 583 } 584 if (!mWalletRoleObserver.isWalletRoleFeatureEnabled()) { 585 if (mPaymentDefaults.settingsDefault != null) { 586 Utils.dumpDebugComponentName( 587 mPaymentDefaults.settingsDefault, proto, 588 PreferredServicesProto.SETTINGS_DEFAULT); 589 } 590 proto.write(PreferredServicesProto.PREFER_FOREGROUND, 591 mPaymentDefaults.preferForeground); 592 } 593 } 594 } 595 } 596