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 17 package com.android.server.telecom; 18 19 import android.Manifest; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.content.BroadcastReceiver; 23 import android.content.ComponentName; 24 import android.content.Context; 25 import android.content.Intent; 26 import android.content.IntentFilter; 27 import android.content.pm.PackageManager; 28 import android.content.pm.ResolveInfo; 29 import android.content.pm.ServiceInfo; 30 import android.content.pm.UserInfo; 31 import android.graphics.Bitmap; 32 import android.graphics.BitmapFactory; 33 import android.graphics.drawable.Icon; 34 import android.net.Uri; 35 import android.os.Binder; 36 import android.os.Bundle; 37 import android.os.AsyncTask; 38 import android.os.PersistableBundle; 39 import android.os.Process; 40 import android.os.UserHandle; 41 import android.os.UserManager; 42 import android.provider.Settings; 43 import android.telecom.CallAudioState; 44 import android.telecom.ConnectionService; 45 import android.telecom.Log; 46 import android.telecom.PhoneAccount; 47 import android.telecom.PhoneAccountHandle; 48 import android.telephony.CarrierConfigManager; 49 import android.telephony.PhoneNumberUtils; 50 import android.telephony.SubscriptionInfo; 51 import android.telephony.SubscriptionManager; 52 import android.telephony.TelephonyManager; 53 import android.text.TextUtils; 54 import android.util.AtomicFile; 55 import android.util.Base64; 56 import android.util.EventLog; 57 import android.util.Xml; 58 59 // TODO: Needed for move to system service: import com.android.internal.R; 60 import com.android.internal.annotations.VisibleForTesting; 61 import com.android.internal.telephony.flags.FeatureFlags; 62 import com.android.internal.util.IndentingPrintWriter; 63 import com.android.internal.util.XmlUtils; 64 import com.android.modules.utils.ModifiedUtf8; 65 import com.android.server.telecom.flags.Flags; 66 67 import org.xmlpull.v1.XmlPullParser; 68 import org.xmlpull.v1.XmlPullParserException; 69 import org.xmlpull.v1.XmlSerializer; 70 71 import java.io.ByteArrayInputStream; 72 import java.io.ByteArrayOutputStream; 73 import java.io.File; 74 import java.io.FileNotFoundException; 75 import java.io.FileOutputStream; 76 import java.io.IOException; 77 import java.io.InputStream; 78 import java.lang.Integer; 79 import java.lang.SecurityException; 80 import java.lang.String; 81 import java.util.ArrayList; 82 import java.util.Arrays; 83 import java.util.Collections; 84 import java.util.Comparator; 85 import java.util.HashMap; 86 import java.util.HashSet; 87 import java.util.Iterator; 88 import java.util.List; 89 import java.util.Map; 90 import java.util.Objects; 91 import java.util.Set; 92 import java.util.concurrent.ConcurrentHashMap; 93 import java.util.concurrent.CopyOnWriteArrayList; 94 import java.util.stream.Collectors; 95 96 /** 97 * Handles writing and reading PhoneAccountHandle registration entries. This is a simple verbatim 98 * delegate for all the account handling methods on {@link android.telecom.TelecomManager} as 99 * implemented in {@link TelecomServiceImpl}, with the notable exception that 100 * {@link TelecomServiceImpl} is responsible for security checking to make sure that the caller has 101 * proper authority over the {@code ComponentName}s they are declaring in their 102 * {@code PhoneAccountHandle}s. 103 * 104 * 105 * -- About Users and Phone Accounts -- 106 * 107 * We store all phone accounts for all users in a single place, which means that there are three 108 * users that we have to deal with in code: 109 * 1) The Android User that is currently active on the device. 110 * 2) The user which owns/registers the phone account. 111 * 3) The user running the app that is requesting the phone account information. 112 * 113 * For example, I have a device with 2 users, primary (A) and secondary (B), and the secondary user 114 * has a work profile running as another user (B2). Each user/profile only have the visibility of 115 * phone accounts owned by them. Lets say, user B (settings) is requesting a list of phone accounts, 116 * and the list only contains phone accounts owned by user B and accounts with 117 * {@link PhoneAccount#CAPABILITY_MULTI_USER}. 118 * 119 * In practice, (2) is stored with the phone account handle and is part of the handle's ID. (1) is 120 * saved in {@link #mCurrentUserHandle} and (3) we get from Binder.getCallingUser(). We check these 121 * users for visibility before returning any phone accounts. 122 */ 123 public class PhoneAccountRegistrar { 124 125 public static final PhoneAccountHandle NO_ACCOUNT_SELECTED = 126 new PhoneAccountHandle(new ComponentName("null", "null"), "NO_ACCOUNT_SELECTED"); 127 128 public abstract static class Listener { onAccountsChanged(PhoneAccountRegistrar registrar)129 public void onAccountsChanged(PhoneAccountRegistrar registrar) {} onDefaultOutgoingChanged(PhoneAccountRegistrar registrar)130 public void onDefaultOutgoingChanged(PhoneAccountRegistrar registrar) {} onSimCallManagerChanged(PhoneAccountRegistrar registrar)131 public void onSimCallManagerChanged(PhoneAccountRegistrar registrar) {} onPhoneAccountRegistered(PhoneAccountRegistrar registrar, PhoneAccountHandle handle)132 public void onPhoneAccountRegistered(PhoneAccountRegistrar registrar, 133 PhoneAccountHandle handle) {} onPhoneAccountUnRegistered(PhoneAccountRegistrar registrar, PhoneAccountHandle handle)134 public void onPhoneAccountUnRegistered(PhoneAccountRegistrar registrar, 135 PhoneAccountHandle handle) {} onPhoneAccountChanged(PhoneAccountRegistrar registrar, PhoneAccount phoneAccount)136 public void onPhoneAccountChanged(PhoneAccountRegistrar registrar, 137 PhoneAccount phoneAccount) {} 138 } 139 140 /** 141 * Receiver for detecting when a managed profile has been removed so that PhoneAccountRegistrar 142 * can clean up orphan {@link PhoneAccount}s 143 */ 144 private final BroadcastReceiver mManagedProfileReceiver = new BroadcastReceiver() { 145 @Override 146 public void onReceive(Context context, Intent intent) { 147 Log.startSession("PARbR.oR"); 148 try { 149 synchronized (mLock) { 150 if (intent.getAction().equals(Intent.ACTION_MANAGED_PROFILE_REMOVED)) { 151 cleanupOrphanedPhoneAccounts(); 152 } 153 } 154 } finally { 155 Log.endSession(); 156 } 157 } 158 }; 159 160 public static final String FILE_NAME = "phone-account-registrar-state.xml"; 161 public static final String ICON_ERROR_MSG = 162 "Icon cannot be written to memory. Try compressing or downsizing"; 163 @VisibleForTesting 164 public static final int EXPECTED_STATE_VERSION = 9; 165 public static final int MAX_PHONE_ACCOUNT_REGISTRATIONS = 10; 166 public static final int MAX_PHONE_ACCOUNT_EXTRAS_KEY_PAIR_LIMIT = 100; 167 public static final int MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT = 256; 168 public static final int MAX_SCHEMES_PER_ACCOUNT = 10; 169 170 /** Keep in sync with the same in SipSettings.java */ 171 private static final String SIP_SHARED_PREFERENCES = "SIP_PREFERENCES"; 172 173 private final List<Listener> mListeners = new CopyOnWriteArrayList<>(); 174 private final AtomicFile mAtomicFile; 175 private final Context mContext; 176 private final UserManager mUserManager; 177 private final TelephonyManager mTelephonyManager; 178 private final SubscriptionManager mSubscriptionManager; 179 private final DefaultDialerCache mDefaultDialerCache; 180 private final AppLabelProxy mAppLabelProxy; 181 private final TelecomSystem.SyncRoot mLock; 182 private State mState; 183 private UserHandle mCurrentUserHandle; 184 private final Set<String> mTestPhoneAccountPackageNameFilters; 185 private interface PhoneAccountRegistrarWriteLock {} 186 private final PhoneAccountRegistrarWriteLock mWriteLock = 187 new PhoneAccountRegistrarWriteLock() {}; 188 private final FeatureFlags mTelephonyFeatureFlags; 189 private final com.android.server.telecom.flags.FeatureFlags mTelecomFeatureFlags; 190 191 @VisibleForTesting PhoneAccountRegistrar(Context context, TelecomSystem.SyncRoot lock, DefaultDialerCache defaultDialerCache, AppLabelProxy appLabelProxy, FeatureFlags telephonyFeatureFlags, com.android.server.telecom.flags.FeatureFlags telecomFeatureFlags)192 public PhoneAccountRegistrar(Context context, TelecomSystem.SyncRoot lock, 193 DefaultDialerCache defaultDialerCache, AppLabelProxy appLabelProxy, 194 FeatureFlags telephonyFeatureFlags, 195 com.android.server.telecom.flags.FeatureFlags telecomFeatureFlags) { 196 this(context, lock, FILE_NAME, defaultDialerCache, appLabelProxy, 197 telephonyFeatureFlags, telecomFeatureFlags); 198 } 199 200 @VisibleForTesting PhoneAccountRegistrar(Context context, TelecomSystem.SyncRoot lock, String fileName, DefaultDialerCache defaultDialerCache, AppLabelProxy appLabelProxy, FeatureFlags telephonyFeatureFlags, com.android.server.telecom.flags.FeatureFlags telecomFeatureFlags)201 public PhoneAccountRegistrar(Context context, TelecomSystem.SyncRoot lock, String fileName, 202 DefaultDialerCache defaultDialerCache, AppLabelProxy appLabelProxy, 203 FeatureFlags telephonyFeatureFlags, 204 com.android.server.telecom.flags.FeatureFlags telecomFeatureFlags) { 205 206 mAtomicFile = new AtomicFile(new File(context.getFilesDir(), fileName)); 207 208 mState = new State(); 209 mContext = context; 210 mLock = lock; 211 mUserManager = context.getSystemService(UserManager.class); 212 mDefaultDialerCache = defaultDialerCache; 213 mSubscriptionManager = SubscriptionManager.from(mContext); 214 mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); 215 mAppLabelProxy = appLabelProxy; 216 mCurrentUserHandle = Process.myUserHandle(); 217 mTelecomFeatureFlags = telecomFeatureFlags; 218 mTestPhoneAccountPackageNameFilters = new HashSet<>(); 219 220 if (telephonyFeatureFlags != null) { 221 mTelephonyFeatureFlags = telephonyFeatureFlags; 222 } else { 223 mTelephonyFeatureFlags = 224 new com.android.internal.telephony.flags.FeatureFlagsImpl(); 225 } 226 227 // register context based receiver to clean up orphan phone accounts 228 IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MANAGED_PROFILE_REMOVED); 229 intentFilter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY); 230 mContext.registerReceiver(mManagedProfileReceiver, intentFilter); 231 232 read(); 233 } 234 235 /** 236 * Retrieves the subscription id for a given phone account if it exists. Subscription ids 237 * apply only to PSTN/SIM card phone accounts so all other accounts should not have a 238 * subscription id. 239 * @param accountHandle The handle for the phone account for which to retrieve the 240 * subscription id. 241 * @return The value of the subscription id or -1 if it does not exist or is not valid. 242 */ getSubscriptionIdForPhoneAccount(PhoneAccountHandle accountHandle)243 public int getSubscriptionIdForPhoneAccount(PhoneAccountHandle accountHandle) { 244 PhoneAccount account = getPhoneAccountUnchecked(accountHandle); 245 246 if (account != null && account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) { 247 try { 248 return mTelephonyManager.getSubscriptionId(accountHandle); 249 } catch (UnsupportedOperationException ignored) { 250 // Ignore; fall back to invalid below. 251 } 252 } 253 return SubscriptionManager.INVALID_SUBSCRIPTION_ID; 254 } 255 256 /** 257 * Retrieves the default outgoing phone account supporting the specified uriScheme. Note that if 258 * {@link #mCurrentUserHandle} does not have visibility into the current default, {@code null} 259 * will be returned. 260 * 261 * @param uriScheme The URI scheme for the outgoing call. 262 * @return The {@link PhoneAccountHandle} to use. 263 */ getOutgoingPhoneAccountForScheme(String uriScheme, UserHandle userHandle)264 public PhoneAccountHandle getOutgoingPhoneAccountForScheme(String uriScheme, 265 UserHandle userHandle) { 266 final PhoneAccountHandle userSelected = getUserSelectedOutgoingPhoneAccount(userHandle); 267 268 if (userSelected != null) { 269 // If there is a default PhoneAccount, ensure it supports calls to handles with the 270 // specified uriScheme. 271 final PhoneAccount userSelectedAccount = getPhoneAccountUnchecked(userSelected); 272 if (userSelectedAccount.supportsUriScheme(uriScheme)) { 273 return userSelected; 274 } 275 } 276 277 List<PhoneAccountHandle> outgoing = getCallCapablePhoneAccounts(uriScheme, false, 278 userHandle, false); 279 switch (outgoing.size()) { 280 case 0: 281 // There are no accounts, so there can be no default 282 return null; 283 case 1: 284 // There is only one account, which is by definition the default. 285 return outgoing.get(0); 286 default: 287 // There are multiple accounts with no selected default 288 return null; 289 } 290 } 291 getOutgoingPhoneAccountForSchemeOfCurrentUser(String uriScheme)292 public PhoneAccountHandle getOutgoingPhoneAccountForSchemeOfCurrentUser(String uriScheme) { 293 return getOutgoingPhoneAccountForScheme(uriScheme, mCurrentUserHandle); 294 } 295 296 /** 297 * @return The user-selected outgoing {@link PhoneAccount}, or null if it hasn't been set (or 298 * if it was set by another user). 299 */ 300 @VisibleForTesting getUserSelectedOutgoingPhoneAccount(UserHandle userHandle)301 public PhoneAccountHandle getUserSelectedOutgoingPhoneAccount(UserHandle userHandle) { 302 if (userHandle == null) { 303 return null; 304 } 305 DefaultPhoneAccountHandle defaultPhoneAccountHandle = mState.defaultOutgoingAccountHandles 306 .get(userHandle); 307 if (defaultPhoneAccountHandle == null) { 308 return null; 309 } 310 // Make sure the account is still registered and owned by the user. 311 PhoneAccount account = getPhoneAccount(defaultPhoneAccountHandle.phoneAccountHandle, 312 userHandle); 313 314 if (account != null) { 315 return defaultPhoneAccountHandle.phoneAccountHandle; 316 } 317 318 Log.v(this, 319 "getUserSelectedOutgoingPhoneAccount: defaultPhoneAccountHandle" 320 + ".phoneAccountHandle=[%s] is not registered or owned by %s" 321 , defaultPhoneAccountHandle.phoneAccountHandle, userHandle); 322 323 return null; 324 } 325 326 /** 327 * @return The {@link DefaultPhoneAccountHandle} containing the user-selected default calling 328 * account and group Id for the {@link UserHandle} specified. 329 */ getUserSelectedDefaultPhoneAccount(UserHandle userHandle)330 private DefaultPhoneAccountHandle getUserSelectedDefaultPhoneAccount(UserHandle userHandle) { 331 if (userHandle == null) { 332 return null; 333 } 334 DefaultPhoneAccountHandle defaultPhoneAccountHandle = mState.defaultOutgoingAccountHandles 335 .get(userHandle); 336 if (defaultPhoneAccountHandle == null) { 337 return null; 338 } 339 340 return defaultPhoneAccountHandle; 341 } 342 343 /** 344 * @return The currently registered PhoneAccount in Telecom that has the same group Id. 345 */ getPhoneAccountByGroupId(String groupId, ComponentName groupComponentName, UserHandle userHandle, PhoneAccountHandle excludePhoneAccountHandle)346 private PhoneAccount getPhoneAccountByGroupId(String groupId, ComponentName groupComponentName, 347 UserHandle userHandle, PhoneAccountHandle excludePhoneAccountHandle) { 348 if (groupId == null || groupId.isEmpty() || userHandle == null) { 349 return null; 350 } 351 // Get the PhoneAccount with the same group Id (and same ComponentName) that is not the 352 // newAccount that was just added 353 List<PhoneAccount> accounts = getAllPhoneAccounts(userHandle, false).stream() 354 .filter(account -> groupId.equals(account.getGroupId()) && 355 !account.getAccountHandle().equals(excludePhoneAccountHandle) && 356 Objects.equals(account.getAccountHandle().getComponentName(), 357 groupComponentName)) 358 .collect(Collectors.toList()); 359 // There should be one or no PhoneAccounts with the same group Id 360 if (accounts.size() > 1) { 361 Log.w(this, "Found multiple PhoneAccounts registered to the same Group Id!"); 362 } 363 return accounts.isEmpty() ? null : accounts.get(0); 364 } 365 366 /** 367 * Sets the phone account with which to place all calls by default. Set by the user 368 * within phone settings. 369 */ setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle, UserHandle userHandle)370 public void setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle, 371 UserHandle userHandle) { 372 if (userHandle == null) { 373 return; 374 } 375 DefaultPhoneAccountHandle currentDefaultInfo = 376 mState.defaultOutgoingAccountHandles.get(userHandle); 377 PhoneAccountHandle currentDefaultPhoneAccount = currentDefaultInfo == null ? null : 378 currentDefaultInfo.phoneAccountHandle; 379 380 Log.i(this, "setUserSelectedOutgoingPhoneAccount: %s", accountHandle); 381 382 if (Objects.equals(currentDefaultPhoneAccount, accountHandle)) { 383 Log.i(this, "setUserSelectedOutgoingPhoneAccount: " 384 + "no change in default phoneAccountHandle. current is same as new."); 385 return; 386 } 387 388 boolean isSimAccount = false; 389 if (accountHandle == null) { 390 // Asking to clear the default outgoing is a valid request 391 mState.defaultOutgoingAccountHandles.remove(userHandle); 392 } else { 393 PhoneAccount account = getPhoneAccount(accountHandle, userHandle); 394 if (account == null) { 395 Log.w(this, "Trying to set nonexistent default outgoing %s", 396 accountHandle); 397 return; 398 } 399 400 if (!account.hasCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER)) { 401 Log.w(this, "Trying to set non-call-provider default outgoing %s", 402 accountHandle); 403 return; 404 } 405 406 if (account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) { 407 // If the account selected is a SIM account, propagate down to the subscription 408 // record. 409 isSimAccount = true; 410 } 411 412 mState.defaultOutgoingAccountHandles 413 .put(userHandle, new DefaultPhoneAccountHandle(userHandle, accountHandle, 414 account.getGroupId())); 415 } 416 417 // Potentially update the default voice subid in SubscriptionManager so that Telephony and 418 // Telecom are in sync. 419 int newSubId = accountHandle == null ? SubscriptionManager.INVALID_SUBSCRIPTION_ID : 420 getSubscriptionIdForPhoneAccount(accountHandle); 421 if (Flags.onlyUpdateTelephonyOnValidSubIds()) { 422 if (shouldUpdateTelephonyDefaultVoiceSubId(accountHandle, isSimAccount, newSubId)) { 423 updateDefaultVoiceSubId(newSubId, accountHandle); 424 } else { 425 Log.i(this, "setUserSelectedOutgoingPhoneAccount: %s is not a sub", accountHandle); 426 } 427 } else { 428 if (isSimAccount || accountHandle == null) { 429 updateDefaultVoiceSubId(newSubId, accountHandle); 430 } else { 431 Log.i(this, "setUserSelectedOutgoingPhoneAccount: %s is not a sub", accountHandle); 432 } 433 } 434 435 write(); 436 fireDefaultOutgoingChanged(); 437 } 438 updateDefaultVoiceSubId(int newSubId, PhoneAccountHandle accountHandle)439 private void updateDefaultVoiceSubId(int newSubId, PhoneAccountHandle accountHandle){ 440 try { 441 int currentVoiceSubId = mSubscriptionManager.getDefaultVoiceSubscriptionId(); 442 if (newSubId != currentVoiceSubId) { 443 Log.i(this, "setUserSelectedOutgoingPhoneAccount: update voice sub; " 444 + "account=%s, subId=%d", accountHandle, newSubId); 445 mSubscriptionManager.setDefaultVoiceSubscriptionId(newSubId); 446 } else { 447 Log.i(this, "setUserSelectedOutgoingPhoneAccount: no change to voice sub"); 448 } 449 } catch (UnsupportedOperationException uoe) { 450 Log.w(this, "setUserSelectedOutgoingPhoneAccount: no telephony"); 451 } 452 } 453 454 // This helper is important for CTS testing. [PhoneAccount]s created by Telecom in CTS are 455 // assigned a subId value of INVALID_SUBSCRIPTION_ID (-1) by Telephony. However, when 456 // Telephony has a default outgoing calling voice account of -1, that translates to no default 457 // account (user should be prompted to select an acct when making MOs). In order to avoid 458 // Telephony clearing out the newly changed default [PhoneAccount] in Telecom, Telephony should 459 // not be updated. This situation will never occur in production since [PhoneAccount]s in 460 // production are assigned non-negative subId values. shouldUpdateTelephonyDefaultVoiceSubId(PhoneAccountHandle phoneAccountHandle, boolean isSimAccount, int newSubId)461 private boolean shouldUpdateTelephonyDefaultVoiceSubId(PhoneAccountHandle phoneAccountHandle, 462 boolean isSimAccount, int newSubId) { 463 // user requests no call preference 464 if (phoneAccountHandle == null) { 465 return true; 466 } 467 // do not update Telephony if the newSubId is invalid 468 if (newSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 469 Log.w(this, "shouldUpdateTelephonyDefaultVoiceSubId: " 470 + "invalid subId scenario, not updating Telephony. " 471 + "phoneAccountHandle=[%s], isSimAccount=[%b], newSubId=[%s]", 472 phoneAccountHandle, isSimAccount, newSubId); 473 return false; 474 } 475 return isSimAccount; 476 } 477 isUserSelectedSmsPhoneAccount(PhoneAccountHandle accountHandle)478 boolean isUserSelectedSmsPhoneAccount(PhoneAccountHandle accountHandle) { 479 try { 480 return getSubscriptionIdForPhoneAccount(accountHandle) == 481 SubscriptionManager.getDefaultSmsSubscriptionId(); 482 } catch (UnsupportedOperationException uoe) { 483 Log.w(this, "isUserSelectedSmsPhoneAccount: no telephony"); 484 return false; 485 } 486 } 487 getSystemSimCallManagerComponent()488 public ComponentName getSystemSimCallManagerComponent() { 489 return getSystemSimCallManagerComponent(SubscriptionManager.getDefaultSubscriptionId()); 490 } 491 getSystemSimCallManagerComponent(int subId)492 public ComponentName getSystemSimCallManagerComponent(int subId) { 493 String defaultSimCallManager = null; 494 try { 495 CarrierConfigManager configManager = (CarrierConfigManager) mContext.getSystemService( 496 Context.CARRIER_CONFIG_SERVICE); 497 if (configManager == null) return null; 498 PersistableBundle configBundle = configManager.getConfigForSubId(subId); 499 if (configBundle != null) { 500 defaultSimCallManager = configBundle.getString( 501 CarrierConfigManager.KEY_DEFAULT_SIM_CALL_MANAGER_STRING); 502 } 503 } catch (UnsupportedOperationException ignored) { 504 Log.w(this, "getSystemSimCallManagerComponent: no telephony"); 505 // Fall through to empty below. 506 } 507 return TextUtils.isEmpty(defaultSimCallManager) 508 ? null : ComponentName.unflattenFromString(defaultSimCallManager); 509 } 510 getSimCallManagerOfCurrentUser()511 public PhoneAccountHandle getSimCallManagerOfCurrentUser() { 512 return getSimCallManager(mCurrentUserHandle); 513 } 514 515 /** 516 * Returns the {@link PhoneAccountHandle} corresponding to the SIM Call Manager associated with 517 * the default Telephony Subscription ID (see 518 * {@link SubscriptionManager#getDefaultSubscriptionId()}). SIM Call Manager returned 519 * corresponds to the following priority order: 520 * 1. If a SIM Call Manager {@link PhoneAccount} is registered for the same package as the 521 * default dialer, then that one is returned. 522 * 2. If there is a SIM Call Manager {@link PhoneAccount} registered which matches the 523 * carrier configuration's default, then that one is returned. 524 * 3. Otherwise, we return null. 525 */ getSimCallManager(UserHandle userHandle)526 public PhoneAccountHandle getSimCallManager(UserHandle userHandle) { 527 return getSimCallManager(SubscriptionManager.getDefaultSubscriptionId(), userHandle); 528 } 529 530 /** 531 * Queries the SIM call manager associated with a specific subscription ID. 532 * 533 * @see #getSimCallManager(UserHandle) for more information. 534 */ getSimCallManager(int subId, UserHandle userHandle)535 public PhoneAccountHandle getSimCallManager(int subId, UserHandle userHandle) { 536 537 // Get the default dialer in case it has a connection manager associated with it. 538 String dialerPackage = mDefaultDialerCache 539 .getDefaultDialerApplication(userHandle.getIdentifier()); 540 541 // Check carrier config. 542 ComponentName systemSimCallManagerComponent = getSystemSimCallManagerComponent(subId); 543 544 PhoneAccountHandle dialerSimCallManager = null; 545 PhoneAccountHandle systemSimCallManager = null; 546 547 if (!TextUtils.isEmpty(dialerPackage) || systemSimCallManagerComponent != null) { 548 // loop through and look for any connection manager in the same package. 549 List<PhoneAccountHandle> allSimCallManagers = getPhoneAccountHandles( 550 PhoneAccount.CAPABILITY_CONNECTION_MANAGER, null, null, 551 true /* includeDisabledAccounts */, userHandle, false); 552 for (PhoneAccountHandle accountHandle : allSimCallManagers) { 553 ComponentName component = accountHandle.getComponentName(); 554 555 // Store the system connection manager if found 556 if (systemSimCallManager == null 557 && Objects.equals(component, systemSimCallManagerComponent) 558 && !resolveComponent(accountHandle).isEmpty()) { 559 systemSimCallManager = accountHandle; 560 561 // Store the dialer connection manager if found 562 } else if (dialerSimCallManager == null 563 && Objects.equals(component.getPackageName(), dialerPackage) 564 && !resolveComponent(accountHandle).isEmpty()) { 565 dialerSimCallManager = accountHandle; 566 } 567 } 568 } 569 570 PhoneAccountHandle retval = dialerSimCallManager != null ? 571 dialerSimCallManager : systemSimCallManager; 572 Log.i(this, "getSimCallManager: SimCallManager for subId %d queried, returning: %s", 573 subId, retval); 574 575 return retval; 576 } 577 578 /** 579 * Loops through all SIM accounts ({@link #getSimPhoneAccounts}) and returns those with SIM call 580 * manager components specified in carrier config that match {@code simCallManagerHandle}. 581 * 582 * <p>Note that this will return handles even when {@code simCallManagerHandle} has not yet been 583 * registered or was recently unregistered. 584 * 585 * <p>If the given {@code simCallManagerHandle} is not the SIM call manager for any active SIMs, 586 * returns an empty list. 587 */ getSimPhoneAccountsFromSimCallManager( @onNull PhoneAccountHandle simCallManagerHandle)588 public @NonNull List<PhoneAccountHandle> getSimPhoneAccountsFromSimCallManager( 589 @NonNull PhoneAccountHandle simCallManagerHandle) { 590 List<PhoneAccountHandle> matchingSimHandles = new ArrayList<>(); 591 for (PhoneAccountHandle simHandle : 592 getSimPhoneAccounts(simCallManagerHandle.getUserHandle())) { 593 ComponentName simCallManager = 594 getSystemSimCallManagerComponent(getSubscriptionIdForPhoneAccount(simHandle)); 595 if (simCallManager == null) continue; 596 if (simCallManager.equals(simCallManagerHandle.getComponentName())) { 597 matchingSimHandles.add(simHandle); 598 } 599 } 600 return matchingSimHandles; 601 } 602 603 /** 604 * Sets a filter for which {@link PhoneAccount}s will be returned from 605 * {@link #filterRestrictedPhoneAccounts(List)}. If non-null, only {@link PhoneAccount}s 606 * with the package name packageNameFilter will be returned. If null, no filter is set. 607 * @param packageNameFilter The package name that will be used to filter only 608 * {@link PhoneAccount}s with the same package name. 609 */ setTestPhoneAccountPackageNameFilter(String packageNameFilter)610 public void setTestPhoneAccountPackageNameFilter(String packageNameFilter) { 611 mTestPhoneAccountPackageNameFilters.clear(); 612 if (packageNameFilter == null) { 613 return; 614 } 615 String [] pkgNamesFilter = packageNameFilter.split(","); 616 mTestPhoneAccountPackageNameFilters.addAll(Arrays.asList(pkgNamesFilter)); 617 StringBuilder pkgNames = new StringBuilder(); 618 for (int i = 0; i < pkgNamesFilter.length; i++) { 619 pkgNames.append(pkgNamesFilter[i]) 620 .append(i != pkgNamesFilter.length - 1 ? ", " : "."); 621 } 622 Log.i(this, "filter set for PhoneAccounts, packageNames: %s", pkgNames.toString()); 623 } 624 625 /** 626 * Filter the given {@link List<PhoneAccount>} and keep only {@link PhoneAccount}s that have the 627 * #mTestPhoneAccountPackageNameFilters. 628 * @param accounts List of {@link PhoneAccount}s to filter. 629 * @return new list of filtered {@link PhoneAccount}s. 630 */ filterRestrictedPhoneAccounts(List<PhoneAccount> accounts)631 public List<PhoneAccount> filterRestrictedPhoneAccounts(List<PhoneAccount> accounts) { 632 if (mTestPhoneAccountPackageNameFilters.isEmpty()) { 633 return new ArrayList<>(accounts); 634 } 635 // Remove all PhoneAccounts that do not have the same package name (prefix) as the filter. 636 return accounts.stream().filter(account -> mTestPhoneAccountPackageNameFilters 637 .contains(account.getAccountHandle().getComponentName().getPackageName())) 638 .collect(Collectors.toList()); 639 } 640 641 /** 642 * If it is a outgoing call, sim call manager associated with the target phone account of the 643 * call is returned (if one exists). 644 * Otherwise, we return the sim call manager of the user associated with the 645 * target phone account. 646 * @return phone account handle of sim call manager based on the ongoing call. 647 */ 648 @Nullable getSimCallManagerFromCall(Call call)649 public PhoneAccountHandle getSimCallManagerFromCall(Call call) { 650 if (call == null) { 651 return null; 652 } 653 UserHandle userHandle = call.getAssociatedUser(); 654 PhoneAccountHandle targetPhoneAccount = call.getTargetPhoneAccount(); 655 Log.d(this, "getSimCallManagerFromCall: callId=%s, targetPhac=%s", 656 call.getId(), targetPhoneAccount); 657 return getSimCallManagerFromHandle(targetPhoneAccount,userHandle); 658 } 659 660 /** 661 * Given a target phone account and user, determines the sim call manager (if any) which is 662 * associated with that {@link PhoneAccountHandle}. 663 * @param targetPhoneAccount The target phone account to check. 664 * @param userHandle The user handle. 665 * @return The {@link PhoneAccountHandle} of the connection manager. 666 */ getSimCallManagerFromHandle(PhoneAccountHandle targetPhoneAccount, UserHandle userHandle)667 public PhoneAccountHandle getSimCallManagerFromHandle(PhoneAccountHandle targetPhoneAccount, 668 UserHandle userHandle) { 669 // First, check if the specified target phone account handle is a connection manager; if 670 // it is, then just return it. 671 PhoneAccount phoneAccount = getPhoneAccountUnchecked(targetPhoneAccount); 672 if (phoneAccount != null 673 && phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER)) { 674 return targetPhoneAccount; 675 } 676 677 int subId = getSubscriptionIdForPhoneAccount(targetPhoneAccount); 678 if (SubscriptionManager.isValidSubscriptionId(subId) 679 && subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { 680 PhoneAccountHandle callManagerHandle = getSimCallManager(subId, userHandle); 681 Log.d(this, "getSimCallManagerFromHandle: targetPhac=%s, subId=%d, scm=%s", 682 targetPhoneAccount, subId, callManagerHandle); 683 return callManagerHandle; 684 } else { 685 PhoneAccountHandle callManagerHandle = getSimCallManager(userHandle); 686 Log.d(this, "getSimCallManagerFromHandle: targetPhac=%s, subId(d)=%d, scm=%s", 687 targetPhoneAccount, subId, callManagerHandle); 688 return callManagerHandle; 689 } 690 } 691 692 /** 693 * Update the current UserHandle to track when users are switched. This will allow the 694 * PhoneAccountRegistar to self-filter the PhoneAccounts to make sure we don't leak anything 695 * across users. 696 * We cannot simply check the calling user because that would always return the primary user for 697 * all invocations originating with the system process. 698 * 699 * @param userHandle The {@link UserHandle}, as delivered by 700 * {@link Intent#ACTION_USER_SWITCHED}. 701 */ setCurrentUserHandle(UserHandle userHandle)702 public void setCurrentUserHandle(UserHandle userHandle) { 703 if (userHandle == null) { 704 Log.d(this, "setCurrentUserHandle, userHandle = null"); 705 userHandle = Process.myUserHandle(); 706 } 707 Log.d(this, "setCurrentUserHandle, %s", userHandle); 708 mCurrentUserHandle = userHandle; 709 } 710 711 /** 712 * @return {@code true} if the phone account was successfully enabled/disabled, {@code false} 713 * otherwise. 714 */ enablePhoneAccount(PhoneAccountHandle accountHandle, boolean isEnabled)715 public boolean enablePhoneAccount(PhoneAccountHandle accountHandle, boolean isEnabled) { 716 PhoneAccount account = getPhoneAccountUnchecked(accountHandle); 717 Log.i(this, "Phone account %s %s.", accountHandle, isEnabled ? "enabled" : "disabled"); 718 if (account == null) { 719 Log.w(this, "Could not find account to enable: " + accountHandle); 720 return false; 721 } else if (account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) { 722 // We never change the enabled state of SIM-based accounts. 723 Log.w(this, "Could not change enable state of SIM account: " + accountHandle); 724 return false; 725 } 726 727 if (account.isEnabled() != isEnabled) { 728 account.setIsEnabled(isEnabled); 729 if (!isEnabled) { 730 // If the disabled account is the default, remove it. 731 removeDefaultPhoneAccountHandle(accountHandle); 732 } 733 write(); 734 fireAccountsChanged(); 735 } 736 return true; 737 } 738 removeDefaultPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle)739 private void removeDefaultPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle) { 740 Iterator<Map.Entry<UserHandle, DefaultPhoneAccountHandle>> iterator = 741 mState.defaultOutgoingAccountHandles.entrySet().iterator(); 742 while (iterator.hasNext()) { 743 Map.Entry<UserHandle, DefaultPhoneAccountHandle> entry = iterator.next(); 744 if (phoneAccountHandle.equals(entry.getValue().phoneAccountHandle)) { 745 iterator.remove(); 746 } 747 } 748 } 749 isMatchedUser(PhoneAccount account, UserHandle userHandle)750 private boolean isMatchedUser(PhoneAccount account, UserHandle userHandle) { 751 if (account == null) { 752 return false; 753 } 754 755 if (userHandle == null) { 756 Log.w(this, "userHandle is null in isVisibleForUser"); 757 return false; 758 } 759 760 UserHandle phoneAccountUserHandle = account.getAccountHandle().getUserHandle(); 761 if (phoneAccountUserHandle == null) { 762 return false; 763 } 764 765 return phoneAccountUserHandle.equals(userHandle); 766 } 767 isVisibleForUser(PhoneAccount account, UserHandle userHandle, boolean acrossProfiles)768 private boolean isVisibleForUser(PhoneAccount account, UserHandle userHandle, 769 boolean acrossProfiles) { 770 if (account == null) { 771 return false; 772 } 773 774 if (userHandle == null) { 775 Log.w(this, "userHandle is null in isVisibleForUser"); 776 return false; 777 } 778 779 // If this PhoneAccount has CAPABILITY_MULTI_USER, it should be visible to all users and 780 // all profiles. Only Telephony and SIP accounts should have this capability. 781 if (account.hasCapabilities(PhoneAccount.CAPABILITY_MULTI_USER)) { 782 return true; 783 } 784 785 UserHandle phoneAccountUserHandle = account.getAccountHandle().getUserHandle(); 786 if (phoneAccountUserHandle == null) { 787 return false; 788 } 789 790 if (mCurrentUserHandle == null) { 791 // In case we need to have emergency phone calls from the lock screen. 792 Log.d(this, "Current user is null; assuming true"); 793 return true; 794 } 795 796 if (acrossProfiles) { 797 UserManager um = mContext.getSystemService(UserManager.class); 798 return mTelecomFeatureFlags.telecomResolveHiddenDependencies() 799 ? um.isSameProfileGroup(userHandle, phoneAccountUserHandle) 800 : um.isSameProfileGroup(userHandle.getIdentifier(), 801 phoneAccountUserHandle.getIdentifier()); 802 } else { 803 return phoneAccountUserHandle.equals(userHandle); 804 } 805 } 806 resolveComponent(PhoneAccountHandle phoneAccountHandle)807 private List<ResolveInfo> resolveComponent(PhoneAccountHandle phoneAccountHandle) { 808 return resolveComponent(phoneAccountHandle.getComponentName(), 809 phoneAccountHandle.getUserHandle()); 810 } 811 resolveComponent(ComponentName componentName, UserHandle userHandle)812 private List<ResolveInfo> resolveComponent(ComponentName componentName, 813 UserHandle userHandle) { 814 PackageManager pm = mContext.getPackageManager(); 815 Intent intent = new Intent(ConnectionService.SERVICE_INTERFACE); 816 intent.setComponent(componentName); 817 try { 818 if (userHandle != null) { 819 return pm.queryIntentServicesAsUser(intent, 0, userHandle.getIdentifier()); 820 } else { 821 return pm.queryIntentServices(intent, 0); 822 } 823 } catch (SecurityException e) { 824 Log.e(this, e, "%s is not visible for the calling user", componentName); 825 return Collections.EMPTY_LIST; 826 } 827 } 828 829 /** 830 * Retrieves a list of all {@link PhoneAccountHandle}s registered. 831 * Only returns accounts which are enabled. 832 * 833 * @return The list of {@link PhoneAccountHandle}s. 834 */ getAllPhoneAccountHandles(UserHandle userHandle, boolean crossUserAccess)835 public List<PhoneAccountHandle> getAllPhoneAccountHandles(UserHandle userHandle, 836 boolean crossUserAccess) { 837 return getPhoneAccountHandles(0, null, null, false, userHandle, crossUserAccess, true); 838 } 839 getAllPhoneAccounts(UserHandle userHandle, boolean crossUserAccess)840 public List<PhoneAccount> getAllPhoneAccounts(UserHandle userHandle, boolean crossUserAccess) { 841 return getPhoneAccounts(0, null, null, false, mCurrentUserHandle, crossUserAccess, true); 842 } 843 844 /** 845 * Retrieves a list of all phone account call provider phone accounts supporting the 846 * specified URI scheme. 847 * 848 * @param uriScheme The URI scheme. 849 * @param includeDisabledAccounts {@code} if disabled {@link PhoneAccount}s should be included 850 * in the results. 851 * @param userHandle The {@link UserHandle} to retrieve the {@link PhoneAccount}s for. 852 * @return The phone account handles. 853 */ getCallCapablePhoneAccounts( String uriScheme, boolean includeDisabledAccounts, UserHandle userHandle, boolean crossUserAccess)854 public List<PhoneAccountHandle> getCallCapablePhoneAccounts( 855 String uriScheme, boolean includeDisabledAccounts, 856 UserHandle userHandle, boolean crossUserAccess) { 857 return getCallCapablePhoneAccounts(uriScheme, includeDisabledAccounts, userHandle, 858 0 /* capabilities */, PhoneAccount.CAPABILITY_EMERGENCY_CALLS_ONLY, 859 crossUserAccess); 860 } 861 862 /** 863 * Retrieves a list of all phone account call provider phone accounts supporting the 864 * specified URI scheme. 865 * 866 * @param uriScheme The URI scheme. 867 * @param includeDisabledAccounts {@code} if disabled {@link PhoneAccount}s should be included 868 * in the results. 869 * @param userHandle The {@link UserHandle} to retrieve the {@link PhoneAccount}s for. 870 * @param capabilities Extra {@link PhoneAccount} capabilities which matching 871 * {@link PhoneAccount}s must have. 872 * @return The phone account handles. 873 */ getCallCapablePhoneAccounts( String uriScheme, boolean includeDisabledAccounts, UserHandle userHandle, int capabilities, int excludedCapabilities, boolean crossUserAccess)874 public List<PhoneAccountHandle> getCallCapablePhoneAccounts( 875 String uriScheme, boolean includeDisabledAccounts, UserHandle userHandle, 876 int capabilities, int excludedCapabilities, boolean crossUserAccess) { 877 return getPhoneAccountHandles( 878 PhoneAccount.CAPABILITY_CALL_PROVIDER | capabilities, 879 excludedCapabilities /*excludedCapabilities*/, 880 uriScheme, null, includeDisabledAccounts, userHandle, crossUserAccess); 881 } 882 883 /** 884 * Retrieves a list of all phone accounts which have 885 * {@link PhoneAccount#CAPABILITY_SELF_MANAGED}. 886 * <p> 887 * Returns only the {@link PhoneAccount}s which are enabled as self-managed accounts are 888 * automatically enabled by default (see {@link #registerPhoneAccount(PhoneAccount)}). 889 * 890 * @param userHandle User handle of phone account owner. 891 * @return The phone account handles. 892 */ getSelfManagedPhoneAccounts(UserHandle userHandle)893 public List<PhoneAccountHandle> getSelfManagedPhoneAccounts(UserHandle userHandle) { 894 return getPhoneAccountHandles( 895 PhoneAccount.CAPABILITY_SELF_MANAGED, 896 PhoneAccount.CAPABILITY_EMERGENCY_CALLS_ONLY /* excludedCapabilities */, 897 null /* uriScheme */, null /* packageName */, false /* includeDisabledAccounts */, 898 userHandle, false); 899 } 900 901 /** 902 * Retrieves a list of all the SIM-based phone accounts. 903 */ getSimPhoneAccounts(UserHandle userHandle)904 public List<PhoneAccountHandle> getSimPhoneAccounts(UserHandle userHandle) { 905 return getPhoneAccountHandles( 906 PhoneAccount.CAPABILITY_CALL_PROVIDER | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION, 907 null, null, false, userHandle, false); 908 } 909 getSimPhoneAccountsOfCurrentUser()910 public List<PhoneAccountHandle> getSimPhoneAccountsOfCurrentUser() { 911 return getSimPhoneAccounts(mCurrentUserHandle); 912 } 913 914 /** 915 * Retrieves a list of all phone accounts registered by a specified package. 916 * 917 * @param packageName The name of the package that registered the phone accounts. 918 * @return The phone account handles. 919 */ getPhoneAccountsForPackage(String packageName, UserHandle userHandle)920 public List<PhoneAccountHandle> getPhoneAccountsForPackage(String packageName, 921 UserHandle userHandle) { 922 return getPhoneAccountHandles(0, null, packageName, false, userHandle, false); 923 } 924 925 926 /** 927 * includes disabled, includes crossUserAccess 928 */ getAllPhoneAccountHandlesForPackage(UserHandle userHandle, String packageName)929 public List<PhoneAccountHandle> getAllPhoneAccountHandlesForPackage(UserHandle userHandle, 930 String packageName) { 931 return getPhoneAccountHandles(0, null, packageName, true /* includeDisabled */, userHandle, 932 true /* crossUserAccess */, true); 933 } 934 935 /** 936 * Retrieves a list of all {@link PhoneAccount#CAPABILITY_SELF_MANAGED} phone accounts 937 * registered by a specified package. 938 * 939 * @param packageName The name of the package that registered the phone accounts. 940 * @return The self-managed phone account handles for the given package. 941 */ getSelfManagedPhoneAccountsForPackage(String packageName, UserHandle userHandle)942 public List<PhoneAccountHandle> getSelfManagedPhoneAccountsForPackage(String packageName, 943 UserHandle userHandle) { 944 List<PhoneAccountHandle> phoneAccountsHandles = new ArrayList<>(); 945 for (PhoneAccountHandle pah : getPhoneAccountsForPackage(packageName, 946 userHandle)) { 947 if (isSelfManagedPhoneAccount(pah)) { 948 phoneAccountsHandles.add(pah); 949 } 950 } 951 return phoneAccountsHandles; 952 } 953 954 /** 955 * Determines if a {@link PhoneAccountHandle} is for a self-managed {@link ConnectionService}. 956 * @param handle The handle. 957 * @return {@code true} if for a self-managed {@link ConnectionService}, {@code false} 958 * otherwise. 959 */ isSelfManagedPhoneAccount(@onNull PhoneAccountHandle handle)960 public boolean isSelfManagedPhoneAccount(@NonNull PhoneAccountHandle handle) { 961 PhoneAccount account = getPhoneAccountUnchecked(handle); 962 if (account == null) { 963 return false; 964 } 965 966 return account.isSelfManaged(); 967 } 968 969 /** 970 * Performs checks before calling addOrReplacePhoneAccount(PhoneAccount) 971 * 972 * @param account The {@code PhoneAccount} to add or replace. 973 * @throws SecurityException if package does not have BIND_TELECOM_CONNECTION_SERVICE 974 * permission 975 * @throws IllegalArgumentException if MAX_PHONE_ACCOUNT_REGISTRATIONS are reached 976 * @throws IllegalArgumentException if MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT is reached 977 * @throws IllegalArgumentException if writing the Icon to memory will cause an Exception 978 */ registerPhoneAccount(PhoneAccount account)979 public void registerPhoneAccount(PhoneAccount account) { 980 // Enforce the requirement that a connection service for a phone account has the correct 981 // permission. 982 if (!hasTransactionalCallCapabilities(account) && 983 !phoneAccountRequiresBindPermission(account.getAccountHandle())) { 984 Log.w(this, 985 "Phone account %s does not have BIND_TELECOM_CONNECTION_SERVICE permission.", 986 account.getAccountHandle()); 987 throw new SecurityException("Registering a PhoneAccount requires either: " 988 + "(1) The Service definition requires that the ConnectionService is guarded" 989 + " with the BIND_TELECOM_CONNECTION_SERVICE, which can be defined using the" 990 + " android:permission tag as part of the Service definition. " 991 + "(2) The PhoneAccount capability called" 992 + " CAPABILITY_SUPPORTS_TRANSACTIONAL_OPERATIONS."); 993 } 994 enforceCharacterLimit(account); 995 enforceIconSizeLimit(account); 996 if (mTelecomFeatureFlags.unregisterUnresolvableAccounts()) { 997 enforcePhoneAccountTargetService(account); 998 } 999 enforceMaxPhoneAccountLimit(account); 1000 if (mTelephonyFeatureFlags.simultaneousCallingIndications()) { 1001 enforceSimultaneousCallingRestrictionLimit(account); 1002 } 1003 addOrReplacePhoneAccount(account); 1004 } 1005 1006 /** 1007 * This method ensures that {@link PhoneAccount}s that have the {@link 1008 * PhoneAccount#CAPABILITY_SUPPORTS_TRANSACTIONAL_OPERATIONS} capability are not 1009 * backed by a {@link ConnectionService} 1010 * 1011 * @param account enforce the check on 1012 */ enforcePhoneAccountTargetService(PhoneAccount account)1013 private void enforcePhoneAccountTargetService(PhoneAccount account) { 1014 if (phoneAccountRequiresBindPermission(account.getAccountHandle()) && 1015 hasTransactionalCallCapabilities(account)) { 1016 throw new IllegalArgumentException( 1017 "Error, the PhoneAccount you are registering has" 1018 + " CAPABILITY_SUPPORTS_TRANSACTIONAL_OPERATIONS and the" 1019 + " PhoneAccountHandle's ComponentName#ClassName points to a" 1020 + " ConnectionService class. Either remove the capability or use a" 1021 + " different ClassName in the PhoneAccountHandle."); 1022 } 1023 } 1024 1025 /** 1026 * Enforce an upper bound on the number of PhoneAccount's a package can register. 1027 * Most apps should only require 1-2. * Include disabled accounts. 1028 * 1029 * @param account to enforce check on 1030 * @throws IllegalArgumentException if MAX_PHONE_ACCOUNT_REGISTRATIONS are reached 1031 */ enforceMaxPhoneAccountLimit(@onNull PhoneAccount account)1032 private void enforceMaxPhoneAccountLimit(@NonNull PhoneAccount account) { 1033 int numOfAcctsRegisteredForPackage = mTelecomFeatureFlags.unregisterUnresolvableAccounts() 1034 ? cleanupAndGetVerifiedAccounts(account).size() 1035 : getPhoneAccountHandles( 1036 0/* capabilities */, 1037 null /* uriScheme */, 1038 account.getAccountHandle().getComponentName().getPackageName(), 1039 true /* includeDisabled */, 1040 account.getAccountHandle().getUserHandle(), 1041 false /* crossUserAccess */).size(); 1042 // enforce the max phone account limit for the application registering accounts 1043 if (numOfAcctsRegisteredForPackage >= MAX_PHONE_ACCOUNT_REGISTRATIONS) { 1044 EventLog.writeEvent(0x534e4554, "259064622", Binder.getCallingUid(), 1045 "enforceMaxPhoneAccountLimit"); 1046 throw new IllegalArgumentException( 1047 "Error, cannot register phone account " + account.getAccountHandle() 1048 + " because the limit, " + MAX_PHONE_ACCOUNT_REGISTRATIONS 1049 + ", has been reached"); 1050 } 1051 } 1052 1053 @VisibleForTesting getRegisteredAccountsForPackageName(String packageName, UserHandle userHandle)1054 public List<PhoneAccount> getRegisteredAccountsForPackageName(String packageName, 1055 UserHandle userHandle) { 1056 if (packageName == null) { 1057 return new ArrayList<>(); 1058 } 1059 List<PhoneAccount> accounts = new ArrayList<>(mState.accounts.size()); 1060 for (PhoneAccount m : mState.accounts) { 1061 PhoneAccountHandle handle = m.getAccountHandle(); 1062 if (!packageName.equals(handle.getComponentName().getPackageName())) { 1063 // Not the right package name; skip this one. 1064 continue; 1065 } 1066 // Do not count accounts registered under different users on the device. Otherwise, an 1067 // application can only have MAX_PHONE_ACCOUNT_REGISTRATIONS across all users. If the 1068 // DUT has multiple users, they should each get to register 10 accounts. Also, 3rd 1069 // party applications cannot create new UserHandles without highly privileged 1070 // permissions. 1071 if (!isVisibleForUser(m, userHandle, false)) { 1072 // Account is not visible for the current user; skip this one. 1073 continue; 1074 } 1075 accounts.add(m); 1076 } 1077 return accounts; 1078 } 1079 1080 /** 1081 * Unregister {@link ConnectionService} accounts that no longer have a resolvable Service. This 1082 * means the Service has been disabled or died. Skip the verification for transactional 1083 * accounts. 1084 * 1085 * @param newAccount being registered 1086 * @return all the verified accounts. These accounts are now guaranteed to be backed by a 1087 * {@link ConnectionService} or do not need one (transactional accounts). 1088 */ 1089 @VisibleForTesting cleanupAndGetVerifiedAccounts(PhoneAccount newAccount)1090 public List<PhoneAccount> cleanupAndGetVerifiedAccounts(PhoneAccount newAccount) { 1091 ArrayList<PhoneAccount> verifiedAccounts = new ArrayList<>(); 1092 List<PhoneAccount> unverifiedAccounts = getRegisteredAccountsForPackageName( 1093 newAccount.getAccountHandle().getComponentName().getPackageName(), 1094 newAccount.getAccountHandle().getUserHandle()); 1095 for (PhoneAccount account : unverifiedAccounts) { 1096 PhoneAccountHandle handle = account.getAccountHandle(); 1097 if (/* skip for transactional accounts since they don't require a ConnectionService */ 1098 !hasTransactionalCallCapabilities(account) && 1099 /* check if the {@link ConnectionService} has been disabled or can longer be 1100 found */ resolveComponent(handle).isEmpty()) { 1101 Log.i(this, " cAGVA: Cannot resolve the ConnectionService for" 1102 + " handle=[%s]; unregistering account", handle); 1103 unregisterPhoneAccount(handle); 1104 } else { 1105 verifiedAccounts.add(account); 1106 } 1107 } 1108 return verifiedAccounts; 1109 } 1110 1111 /** 1112 * determine if there will be an issue writing the icon to memory 1113 * 1114 * @param account to enforce check on 1115 * @throws IllegalArgumentException if writing the Icon to memory will cause an Exception 1116 */ 1117 @VisibleForTesting enforceIconSizeLimit(PhoneAccount account)1118 public void enforceIconSizeLimit(PhoneAccount account) { 1119 if (account.getIcon() == null) { 1120 return; 1121 } 1122 String text = ""; 1123 // convert the icon into a Base64 String 1124 try { 1125 text = XmlSerialization.writeIconToBase64String(account.getIcon()); 1126 } catch (IOException e) { 1127 EventLog.writeEvent(0x534e4554, "259064622", Binder.getCallingUid(), 1128 "enforceIconSizeLimit"); 1129 throw new IllegalArgumentException(ICON_ERROR_MSG); 1130 } 1131 // enforce the max bytes check in com.android.modules.utils.FastDataOutput#writeUTF(string) 1132 try { 1133 final int len = (int) ModifiedUtf8.countBytes(text, false); 1134 if (len > 65_535 /* MAX_UNSIGNED_SHORT */) { 1135 EventLog.writeEvent(0x534e4554, "259064622", Binder.getCallingUid(), 1136 "enforceIconSizeLimit"); 1137 throw new IllegalArgumentException(ICON_ERROR_MSG); 1138 } 1139 } catch (IOException e) { 1140 EventLog.writeEvent(0x534e4554, "259064622", Binder.getCallingUid(), 1141 "enforceIconSizeLimit"); 1142 throw new IllegalArgumentException(ICON_ERROR_MSG); 1143 } 1144 } 1145 1146 /** 1147 * All {@link PhoneAccount} and{@link PhoneAccountHandle} String and Char-Sequence fields 1148 * should be restricted to character limit of MAX_PHONE_ACCOUNT_CHAR_LIMIT to prevent exceptions 1149 * when writing large character streams to XML-Serializer. 1150 * 1151 * @param account to enforce character limit checks on 1152 * @throws IllegalArgumentException if MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT reached 1153 */ enforceCharacterLimit(PhoneAccount account)1154 public void enforceCharacterLimit(PhoneAccount account) { 1155 if (account == null) { 1156 return; 1157 } 1158 PhoneAccountHandle handle = account.getAccountHandle(); 1159 1160 String[] fields = 1161 {"Package Name", "Class Name", "PhoneAccountHandle Id", "Label", "ShortDescription", 1162 "GroupId", "Address", "SubscriptionAddress"}; 1163 CharSequence[] args = {handle.getComponentName().getPackageName(), 1164 handle.getComponentName().getClassName(), handle.getId(), account.getLabel(), 1165 account.getShortDescription(), account.getGroupId(), 1166 (account.getAddress() != null ? account.getAddress().toString() : ""), 1167 (account.getSubscriptionAddress() != null ? 1168 account.getSubscriptionAddress().toString() : "")}; 1169 1170 for (int i = 0; i < fields.length; i++) { 1171 if (args[i] != null && args[i].length() > MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT) { 1172 EventLog.writeEvent(0x534e4554, "259064622", Binder.getCallingUid(), 1173 "enforceCharacterLimit"); 1174 throw new IllegalArgumentException("The PhoneAccount or PhoneAccountHandle [" 1175 + fields[i] + "] field has an invalid character count. PhoneAccount and " 1176 + "PhoneAccountHandle String and Char-Sequence fields are limited to " 1177 + MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT + " characters."); 1178 } 1179 } 1180 1181 // Enforce limits on the URI Schemes provided 1182 enforceLimitsOnSchemes(account); 1183 1184 // Enforce limit on the PhoneAccount#mExtras 1185 Bundle extras = account.getExtras(); 1186 if (extras != null) { 1187 if (extras.keySet().size() > MAX_PHONE_ACCOUNT_EXTRAS_KEY_PAIR_LIMIT) { 1188 EventLog.writeEvent(0x534e4554, "259064622", Binder.getCallingUid(), 1189 "enforceCharacterLimit"); 1190 throw new IllegalArgumentException("The PhoneAccount#mExtras is limited to " + 1191 MAX_PHONE_ACCOUNT_EXTRAS_KEY_PAIR_LIMIT + " (key,value) pairs."); 1192 } 1193 1194 for (String key : extras.keySet()) { 1195 Object value = extras.get(key); 1196 1197 if ((key != null && key.length() > MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT) || 1198 (value instanceof String && 1199 ((String) value).length() > MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT)) { 1200 EventLog.writeEvent(0x534e4554, "259064622", Binder.getCallingUid(), 1201 "enforceCharacterLimit"); 1202 throw new IllegalArgumentException("The PhoneAccount#mExtras contains a String" 1203 + " key or value that has an invalid character count. PhoneAccount and " 1204 + "PhoneAccountHandle String and Char-Sequence fields are limited to " 1205 + MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT + " characters."); 1206 } 1207 } 1208 } 1209 } 1210 1211 /** 1212 * Enforce size limits on the simultaneous calling restriction of a PhoneAccount. 1213 * If a PhoneAccount has a simultaneous calling restriction on it, enforce the following: the 1214 * number of PhoneAccountHandles in the Set can not exceed the per app restriction on 1215 * PhoneAccounts registered and each PhoneAccountHandle's fields must not exceed the per field 1216 * character limit. 1217 * @param account The PhoneAccount to enforce simultaneous calling restrictions on. 1218 * @throws IllegalArgumentException if the PhoneAccount exceeds size limits. 1219 */ enforceSimultaneousCallingRestrictionLimit(@onNull PhoneAccount account)1220 public void enforceSimultaneousCallingRestrictionLimit(@NonNull PhoneAccount account) { 1221 if (!account.hasSimultaneousCallingRestriction()) return; 1222 Set<PhoneAccountHandle> restrictions = account.getSimultaneousCallingRestriction(); 1223 if (restrictions.size() > MAX_PHONE_ACCOUNT_REGISTRATIONS) { 1224 throw new IllegalArgumentException("Can not register a PhoneAccount with a number" 1225 + "of simultaneous calling restrictions that is greater than " 1226 + MAX_PHONE_ACCOUNT_REGISTRATIONS); 1227 } 1228 for (PhoneAccountHandle handle : restrictions) { 1229 ComponentName component = handle.getComponentName(); 1230 if (component.getPackageName().length() > MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT) { 1231 throw new IllegalArgumentException("A PhoneAccountHandle added as part of " 1232 + "a simultaneous calling restriction has a package name that has exceeded " 1233 + "the character limit of " + MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT); 1234 } 1235 if (component.getClassName().length() > MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT) { 1236 throw new IllegalArgumentException("A PhoneAccountHandle added as part of " 1237 + "a simultaneous calling restriction has a class name that has exceeded " 1238 + "the character limit of " + MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT); 1239 } 1240 if (handle.getId().length() > MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT) { 1241 throw new IllegalArgumentException("A PhoneAccountHandle added as part of " 1242 + "a simultaneous calling restriction has an ID that has exceeded " 1243 + "the character limit of " + MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT); 1244 } 1245 } 1246 } 1247 1248 /** 1249 * Enforce a character limit on all PA and PAH string or char-sequence fields. 1250 * 1251 * @param account to enforce check on 1252 * @throws IllegalArgumentException if MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT reached 1253 */ 1254 @VisibleForTesting enforceLimitsOnSchemes(@onNull PhoneAccount account)1255 public void enforceLimitsOnSchemes(@NonNull PhoneAccount account) { 1256 List<String> schemes = account.getSupportedUriSchemes(); 1257 1258 if (schemes == null) { 1259 return; 1260 } 1261 1262 if (schemes.size() > MAX_SCHEMES_PER_ACCOUNT) { 1263 EventLog.writeEvent(0x534e4554, "259064622", Binder.getCallingUid(), 1264 "enforceLimitsOnSchemes"); 1265 throw new IllegalArgumentException( 1266 "Error, cannot register phone account " + account.getAccountHandle() 1267 + " because the URI scheme limit of " 1268 + MAX_SCHEMES_PER_ACCOUNT + " has been reached"); 1269 } 1270 1271 for (String scheme : schemes) { 1272 if (scheme.length() > MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT) { 1273 EventLog.writeEvent(0x534e4554, "259064622", Binder.getCallingUid(), 1274 "enforceLimitsOnSchemes"); 1275 throw new IllegalArgumentException( 1276 "Error, cannot register phone account " + account.getAccountHandle() 1277 + " because the max scheme limit of " 1278 + MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT + " has been reached"); 1279 } 1280 } 1281 } 1282 1283 /** 1284 * Adds a {@code PhoneAccount}, replacing an existing one if found. 1285 * 1286 * @param account The {@code PhoneAccount} to add or replace. 1287 */ addOrReplacePhoneAccount(PhoneAccount account)1288 private void addOrReplacePhoneAccount(PhoneAccount account) { 1289 Log.d(this, "addOrReplacePhoneAccount(%s -> %s)", 1290 account.getAccountHandle(), account); 1291 1292 // Start _enabled_ property as false. 1293 // !!! IMPORTANT !!! It is important that we do not read the enabled state that the 1294 // source app provides or else an third party app could enable itself. 1295 boolean isEnabled = false; 1296 boolean isNewAccount; 1297 1298 // add self-managed capability for transactional accounts that are missing it 1299 if (hasTransactionalCallCapabilities(account) 1300 && !account.hasCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED)) { 1301 account = account.toBuilder() 1302 .setCapabilities(account.getCapabilities() 1303 | PhoneAccount.CAPABILITY_SELF_MANAGED) 1304 .build(); 1305 // Note: below we will automatically remove CAPABILITY_CONNECTION_MANAGER, 1306 // CAPABILITY_CALL_PROVIDER, and CAPABILITY_SIM_SUBSCRIPTION if this magically becomes 1307 // a self-managed phone account here. 1308 } 1309 1310 PhoneAccount oldAccount = getPhoneAccountUnchecked(account.getAccountHandle()); 1311 if (oldAccount != null) { 1312 enforceSelfManagedAccountUnmodified(account, oldAccount); 1313 mState.accounts.remove(oldAccount); 1314 isEnabled = oldAccount.isEnabled(); 1315 Log.i(this, "Modify account: %s", getAccountDiffString(account, oldAccount)); 1316 isNewAccount = false; 1317 } else { 1318 Log.i(this, "New phone account registered: " + account); 1319 isNewAccount = true; 1320 } 1321 1322 // When registering a self-managed PhoneAccount we enforce the rule that the label that the 1323 // app uses is also its phone account label. Also ensure it does not attempt to declare 1324 // itself as a sim acct, call manager or call provider. 1325 if (account.hasCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED)) { 1326 // Turn off bits we don't want to be able to set (TelecomServiceImpl protects against 1327 // this but we'll also prevent it from happening here, just to be safe). 1328 if ((account.getCapabilities() & (PhoneAccount.CAPABILITY_CALL_PROVIDER 1329 | PhoneAccount.CAPABILITY_CONNECTION_MANAGER 1330 | PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) > 0) { 1331 Log.w(this, "addOrReplacePhoneAccount: attempt to register a " 1332 + "VoIP phone account with call provider/cm/sim sub capabilities."); 1333 } 1334 int newCapabilities = account.getCapabilities() & 1335 ~(PhoneAccount.CAPABILITY_CALL_PROVIDER | 1336 PhoneAccount.CAPABILITY_CONNECTION_MANAGER | 1337 PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION); 1338 1339 // Ensure name is correct. 1340 CharSequence newLabel = mAppLabelProxy.getAppLabel( 1341 account.getAccountHandle().getComponentName().getPackageName(), 1342 UserUtil.getAssociatedUserForCall( 1343 mTelecomFeatureFlags.associatedUserRefactorForWorkProfile(), 1344 this, UserHandle.CURRENT, account.getAccountHandle())); 1345 1346 account = account.toBuilder() 1347 .setLabel(newLabel) 1348 .setCapabilities(newCapabilities) 1349 .build(); 1350 } 1351 1352 mState.accounts.add(account); 1353 // Set defaults and replace based on the group Id. 1354 maybeReplaceOldAccount(account); 1355 // Reset enabled state to whatever the value was if the account was already registered, 1356 // or _true_ if this is a SIM-based account. All SIM-based accounts are always enabled, 1357 // as are all self-managed phone accounts. 1358 account.setIsEnabled( 1359 isEnabled || account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) 1360 || account.hasCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED)); 1361 1362 write(); 1363 fireAccountsChanged(); 1364 if (isNewAccount) { 1365 fireAccountRegistered(account.getAccountHandle()); 1366 } else { 1367 fireAccountChanged(account); 1368 } 1369 // If this is the SIM call manager, tell telephony when the voice ServiceState override 1370 // needs to be updated. 1371 maybeNotifyTelephonyForVoiceServiceState(account, /* registered= */ true); 1372 } 1373 unregisterPhoneAccount(PhoneAccountHandle accountHandle)1374 public void unregisterPhoneAccount(PhoneAccountHandle accountHandle) { 1375 PhoneAccount account = getPhoneAccountUnchecked(accountHandle); 1376 if (account != null) { 1377 if (mState.accounts.remove(account)) { 1378 write(); 1379 fireAccountsChanged(); 1380 fireAccountUnRegistered(accountHandle); 1381 // If this is the SIM call manager, tell telephony when the voice ServiceState 1382 // override needs to be updated. 1383 maybeNotifyTelephonyForVoiceServiceState(account, /* registered= */ false); 1384 } 1385 } 1386 } 1387 enforceSelfManagedAccountUnmodified(PhoneAccount newAccount, PhoneAccount oldAccount)1388 private void enforceSelfManagedAccountUnmodified(PhoneAccount newAccount, 1389 PhoneAccount oldAccount) { 1390 if (oldAccount.hasCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED) && 1391 (!newAccount.hasCapabilities(PhoneAccount.CAPABILITY_SELF_MANAGED))) { 1392 EventLog.writeEvent(0x534e4554, "246930197"); 1393 Log.w(this, "Self-managed phone account %s replaced by a non self-managed one", 1394 newAccount.getAccountHandle()); 1395 throw new IllegalArgumentException("Error, cannot change a self-managed " 1396 + "phone account " + newAccount.getAccountHandle() 1397 + " to other kinds of phone account"); 1398 } 1399 } 1400 1401 /** 1402 * Un-registers all phone accounts associated with a specified package. 1403 * 1404 * @param packageName The package for which phone accounts will be removed. 1405 * @param userHandle The {@link UserHandle} the package is running under. 1406 */ clearAccounts(String packageName, UserHandle userHandle)1407 public void clearAccounts(String packageName, UserHandle userHandle) { 1408 boolean accountsRemoved = false; 1409 Iterator<PhoneAccount> it = mState.accounts.iterator(); 1410 while (it.hasNext()) { 1411 PhoneAccount phoneAccount = it.next(); 1412 PhoneAccountHandle handle = phoneAccount.getAccountHandle(); 1413 if (Objects.equals(packageName, handle.getComponentName().getPackageName()) 1414 && Objects.equals(userHandle, handle.getUserHandle())) { 1415 Log.i(this, "Removing phone account " + phoneAccount.getLabel()); 1416 mState.accounts.remove(phoneAccount); 1417 accountsRemoved = true; 1418 } 1419 } 1420 1421 if (accountsRemoved) { 1422 write(); 1423 fireAccountsChanged(); 1424 } 1425 } 1426 isVoiceMailNumber(PhoneAccountHandle accountHandle, String number)1427 public boolean isVoiceMailNumber(PhoneAccountHandle accountHandle, String number) { 1428 int subId = getSubscriptionIdForPhoneAccount(accountHandle); 1429 return PhoneNumberUtils.isVoiceMailNumber(mContext, subId, number); 1430 } 1431 addListener(Listener l)1432 public void addListener(Listener l) { 1433 mListeners.add(l); 1434 } 1435 removeListener(Listener l)1436 public void removeListener(Listener l) { 1437 if (l != null) { 1438 mListeners.remove(l); 1439 } 1440 } 1441 fireAccountRegistered(PhoneAccountHandle handle)1442 private void fireAccountRegistered(PhoneAccountHandle handle) { 1443 for (Listener l : mListeners) { 1444 l.onPhoneAccountRegistered(this, handle); 1445 } 1446 } 1447 fireAccountChanged(PhoneAccount account)1448 private void fireAccountChanged(PhoneAccount account) { 1449 for (Listener l : mListeners) { 1450 l.onPhoneAccountChanged(this, account); 1451 } 1452 } 1453 fireAccountUnRegistered(PhoneAccountHandle handle)1454 private void fireAccountUnRegistered(PhoneAccountHandle handle) { 1455 for (Listener l : mListeners) { 1456 l.onPhoneAccountUnRegistered(this, handle); 1457 } 1458 } 1459 fireAccountsChanged()1460 private void fireAccountsChanged() { 1461 for (Listener l : mListeners) { 1462 l.onAccountsChanged(this); 1463 } 1464 } 1465 fireDefaultOutgoingChanged()1466 private void fireDefaultOutgoingChanged() { 1467 for (Listener l : mListeners) { 1468 l.onDefaultOutgoingChanged(this); 1469 } 1470 } 1471 getAccountDiffString(PhoneAccount account1, PhoneAccount account2)1472 private String getAccountDiffString(PhoneAccount account1, PhoneAccount account2) { 1473 if (account1 == null || account2 == null) { 1474 return "Diff: " + account1 + ", " + account2; 1475 } 1476 1477 StringBuffer sb = new StringBuffer(); 1478 sb.append("[").append(account1.getAccountHandle()); 1479 appendDiff(sb, "addr", Log.piiHandle(account1.getAddress()), 1480 Log.piiHandle(account2.getAddress())); 1481 appendDiff(sb, "cap", account1.capabilitiesToString(), account2.capabilitiesToString()); 1482 appendDiff(sb, "hl", account1.getHighlightColor(), account2.getHighlightColor()); 1483 appendDiff(sb, "lbl", account1.getLabel(), account2.getLabel()); 1484 appendDiff(sb, "desc", account1.getShortDescription(), account2.getShortDescription()); 1485 appendDiff(sb, "subAddr", Log.piiHandle(account1.getSubscriptionAddress()), 1486 Log.piiHandle(account2.getSubscriptionAddress())); 1487 appendDiff(sb, "uris", account1.getSupportedUriSchemes(), 1488 account2.getSupportedUriSchemes()); 1489 sb.append("]"); 1490 return sb.toString(); 1491 } 1492 appendDiff(StringBuffer sb, String attrName, Object obj1, Object obj2)1493 private void appendDiff(StringBuffer sb, String attrName, Object obj1, Object obj2) { 1494 if (!Objects.equals(obj1, obj2)) { 1495 sb.append("(") 1496 .append(attrName) 1497 .append(": ") 1498 .append(obj1) 1499 .append(" -> ") 1500 .append(obj2) 1501 .append(")"); 1502 } 1503 } 1504 maybeReplaceOldAccount(PhoneAccount newAccount)1505 private void maybeReplaceOldAccount(PhoneAccount newAccount) { 1506 UserHandle newAccountUserHandle = newAccount.getAccountHandle().getUserHandle(); 1507 DefaultPhoneAccountHandle defaultHandle = 1508 getUserSelectedDefaultPhoneAccount(newAccountUserHandle); 1509 if (defaultHandle == null || defaultHandle.groupId.isEmpty()) { 1510 Log.v(this, "maybeReplaceOldAccount: Not replacing PhoneAccount, no group Id or " + 1511 "default."); 1512 return; 1513 } 1514 if (!defaultHandle.groupId.equals(newAccount.getGroupId())) { 1515 Log.v(this, "maybeReplaceOldAccount: group Ids are not equal."); 1516 return; 1517 } 1518 if (Objects.equals(newAccount.getAccountHandle().getComponentName(), 1519 defaultHandle.phoneAccountHandle.getComponentName())) { 1520 // Move default calling account over to new user, since the ComponentNames and Group Ids 1521 // are the same. 1522 setUserSelectedOutgoingPhoneAccount(newAccount.getAccountHandle(), 1523 newAccountUserHandle); 1524 } else { 1525 Log.v(this, "maybeReplaceOldAccount: group Ids are equal, but ComponentName is not" + 1526 " the same as the default. Not replacing default PhoneAccount."); 1527 } 1528 PhoneAccount replacementAccount = getPhoneAccountByGroupId(newAccount.getGroupId(), 1529 newAccount.getAccountHandle().getComponentName(), newAccountUserHandle, 1530 newAccount.getAccountHandle()); 1531 if (replacementAccount != null) { 1532 // Unregister the old PhoneAccount. 1533 Log.v(this, "maybeReplaceOldAccount: Unregistering old PhoneAccount: " + 1534 replacementAccount.getAccountHandle()); 1535 unregisterPhoneAccount(replacementAccount.getAccountHandle()); 1536 } 1537 } 1538 maybeNotifyTelephonyForVoiceServiceState( @onNull PhoneAccount account, boolean registered)1539 private void maybeNotifyTelephonyForVoiceServiceState( 1540 @NonNull PhoneAccount account, boolean registered) { 1541 // TODO(b/215419665) what about SIM_SUBSCRIPTION accounts? They could theoretically also use 1542 // these capabilities, but don't today. If they do start using them, then there will need to 1543 // be a kind of "or" logic between SIM_SUBSCRIPTION and CONNECTION_MANAGER accounts to get 1544 // the correct value of hasService for a given SIM. 1545 boolean hasService = false; 1546 List<PhoneAccountHandle> simHandlesToNotify; 1547 if (account.hasCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER)) { 1548 // When we unregister the SIM call manager account, we always set hasService back to 1549 // false since it is no longer providing OTT calling capability once unregistered. 1550 if (registered) { 1551 // Note: we do *not* early return when the SUPPORTS capability is not present 1552 // because it's possible the SIM call manager could remove either capability at 1553 // runtime and re-register. However, it is an error to use the AVAILABLE capability 1554 // without also setting SUPPORTS. 1555 hasService = 1556 account.hasCapabilities( 1557 PhoneAccount.CAPABILITY_SUPPORTS_VOICE_CALLING_INDICATIONS 1558 | PhoneAccount.CAPABILITY_VOICE_CALLING_AVAILABLE); 1559 } 1560 // Notify for all SIMs that named this component as their SIM call manager in carrier 1561 // config, since there may be more than one impacted SIM here. 1562 simHandlesToNotify = getSimPhoneAccountsFromSimCallManager(account.getAccountHandle()); 1563 } else if (account.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) { 1564 // When new SIMs get registered, we notify them of their current voice status override. 1565 // If there is no SIM call manager for this SIM, we treat that as hasService = false and 1566 // still notify to ensure consistency. 1567 if (!registered) { 1568 // We don't do anything when SIMs are unregistered because we won't have an active 1569 // subId to map back to phoneId and tell telephony about; that case is handled by 1570 // telephony internally. 1571 return; 1572 } 1573 PhoneAccountHandle simCallManagerHandle = 1574 getSimCallManagerFromHandle( 1575 account.getAccountHandle(), account.getAccountHandle().getUserHandle()); 1576 if (simCallManagerHandle != null) { 1577 PhoneAccount simCallManager = getPhoneAccountUnchecked(simCallManagerHandle); 1578 hasService = 1579 simCallManager != null 1580 && simCallManager.hasCapabilities( 1581 PhoneAccount.CAPABILITY_SUPPORTS_VOICE_CALLING_INDICATIONS 1582 | PhoneAccount.CAPABILITY_VOICE_CALLING_AVAILABLE); 1583 } 1584 simHandlesToNotify = Collections.singletonList(account.getAccountHandle()); 1585 } else { 1586 // Not a relevant account - we only care about CONNECTION_MANAGER and SIM_SUBSCRIPTION. 1587 return; 1588 } 1589 if (simHandlesToNotify.isEmpty()) return; 1590 Log.i( 1591 this, 1592 "Notifying telephony of voice service override change for %d SIMs, hasService = %b", 1593 simHandlesToNotify.size(), 1594 hasService); 1595 try { 1596 for (PhoneAccountHandle simHandle : simHandlesToNotify) { 1597 // This may be null if there are no active SIMs but the device is still camped for 1598 // emergency calls and registered a SIM_SUBSCRIPTION for that purpose. 1599 TelephonyManager simTm = mTelephonyManager.createForPhoneAccountHandle(simHandle); 1600 if (simTm == null) { 1601 Log.i(this, "maybeNotifyTelephonyForVoiceServiceState: " 1602 + "simTm is null."); 1603 continue; 1604 } 1605 simTm.setVoiceServiceStateOverride(hasService); 1606 } 1607 } catch (UnsupportedOperationException ignored) { 1608 // No telephony, so we can't override the sim service state. 1609 // Realistically we shouldn't get here because there should be no sim subs in this case. 1610 Log.w(this, "maybeNotifyTelephonyForVoiceServiceState: no telephony"); 1611 } 1612 } 1613 1614 /** 1615 * Determines if the connection service specified by a {@link PhoneAccountHandle} requires the 1616 * {@link Manifest.permission#BIND_TELECOM_CONNECTION_SERVICE} permission. 1617 * 1618 * @param phoneAccountHandle The phone account to check. 1619 * @return {@code True} if the phone account has permission. 1620 */ phoneAccountRequiresBindPermission(PhoneAccountHandle phoneAccountHandle)1621 public boolean phoneAccountRequiresBindPermission(PhoneAccountHandle phoneAccountHandle) { 1622 List<ResolveInfo> resolveInfos = resolveComponent(phoneAccountHandle); 1623 if (resolveInfos.isEmpty()) { 1624 Log.w(this, "phoneAccount %s not found", phoneAccountHandle.getComponentName()); 1625 return false; 1626 } 1627 1628 for (ResolveInfo resolveInfo : resolveInfos) { 1629 ServiceInfo serviceInfo = resolveInfo.serviceInfo; 1630 if (serviceInfo == null) { 1631 return false; 1632 } 1633 1634 if (!Manifest.permission.BIND_CONNECTION_SERVICE.equals(serviceInfo.permission) && 1635 !Manifest.permission.BIND_TELECOM_CONNECTION_SERVICE.equals( 1636 serviceInfo.permission)) { 1637 // The ConnectionService must require either the deprecated BIND_CONNECTION_SERVICE, 1638 // or the public BIND_TELECOM_CONNECTION_SERVICE permissions, both of which are 1639 // system/signature only. 1640 return false; 1641 } 1642 } 1643 return true; 1644 } 1645 1646 @VisibleForTesting hasTransactionalCallCapabilities(PhoneAccount phoneAccount)1647 public boolean hasTransactionalCallCapabilities(PhoneAccount phoneAccount) { 1648 if (phoneAccount == null) { 1649 return false; 1650 } 1651 return phoneAccount.hasCapabilities( 1652 PhoneAccount.CAPABILITY_SUPPORTS_TRANSACTIONAL_OPERATIONS); 1653 } 1654 1655 // 1656 // Methods for retrieving PhoneAccounts and PhoneAccountHandles 1657 // 1658 1659 /** 1660 * Returns the PhoneAccount for the specified handle. Does no user checking. 1661 * 1662 * @param handle 1663 * @return The corresponding phone account if one exists. 1664 */ getPhoneAccountUnchecked(PhoneAccountHandle handle)1665 public PhoneAccount getPhoneAccountUnchecked(PhoneAccountHandle handle) { 1666 for (PhoneAccount m : mState.accounts) { 1667 if (Objects.equals(handle, m.getAccountHandle())) { 1668 return m; 1669 } 1670 } 1671 return null; 1672 } 1673 1674 /** 1675 * Like getPhoneAccount, but checks to see if the current user is allowed to see the phone 1676 * account before returning it. The current user is the active user on the actual android 1677 * device. 1678 */ getPhoneAccount(PhoneAccountHandle handle, UserHandle userHandle)1679 public PhoneAccount getPhoneAccount(PhoneAccountHandle handle, UserHandle userHandle) { 1680 return getPhoneAccount(handle, userHandle, /* acrossProfiles */ false); 1681 } 1682 getPhoneAccount(PhoneAccountHandle handle, UserHandle userHandle, boolean acrossProfiles)1683 public PhoneAccount getPhoneAccount(PhoneAccountHandle handle, 1684 UserHandle userHandle, boolean acrossProfiles) { 1685 PhoneAccount account = getPhoneAccountUnchecked(handle); 1686 if (account != null && (isVisibleForUser(account, userHandle, acrossProfiles))) { 1687 return account; 1688 } 1689 return null; 1690 } 1691 getPhoneAccountOfCurrentUser(PhoneAccountHandle handle)1692 public PhoneAccount getPhoneAccountOfCurrentUser(PhoneAccountHandle handle) { 1693 return getPhoneAccount(handle, mCurrentUserHandle); 1694 } 1695 getPhoneAccountHandles( int capabilities, String uriScheme, String packageName, boolean includeDisabledAccounts, UserHandle userHandle, boolean crossUserAccess)1696 private List<PhoneAccountHandle> getPhoneAccountHandles( 1697 int capabilities, 1698 String uriScheme, 1699 String packageName, 1700 boolean includeDisabledAccounts, 1701 UserHandle userHandle, 1702 boolean crossUserAccess) { 1703 return getPhoneAccountHandles(capabilities, 0 /*excludedCapabilities*/, uriScheme, 1704 packageName, includeDisabledAccounts, userHandle, crossUserAccess, false); 1705 } 1706 getPhoneAccountHandles( int capabilities, String uriScheme, String packageName, boolean includeDisabledAccounts, UserHandle userHandle, boolean crossUserAccess, boolean includeAll)1707 private List<PhoneAccountHandle> getPhoneAccountHandles( 1708 int capabilities, 1709 String uriScheme, 1710 String packageName, 1711 boolean includeDisabledAccounts, 1712 UserHandle userHandle, 1713 boolean crossUserAccess, 1714 boolean includeAll) { 1715 return getPhoneAccountHandles(capabilities, 0 /*excludedCapabilities*/, uriScheme, 1716 packageName, includeDisabledAccounts, userHandle, crossUserAccess, includeAll); 1717 } 1718 1719 /** 1720 * Returns a list of phone account handles with the specified capabilities, uri scheme, 1721 * and package name. 1722 */ getPhoneAccountHandles( int capabilities, int excludedCapabilities, String uriScheme, String packageName, boolean includeDisabledAccounts, UserHandle userHandle, boolean crossUserAccess)1723 private List<PhoneAccountHandle> getPhoneAccountHandles( 1724 int capabilities, 1725 int excludedCapabilities, 1726 String uriScheme, 1727 String packageName, 1728 boolean includeDisabledAccounts, 1729 UserHandle userHandle, 1730 boolean crossUserAccess) { 1731 return getPhoneAccountHandles(capabilities, excludedCapabilities, uriScheme, packageName, 1732 includeDisabledAccounts, userHandle, crossUserAccess, false); 1733 } 1734 getPhoneAccountHandles( int capabilities, int excludedCapabilities, String uriScheme, String packageName, boolean includeDisabledAccounts, UserHandle userHandle, boolean crossUserAccess, boolean includeAll)1735 private List<PhoneAccountHandle> getPhoneAccountHandles( 1736 int capabilities, 1737 int excludedCapabilities, 1738 String uriScheme, 1739 String packageName, 1740 boolean includeDisabledAccounts, 1741 UserHandle userHandle, 1742 boolean crossUserAccess, 1743 boolean includeAll) { 1744 List<PhoneAccountHandle> handles = new ArrayList<>(); 1745 1746 for (PhoneAccount account : getPhoneAccounts( 1747 capabilities, excludedCapabilities, uriScheme, packageName, 1748 includeDisabledAccounts, userHandle, crossUserAccess, includeAll)) { 1749 handles.add(account.getAccountHandle()); 1750 } 1751 return handles; 1752 } 1753 getPhoneAccounts( int capabilities, String uriScheme, String packageName, boolean includeDisabledAccounts, UserHandle userHandle, boolean crossUserAccess)1754 private List<PhoneAccount> getPhoneAccounts( 1755 int capabilities, 1756 String uriScheme, 1757 String packageName, 1758 boolean includeDisabledAccounts, 1759 UserHandle userHandle, 1760 boolean crossUserAccess) { 1761 return getPhoneAccounts(capabilities, 0 /*excludedCapabilities*/, uriScheme, packageName, 1762 includeDisabledAccounts, userHandle, crossUserAccess, false); 1763 } 1764 getPhoneAccounts( int capabilities, String uriScheme, String packageName, boolean includeDisabledAccounts, UserHandle userHandle, boolean crossUserAccess, boolean includeAll)1765 private List<PhoneAccount> getPhoneAccounts( 1766 int capabilities, 1767 String uriScheme, 1768 String packageName, 1769 boolean includeDisabledAccounts, 1770 UserHandle userHandle, 1771 boolean crossUserAccess, 1772 boolean includeAll) { 1773 return getPhoneAccounts(capabilities, 0 /*excludedCapabilities*/, uriScheme, packageName, 1774 includeDisabledAccounts, userHandle, crossUserAccess, includeAll); 1775 } 1776 1777 /** 1778 * Returns a list of phone account handles with the specified flag, supporting the specified 1779 * URI scheme, within the specified package name. 1780 * 1781 * @param capabilities Capabilities which the {@code PhoneAccount} must have. Ignored if 0. 1782 * @param excludedCapabilities Capabilities which the {@code PhoneAccount} must not have. 1783 * Ignored if 0. 1784 * @param uriScheme URI schemes the PhoneAccount must handle. {@code null} bypasses the 1785 * URI scheme check. 1786 * @param packageName Package name of the PhoneAccount. {@code null} bypasses packageName check. 1787 */ getPhoneAccounts( int capabilities, int excludedCapabilities, String uriScheme, String packageName, boolean includeDisabledAccounts, UserHandle userHandle, boolean crossUserAccess)1788 private List<PhoneAccount> getPhoneAccounts( 1789 int capabilities, 1790 int excludedCapabilities, 1791 String uriScheme, 1792 String packageName, 1793 boolean includeDisabledAccounts, 1794 UserHandle userHandle, 1795 boolean crossUserAccess) { 1796 return getPhoneAccounts(capabilities, excludedCapabilities, uriScheme, packageName, 1797 includeDisabledAccounts, userHandle, crossUserAccess, false); 1798 } 1799 1800 @VisibleForTesting getPhoneAccounts( int capabilities, int excludedCapabilities, String uriScheme, String packageName, boolean includeDisabledAccounts, UserHandle userHandle, boolean crossUserAccess, boolean includeAll)1801 public List<PhoneAccount> getPhoneAccounts( 1802 int capabilities, 1803 int excludedCapabilities, 1804 String uriScheme, 1805 String packageName, 1806 boolean includeDisabledAccounts, 1807 UserHandle userHandle, 1808 boolean crossUserAccess, 1809 boolean includeAll) { 1810 List<PhoneAccount> accounts = new ArrayList<>(mState.accounts.size()); 1811 List<PhoneAccount> matchedAccounts = new ArrayList<>(mState.accounts.size()); 1812 for (PhoneAccount m : mState.accounts) { 1813 if (!(m.isEnabled() || includeDisabledAccounts)) { 1814 // Do not include disabled accounts. 1815 continue; 1816 } 1817 1818 if ((m.getCapabilities() & excludedCapabilities) != 0) { 1819 // If an excluded capability is present, skip. 1820 continue; 1821 } 1822 1823 if (capabilities != 0 && !m.hasCapabilities(capabilities)) { 1824 // Account doesn't have the right capabilities; skip this one. 1825 continue; 1826 } 1827 if (uriScheme != null && !m.supportsUriScheme(uriScheme)) { 1828 // Account doesn't support this URI scheme; skip this one. 1829 continue; 1830 } 1831 PhoneAccountHandle handle = m.getAccountHandle(); 1832 1833 // PhoneAccounts with CAPABILITY_SUPPORTS_TRANSACTIONAL_OPERATIONS do not require a 1834 // ConnectionService and will fail [resolveComponent(PhoneAccountHandle)]. Bypass 1835 // the [resolveComponent(PhoneAccountHandle)] for transactional accounts. 1836 if (!hasTransactionalCallCapabilities(m) && resolveComponent(handle).isEmpty()) { 1837 // This component cannot be resolved anymore; skip this one. 1838 continue; 1839 } 1840 if (packageName != null && 1841 !packageName.equals(handle.getComponentName().getPackageName())) { 1842 // Not the right package name; skip this one. 1843 continue; 1844 } 1845 if (isMatchedUser(m, userHandle)) { 1846 matchedAccounts.add(m); 1847 } 1848 if (!crossUserAccess && !isVisibleForUser(m, userHandle, false)) { 1849 // Account is not visible for the current user; skip this one. 1850 continue; 1851 } 1852 accounts.add(m); 1853 } 1854 1855 // Return the account if it exactly matches. Otherwise, return any account that's visible 1856 if (mTelephonyFeatureFlags.workProfileApiSplit() && !crossUserAccess && !includeAll 1857 && !matchedAccounts.isEmpty()) { 1858 return matchedAccounts; 1859 } 1860 1861 return accounts; 1862 } 1863 1864 /** 1865 * Clean up the orphan {@code PhoneAccount}. An orphan {@code PhoneAccount} is a phone 1866 * account that does not have a {@code UserHandle} or belongs to a deleted package. 1867 * 1868 * @return the number of orphan {@code PhoneAccount} deleted. 1869 */ cleanupOrphanedPhoneAccounts()1870 public int cleanupOrphanedPhoneAccounts() { 1871 ArrayList<PhoneAccount> badAccountsList = new ArrayList<>(); 1872 HashMap<String, Boolean> packageLookup = new HashMap<>(); 1873 HashMap<PhoneAccount, Boolean> userHandleLookup = new HashMap<>(); 1874 1875 // iterate over all accounts in registrar 1876 for (PhoneAccount pa : mState.accounts) { 1877 String packageName = pa.getAccountHandle().getComponentName().getPackageName(); 1878 1879 // check if the package for the PhoneAccount is uninstalled 1880 if (packageLookup.computeIfAbsent(packageName, 1881 pn -> isPackageUninstalled(pn))) { 1882 badAccountsList.add(pa); 1883 } 1884 // check if PhoneAccount does not have a valid UserHandle (user was deleted) 1885 else if (userHandleLookup.computeIfAbsent(pa, 1886 a -> isUserHandleDeletedForPhoneAccount(a))) { 1887 badAccountsList.add(pa); 1888 } 1889 } 1890 1891 mState.accounts.removeAll(badAccountsList); 1892 1893 return badAccountsList.size(); 1894 } 1895 isPackageUninstalled(String packageName)1896 public Boolean isPackageUninstalled(String packageName) { 1897 try { 1898 mContext.getPackageManager().getPackageInfo(packageName, 0); 1899 return false; 1900 } catch (PackageManager.NameNotFoundException e) { 1901 return true; 1902 } 1903 } 1904 isUserHandleDeletedForPhoneAccount(PhoneAccount phoneAccount)1905 private Boolean isUserHandleDeletedForPhoneAccount(PhoneAccount phoneAccount) { 1906 UserHandle userHandle = phoneAccount.getAccountHandle().getUserHandle(); 1907 return (userHandle == null) || 1908 (mUserManager.getSerialNumberForUser(userHandle) == -1L); 1909 } 1910 1911 // 1912 // State Implementation for PhoneAccountRegistrar 1913 // 1914 1915 /** 1916 * The state of this {@code PhoneAccountRegistrar}. 1917 */ 1918 @VisibleForTesting 1919 public static class State { 1920 /** 1921 * Store the default phone account handle of users. If no record of a user can be found in 1922 * the map, it means that no default phone account handle is set in that user. 1923 */ 1924 public final Map<UserHandle, DefaultPhoneAccountHandle> defaultOutgoingAccountHandles 1925 = new ConcurrentHashMap<>(); 1926 1927 /** 1928 * The complete list of {@code PhoneAccount}s known to the Telecom subsystem. 1929 */ 1930 public final List<PhoneAccount> accounts = new CopyOnWriteArrayList<>(); 1931 1932 /** 1933 * The version number of the State data. 1934 */ 1935 public int versionNumber; 1936 } 1937 1938 /** 1939 * The default {@link PhoneAccountHandle} of a user. 1940 */ 1941 public static class DefaultPhoneAccountHandle { 1942 1943 public final UserHandle userHandle; 1944 1945 public PhoneAccountHandle phoneAccountHandle; 1946 1947 public final String groupId; 1948 DefaultPhoneAccountHandle(UserHandle userHandle, PhoneAccountHandle phoneAccountHandle, String groupId)1949 public DefaultPhoneAccountHandle(UserHandle userHandle, 1950 PhoneAccountHandle phoneAccountHandle, String groupId) { 1951 this.userHandle = userHandle; 1952 this.phoneAccountHandle = phoneAccountHandle; 1953 this.groupId = groupId; 1954 } 1955 } 1956 1957 /** 1958 * Dumps the state of the {@link CallsManager}. 1959 * 1960 * @param pw The {@code IndentingPrintWriter} to write the state to. 1961 */ dump(IndentingPrintWriter pw)1962 public void dump(IndentingPrintWriter pw) { 1963 if (mState != null) { 1964 pw.println("xmlVersion: " + mState.versionNumber); 1965 DefaultPhoneAccountHandle defaultPhoneAccountHandle 1966 = mState.defaultOutgoingAccountHandles.get(Process.myUserHandle()); 1967 pw.println("defaultOutgoing: " + (defaultPhoneAccountHandle == null ? "none" : 1968 defaultPhoneAccountHandle.phoneAccountHandle)); 1969 PhoneAccountHandle defaultOutgoing = 1970 getOutgoingPhoneAccountForScheme(PhoneAccount.SCHEME_TEL, mCurrentUserHandle); 1971 pw.print("outgoingPhoneAccountForTelScheme: "); 1972 if (defaultOutgoing == null) { 1973 pw.println("none"); 1974 } else { 1975 pw.println(defaultOutgoing); 1976 } 1977 // SubscriptionManager will throw if FEATURE_TELEPHONY_SUBSCRIPTION is not present. 1978 if (mContext.getPackageManager().hasSystemFeature( 1979 PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)) { 1980 pw.println("defaultVoiceSubId: " 1981 + SubscriptionManager.getDefaultVoiceSubscriptionId()); 1982 } 1983 pw.println("simCallManager: " + getSimCallManager(mCurrentUserHandle)); 1984 pw.println("phoneAccounts:"); 1985 pw.increaseIndent(); 1986 for (PhoneAccount phoneAccount : mState.accounts) { 1987 pw.println(phoneAccount); 1988 } 1989 pw.decreaseIndent(); 1990 pw.increaseIndent(); 1991 pw.println("test emergency PhoneAccount filter: " + mTestPhoneAccountPackageNameFilters); 1992 pw.decreaseIndent(); 1993 } 1994 } 1995 sortPhoneAccounts()1996 private void sortPhoneAccounts() { 1997 if (mState.accounts.size() > 1) { 1998 // Sort the phone accounts using sort order: 1999 // 1) SIM accounts first, followed by non-sim accounts 2000 // 2) Sort order, with those specifying no sort order last. 2001 // 3) Label 2002 2003 // Comparator to sort SIM subscriptions before non-sim subscriptions. 2004 Comparator<PhoneAccount> bySimCapability = (p1, p2) -> { 2005 if (p1.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) 2006 && !p2.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) { 2007 return -1; 2008 } else if (!p1.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION) 2009 && p2.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION)) { 2010 return 1; 2011 } else { 2012 return 0; 2013 } 2014 }; 2015 2016 // Create a string comparator which will sort strings, placing nulls last. 2017 Comparator<String> nullSafeStringComparator = Comparator.nullsLast( 2018 String::compareTo); 2019 2020 // Comparator which places PhoneAccounts with a specified sort order first, followed by 2021 // those with no sort order. 2022 Comparator<PhoneAccount> bySortOrder = (p1, p2) -> { 2023 int sort1 = p1.getExtras() == null ? Integer.MAX_VALUE: 2024 p1.getExtras().getInt(PhoneAccount.EXTRA_SORT_ORDER, Integer.MAX_VALUE); 2025 int sort2 = p2.getExtras() == null ? Integer.MAX_VALUE: 2026 p2.getExtras().getInt(PhoneAccount.EXTRA_SORT_ORDER, Integer.MAX_VALUE); 2027 return Integer.compare(sort1, sort2); 2028 }; 2029 2030 // Comparator which sorts PhoneAccounts by label. 2031 Comparator<PhoneAccount> byLabel = (p1, p2) -> { 2032 String s1 = p1.getLabel() == null ? null : p1.getLabel().toString(); 2033 String s2 = p2.getLabel() == null ? null : p2.getLabel().toString(); 2034 return nullSafeStringComparator.compare(s1, s2); 2035 }; 2036 2037 // Sort the phone accounts. 2038 mState.accounts.sort(bySimCapability.thenComparing(bySortOrder.thenComparing(byLabel))); 2039 } 2040 } 2041 2042 //////////////////////////////////////////////////////////////////////////////////////////////// 2043 // 2044 // State management 2045 // 2046 2047 private class AsyncXmlWriter extends AsyncTask<ByteArrayOutputStream, Void, Void> { 2048 @Override doInBackground(ByteArrayOutputStream... args)2049 public Void doInBackground(ByteArrayOutputStream... args) { 2050 final ByteArrayOutputStream buffer = args[0]; 2051 FileOutputStream fileOutput = null; 2052 try { 2053 synchronized (mWriteLock) { 2054 fileOutput = mAtomicFile.startWrite(); 2055 buffer.writeTo(fileOutput); 2056 mAtomicFile.finishWrite(fileOutput); 2057 } 2058 } catch (IOException e) { 2059 Log.e(this, e, "Writing state to XML file"); 2060 mAtomicFile.failWrite(fileOutput); 2061 } 2062 return null; 2063 } 2064 } 2065 write()2066 private void write() { 2067 try { 2068 sortPhoneAccounts(); 2069 ByteArrayOutputStream os = new ByteArrayOutputStream(); 2070 XmlSerializer serializer = Xml.resolveSerializer(os); 2071 writeToXml(mState, serializer, mContext, mTelephonyFeatureFlags); 2072 serializer.flush(); 2073 new AsyncXmlWriter().execute(os); 2074 } catch (IOException e) { 2075 Log.e(this, e, "Writing state to XML buffer"); 2076 } 2077 } 2078 read()2079 private void read() { 2080 final InputStream is; 2081 try { 2082 is = mAtomicFile.openRead(); 2083 } catch (FileNotFoundException ex) { 2084 return; 2085 } 2086 2087 boolean versionChanged = false; 2088 2089 try { 2090 XmlPullParser parser = Xml.resolvePullParser(is); 2091 parser.nextTag(); 2092 mState = readFromXml(parser, mContext, mTelephonyFeatureFlags, mTelecomFeatureFlags); 2093 migratePhoneAccountHandle(mState); 2094 versionChanged = mState.versionNumber < EXPECTED_STATE_VERSION; 2095 2096 } catch (IOException | XmlPullParserException e) { 2097 Log.e(this, e, "Reading state from XML file"); 2098 mState = new State(); 2099 } finally { 2100 try { 2101 is.close(); 2102 } catch (IOException e) { 2103 Log.e(this, e, "Closing InputStream"); 2104 } 2105 } 2106 2107 // Verify all of the UserHandles. 2108 List<PhoneAccount> badAccounts = new ArrayList<>(); 2109 for (PhoneAccount phoneAccount : mState.accounts) { 2110 UserHandle userHandle = phoneAccount.getAccountHandle().getUserHandle(); 2111 if (userHandle == null) { 2112 Log.w(this, "Missing UserHandle for %s", phoneAccount); 2113 badAccounts.add(phoneAccount); 2114 } else if (mUserManager.getSerialNumberForUser(userHandle) == -1) { 2115 Log.w(this, "User does not exist for %s", phoneAccount); 2116 badAccounts.add(phoneAccount); 2117 } 2118 } 2119 mState.accounts.removeAll(badAccounts); 2120 2121 // If an upgrade occurred, write out the changed data. 2122 if (versionChanged || !badAccounts.isEmpty()) { 2123 write(); 2124 } 2125 } 2126 2127 private static void writeToXml(State state, XmlSerializer serializer, Context context, 2128 FeatureFlags telephonyFeatureFlags) throws IOException { 2129 sStateXml.writeToXml(state, serializer, context, telephonyFeatureFlags); 2130 } 2131 2132 private static State readFromXml(XmlPullParser parser, Context context, 2133 FeatureFlags telephonyFeatureFlags, 2134 com.android.server.telecom.flags.FeatureFlags telecomFeatureFlags) 2135 throws IOException, XmlPullParserException { 2136 State s = sStateXml.readFromXml(parser, 0, context, 2137 telephonyFeatureFlags, telecomFeatureFlags); 2138 return s != null ? s : new State(); 2139 } 2140 2141 /** 2142 * Try to migrate the ID of default phone account handle from IccId to SubId. 2143 */ 2144 @VisibleForTesting 2145 public void migratePhoneAccountHandle(State state) { 2146 if (mSubscriptionManager == null) { 2147 return; 2148 } 2149 // Use getAllSubscirptionInfoList() to get the mapping between iccId and subId 2150 // from the subscription database 2151 List<SubscriptionInfo> subscriptionInfos = mSubscriptionManager 2152 .getAllSubscriptionInfoList(); 2153 Map<UserHandle, DefaultPhoneAccountHandle> defaultPhoneAccountHandles 2154 = state.defaultOutgoingAccountHandles; 2155 for (Map.Entry<UserHandle, DefaultPhoneAccountHandle> entry 2156 : defaultPhoneAccountHandles.entrySet()) { 2157 DefaultPhoneAccountHandle defaultPhoneAccountHandle = entry.getValue(); 2158 2159 // Migrate Telephony PhoneAccountHandle only 2160 String telephonyComponentName = 2161 "com.android.phone/com.android.services.telephony.TelephonyConnectionService"; 2162 if (!defaultPhoneAccountHandle.phoneAccountHandle.getComponentName() 2163 .flattenToString().equals(telephonyComponentName)) { 2164 continue; 2165 } 2166 // Migrate from IccId to SubId 2167 for (SubscriptionInfo subscriptionInfo : subscriptionInfos) { 2168 String phoneAccountHandleId = defaultPhoneAccountHandle.phoneAccountHandle.getId(); 2169 // Some phone account handle would store phone account handle id with the IccId 2170 // string plus "F", and the getIccId() returns IccId string itself without "F", 2171 // so here need to use "startsWith" to match. 2172 if (phoneAccountHandleId != null && phoneAccountHandleId.startsWith( 2173 subscriptionInfo.getIccId())) { 2174 Log.i(this, "Found subscription ID to migrate: " 2175 + subscriptionInfo.getSubscriptionId()); 2176 defaultPhoneAccountHandle.phoneAccountHandle = new PhoneAccountHandle( 2177 defaultPhoneAccountHandle.phoneAccountHandle.getComponentName(), 2178 Integer.toString(subscriptionInfo.getSubscriptionId())); 2179 break; 2180 } 2181 } 2182 } 2183 } 2184 2185 //////////////////////////////////////////////////////////////////////////////////////////////// 2186 // 2187 // XML serialization 2188 // 2189 2190 @VisibleForTesting 2191 public abstract static class XmlSerialization<T> { 2192 private static final String TAG_VALUE = "value"; 2193 private static final String ATTRIBUTE_LENGTH = "length"; 2194 private static final String ATTRIBUTE_KEY = "key"; 2195 private static final String ATTRIBUTE_VALUE_TYPE = "type"; 2196 private static final String VALUE_TYPE_STRING = "string"; 2197 private static final String VALUE_TYPE_INTEGER = "integer"; 2198 private static final String VALUE_TYPE_BOOLEAN = "boolean"; 2199 2200 /** 2201 * Write the supplied object to XML 2202 */ 2203 public abstract void writeToXml(T o, XmlSerializer serializer, Context context, 2204 FeatureFlags telephonyFeatureFlags) throws IOException; 2205 2206 /** 2207 * Read from the supplied XML into a new object, returning null in case of an 2208 * unrecoverable schema mismatch or other data error. 'parser' must be already 2209 * positioned at the first tag that is expected to have been emitted by this 2210 * object's writeToXml(). This object tries to fail early without modifying 2211 * 'parser' if it does not recognize the data it sees. 2212 */ 2213 public abstract T readFromXml(XmlPullParser parser, int version, Context context, 2214 FeatureFlags telephonyFeatureFlags, 2215 com.android.server.telecom.flags.FeatureFlags featureFlags) 2216 throws IOException, XmlPullParserException; 2217 2218 protected void writeTextIfNonNull(String tagName, Object value, XmlSerializer serializer) 2219 throws IOException { 2220 if (value != null) { 2221 serializer.startTag(null, tagName); 2222 serializer.text(Objects.toString(value)); 2223 serializer.endTag(null, tagName); 2224 } 2225 } 2226 2227 /** 2228 * Serializes a List of PhoneAccountHandles. 2229 * @param tagName The tag for the List 2230 * @param handles The List of PhoneAccountHandles to serialize 2231 * @param serializer The serializer 2232 * @throws IOException if serialization fails. 2233 */ 2234 protected void writePhoneAccountHandleSet(String tagName, Set<PhoneAccountHandle> handles, 2235 XmlSerializer serializer, Context context, FeatureFlags telephonyFeatureFlags) 2236 throws IOException { 2237 serializer.startTag(null, tagName); 2238 if (handles != null) { 2239 serializer.attribute(null, ATTRIBUTE_LENGTH, Objects.toString(handles.size())); 2240 for (PhoneAccountHandle handle : handles) { 2241 sPhoneAccountHandleXml.writeToXml(handle, serializer, context, 2242 telephonyFeatureFlags); 2243 } 2244 } else { 2245 serializer.attribute(null, ATTRIBUTE_LENGTH, "0"); 2246 } 2247 serializer.endTag(null, tagName); 2248 } 2249 2250 /** 2251 * Serializes a string array. 2252 * 2253 * @param tagName The tag name for the string array. 2254 * @param values The string values to serialize. 2255 * @param serializer The serializer. 2256 * @throws IOException 2257 */ 2258 protected void writeStringList(String tagName, List<String> values, 2259 XmlSerializer serializer) 2260 throws IOException { 2261 2262 serializer.startTag(null, tagName); 2263 if (values != null) { 2264 serializer.attribute(null, ATTRIBUTE_LENGTH, Objects.toString(values.size())); 2265 for (String toSerialize : values) { 2266 serializer.startTag(null, TAG_VALUE); 2267 if (toSerialize != null ){ 2268 serializer.text(toSerialize); 2269 } 2270 serializer.endTag(null, TAG_VALUE); 2271 } 2272 } else { 2273 serializer.attribute(null, ATTRIBUTE_LENGTH, "0"); 2274 } 2275 serializer.endTag(null, tagName); 2276 } 2277 2278 protected void writeBundle(String tagName, Bundle values, XmlSerializer serializer) 2279 throws IOException { 2280 2281 serializer.startTag(null, tagName); 2282 if (values != null) { 2283 for (String key : values.keySet()) { 2284 Object value = values.get(key); 2285 2286 if (value == null) { 2287 continue; 2288 } 2289 2290 String valueType; 2291 if (value instanceof String) { 2292 valueType = VALUE_TYPE_STRING; 2293 } else if (value instanceof Integer) { 2294 valueType = VALUE_TYPE_INTEGER; 2295 } else if (value instanceof Boolean) { 2296 valueType = VALUE_TYPE_BOOLEAN; 2297 } else { 2298 Log.w(this, 2299 "PhoneAccounts support only string, integer and boolean extras TY."); 2300 continue; 2301 } 2302 2303 serializer.startTag(null, TAG_VALUE); 2304 serializer.attribute(null, ATTRIBUTE_KEY, key); 2305 serializer.attribute(null, ATTRIBUTE_VALUE_TYPE, valueType); 2306 serializer.text(Objects.toString(value)); 2307 serializer.endTag(null, TAG_VALUE); 2308 } 2309 } 2310 serializer.endTag(null, tagName); 2311 } 2312 2313 protected void writeIconIfNonNull(String tagName, Icon value, XmlSerializer serializer) 2314 throws IOException { 2315 if (value != null) { 2316 String text = writeIconToBase64String(value); 2317 serializer.startTag(null, tagName); 2318 serializer.text(text); 2319 serializer.endTag(null, tagName); 2320 } 2321 } 2322 2323 public static String writeIconToBase64String(Icon icon) throws IOException { 2324 ByteArrayOutputStream stream = new ByteArrayOutputStream(); 2325 icon.writeToStream(stream); 2326 byte[] iconByteArray = stream.toByteArray(); 2327 return Base64.encodeToString(iconByteArray, 0, iconByteArray.length, 0); 2328 } 2329 2330 protected void writeLong(String tagName, long value, XmlSerializer serializer) 2331 throws IOException { 2332 serializer.startTag(null, tagName); 2333 serializer.text(Long.valueOf(value).toString()); 2334 serializer.endTag(null, tagName); 2335 } 2336 2337 protected void writeNonNullString(String tagName, String value, XmlSerializer serializer) 2338 throws IOException { 2339 serializer.startTag(null, tagName); 2340 serializer.text(value != null ? value : ""); 2341 serializer.endTag(null, tagName); 2342 } 2343 2344 protected Set<PhoneAccountHandle> readPhoneAccountHandleSet(XmlPullParser parser, 2345 int version, Context context, FeatureFlags telephonyFeatureFlags, 2346 com.android.server.telecom.flags.FeatureFlags telecomFeatureFlags) 2347 throws IOException, XmlPullParserException { 2348 int length = Integer.parseInt(parser.getAttributeValue(null, ATTRIBUTE_LENGTH)); 2349 Set<PhoneAccountHandle> handles = new HashSet<>(length); 2350 if (length == 0) return handles; 2351 2352 int outerDepth = parser.getDepth(); 2353 while (XmlUtils.nextElementWithin(parser, outerDepth)) { 2354 handles.add(sPhoneAccountHandleXml.readFromXml(parser, version, context, 2355 telephonyFeatureFlags, telecomFeatureFlags)); 2356 } 2357 return handles; 2358 } 2359 2360 /** 2361 * Reads a string array from the XML parser. 2362 * 2363 * @param parser The XML parser. 2364 * @return String array containing the parsed values. 2365 * @throws IOException Exception related to IO. 2366 * @throws XmlPullParserException Exception related to parsing. 2367 */ 2368 protected List<String> readStringList(XmlPullParser parser) 2369 throws IOException, XmlPullParserException { 2370 2371 int length = Integer.parseInt(parser.getAttributeValue(null, ATTRIBUTE_LENGTH)); 2372 List<String> arrayEntries = new ArrayList<String>(length); 2373 String value = null; 2374 2375 if (length == 0) { 2376 return arrayEntries; 2377 } 2378 2379 int outerDepth = parser.getDepth(); 2380 while (XmlUtils.nextElementWithin(parser, outerDepth)) { 2381 if (parser.getName().equals(TAG_VALUE)) { 2382 parser.next(); 2383 value = parser.getText(); 2384 arrayEntries.add(value); 2385 } 2386 } 2387 2388 return arrayEntries; 2389 } 2390 2391 /** 2392 * Reads a bundle from the XML parser. 2393 * 2394 * @param parser The XML parser. 2395 * @return Bundle containing the parsed values. 2396 * @throws IOException Exception related to IO. 2397 * @throws XmlPullParserException Exception related to parsing. 2398 */ 2399 protected Bundle readBundle(XmlPullParser parser) 2400 throws IOException, XmlPullParserException { 2401 2402 Bundle bundle = null; 2403 int outerDepth = parser.getDepth(); 2404 while (XmlUtils.nextElementWithin(parser, outerDepth)) { 2405 if (parser.getName().equals(TAG_VALUE)) { 2406 String valueType = parser.getAttributeValue(null, ATTRIBUTE_VALUE_TYPE); 2407 String key = parser.getAttributeValue(null, ATTRIBUTE_KEY); 2408 parser.next(); 2409 String value = parser.getText(); 2410 2411 if (bundle == null) { 2412 bundle = new Bundle(); 2413 } 2414 2415 // Do not write null values to the bundle. 2416 if (value == null) { 2417 continue; 2418 } 2419 2420 if (VALUE_TYPE_STRING.equals(valueType)) { 2421 bundle.putString(key, value); 2422 } else if (VALUE_TYPE_INTEGER.equals(valueType)) { 2423 try { 2424 int intValue = Integer.parseInt(value); 2425 bundle.putInt(key, intValue); 2426 } catch (NumberFormatException nfe) { 2427 Log.w(this, "Invalid integer PhoneAccount extra."); 2428 } 2429 } else if (VALUE_TYPE_BOOLEAN.equals(valueType)) { 2430 boolean boolValue = Boolean.parseBoolean(value); 2431 bundle.putBoolean(key, boolValue); 2432 } else { 2433 Log.w(this, "Invalid type " + valueType + " for PhoneAccount bundle."); 2434 } 2435 } 2436 } 2437 return bundle; 2438 } 2439 2440 protected Bitmap readBitmap(XmlPullParser parser) { 2441 byte[] imageByteArray = Base64.decode(parser.getText(), 0); 2442 return BitmapFactory.decodeByteArray(imageByteArray, 0, imageByteArray.length); 2443 } 2444 2445 @Nullable 2446 protected Icon readIcon(XmlPullParser parser) throws IOException { 2447 try { 2448 byte[] iconByteArray = Base64.decode(parser.getText(), 0); 2449 ByteArrayInputStream stream = new ByteArrayInputStream(iconByteArray); 2450 return Icon.createFromStream(stream); 2451 } catch (IllegalArgumentException e) { 2452 Log.e(this, e, "Bitmap must not be null."); 2453 return null; 2454 } 2455 } 2456 } 2457 2458 @VisibleForTesting 2459 public static final XmlSerialization<State> sStateXml = 2460 new XmlSerialization<State>() { 2461 private static final String CLASS_STATE = "phone_account_registrar_state"; 2462 private static final String DEFAULT_OUTGOING = "default_outgoing"; 2463 private static final String ACCOUNTS = "accounts"; 2464 private static final String VERSION = "version"; 2465 2466 @Override 2467 public void writeToXml(State o, XmlSerializer serializer, Context context, 2468 FeatureFlags telephonyFeatureFlags) throws IOException { 2469 if (o != null) { 2470 serializer.startTag(null, CLASS_STATE); 2471 serializer.attribute(null, VERSION, Objects.toString(EXPECTED_STATE_VERSION)); 2472 2473 serializer.startTag(null, DEFAULT_OUTGOING); 2474 for (DefaultPhoneAccountHandle defaultPhoneAccountHandle : o 2475 .defaultOutgoingAccountHandles.values()) { 2476 sDefaultPhoneAccountHandleXml 2477 .writeToXml(defaultPhoneAccountHandle, serializer, context, 2478 telephonyFeatureFlags); 2479 } 2480 serializer.endTag(null, DEFAULT_OUTGOING); 2481 2482 serializer.startTag(null, ACCOUNTS); 2483 for (PhoneAccount m : o.accounts) { 2484 sPhoneAccountXml.writeToXml(m, serializer, context, telephonyFeatureFlags); 2485 } 2486 serializer.endTag(null, ACCOUNTS); 2487 2488 serializer.endTag(null, CLASS_STATE); 2489 } 2490 } 2491 2492 @Override 2493 public State readFromXml(XmlPullParser parser, int version, Context context, 2494 FeatureFlags telephonyFeatureFlags, 2495 com.android.server.telecom.flags.FeatureFlags telecomFeatureFlags) 2496 throws IOException, XmlPullParserException { 2497 if (parser.getName().equals(CLASS_STATE)) { 2498 State s = new State(); 2499 2500 String rawVersion = parser.getAttributeValue(null, VERSION); 2501 s.versionNumber = TextUtils.isEmpty(rawVersion) ? 1 : Integer.parseInt(rawVersion); 2502 2503 int outerDepth = parser.getDepth(); 2504 while (XmlUtils.nextElementWithin(parser, outerDepth)) { 2505 if (parser.getName().equals(DEFAULT_OUTGOING)) { 2506 if (s.versionNumber < 9) { 2507 // Migrate old default phone account handle here by assuming the 2508 // default phone account handle belongs to the primary user. Also, 2509 // assume there are no groups. 2510 parser.nextTag(); 2511 PhoneAccountHandle phoneAccountHandle = sPhoneAccountHandleXml 2512 .readFromXml(parser, s.versionNumber, context, 2513 telephonyFeatureFlags, telecomFeatureFlags); 2514 UserManager userManager = context.getSystemService(UserManager.class); 2515 // UserManager#getMainUser requires either the MANAGE_USERS, 2516 // CREATE_USERS, or QUERY_USERS permission. 2517 UserHandle primaryUser = userManager.getMainUser(); 2518 UserInfo primaryUserInfo = userManager.getPrimaryUser(); 2519 if (!telecomFeatureFlags.telecomResolveHiddenDependencies()) { 2520 primaryUser = primaryUserInfo != null 2521 ? primaryUserInfo.getUserHandle() 2522 : null; 2523 } 2524 if (primaryUser != null) { 2525 DefaultPhoneAccountHandle defaultPhoneAccountHandle 2526 = new DefaultPhoneAccountHandle(primaryUser, 2527 phoneAccountHandle, "" /* groupId */); 2528 s.defaultOutgoingAccountHandles 2529 .put(primaryUser, defaultPhoneAccountHandle); 2530 } 2531 } else { 2532 int defaultAccountHandlesDepth = parser.getDepth(); 2533 while (XmlUtils.nextElementWithin(parser, defaultAccountHandlesDepth)) { 2534 DefaultPhoneAccountHandle accountHandle 2535 = sDefaultPhoneAccountHandleXml 2536 .readFromXml(parser, s.versionNumber, context, 2537 telephonyFeatureFlags, telecomFeatureFlags); 2538 if (accountHandle != null && s.accounts != null) { 2539 s.defaultOutgoingAccountHandles 2540 .put(accountHandle.userHandle, accountHandle); 2541 } 2542 } 2543 } 2544 } else if (parser.getName().equals(ACCOUNTS)) { 2545 int accountsDepth = parser.getDepth(); 2546 while (XmlUtils.nextElementWithin(parser, accountsDepth)) { 2547 PhoneAccount account = sPhoneAccountXml.readFromXml(parser, 2548 s.versionNumber, context, telephonyFeatureFlags, 2549 telecomFeatureFlags); 2550 2551 if (account != null && s.accounts != null) { 2552 s.accounts.add(account); 2553 } 2554 } 2555 } 2556 } 2557 return s; 2558 } 2559 return null; 2560 } 2561 }; 2562 2563 @VisibleForTesting 2564 public static final XmlSerialization<DefaultPhoneAccountHandle> sDefaultPhoneAccountHandleXml = 2565 new XmlSerialization<DefaultPhoneAccountHandle>() { 2566 private static final String CLASS_DEFAULT_OUTGOING_PHONE_ACCOUNT_HANDLE 2567 = "default_outgoing_phone_account_handle"; 2568 private static final String USER_SERIAL_NUMBER = "user_serial_number"; 2569 private static final String GROUP_ID = "group_id"; 2570 private static final String ACCOUNT_HANDLE = "account_handle"; 2571 2572 @Override 2573 public void writeToXml(DefaultPhoneAccountHandle o, XmlSerializer serializer, 2574 Context context, FeatureFlags telephonyFeatureFlags) throws IOException { 2575 if (o != null) { 2576 final UserManager userManager = context.getSystemService(UserManager.class); 2577 final long serialNumber = userManager.getSerialNumberForUser(o.userHandle); 2578 if (serialNumber != -1) { 2579 serializer.startTag(null, CLASS_DEFAULT_OUTGOING_PHONE_ACCOUNT_HANDLE); 2580 writeLong(USER_SERIAL_NUMBER, serialNumber, serializer); 2581 writeNonNullString(GROUP_ID, o.groupId, serializer); 2582 serializer.startTag(null, ACCOUNT_HANDLE); 2583 sPhoneAccountHandleXml.writeToXml(o.phoneAccountHandle, serializer, 2584 context, telephonyFeatureFlags); 2585 serializer.endTag(null, ACCOUNT_HANDLE); 2586 serializer.endTag(null, CLASS_DEFAULT_OUTGOING_PHONE_ACCOUNT_HANDLE); 2587 } 2588 } 2589 } 2590 2591 @Override 2592 public DefaultPhoneAccountHandle readFromXml(XmlPullParser parser, int version, 2593 Context context, FeatureFlags telephonyFeatureFlags, 2594 com.android.server.telecom.flags.FeatureFlags telecomFeatureFlags) 2595 throws IOException, XmlPullParserException { 2596 if (parser.getName().equals(CLASS_DEFAULT_OUTGOING_PHONE_ACCOUNT_HANDLE)) { 2597 int outerDepth = parser.getDepth(); 2598 PhoneAccountHandle accountHandle = null; 2599 String userSerialNumberString = null; 2600 String groupId = ""; 2601 while (XmlUtils.nextElementWithin(parser, outerDepth)) { 2602 if (parser.getName().equals(ACCOUNT_HANDLE)) { 2603 parser.nextTag(); 2604 accountHandle = sPhoneAccountHandleXml.readFromXml(parser, version, 2605 context, telephonyFeatureFlags, telecomFeatureFlags); 2606 } else if (parser.getName().equals(USER_SERIAL_NUMBER)) { 2607 parser.next(); 2608 userSerialNumberString = parser.getText(); 2609 } else if (parser.getName().equals(GROUP_ID)) { 2610 if (parser.next() == XmlPullParser.TEXT) { 2611 groupId = parser.getText(); 2612 } 2613 } 2614 } 2615 UserHandle userHandle = null; 2616 if (userSerialNumberString != null) { 2617 try { 2618 long serialNumber = Long.parseLong(userSerialNumberString); 2619 userHandle = context.getSystemService(UserManager.class) 2620 .getUserForSerialNumber(serialNumber); 2621 } catch (NumberFormatException e) { 2622 Log.e(this, e, 2623 "Could not parse UserHandle " + userSerialNumberString); 2624 } 2625 } 2626 if (accountHandle != null && userHandle != null && groupId != null) { 2627 return new DefaultPhoneAccountHandle(userHandle, accountHandle, 2628 groupId); 2629 } 2630 } 2631 return null; 2632 } 2633 }; 2634 2635 2636 @VisibleForTesting 2637 public static final XmlSerialization<PhoneAccount> sPhoneAccountXml = 2638 new XmlSerialization<PhoneAccount>() { 2639 private static final String CLASS_PHONE_ACCOUNT = "phone_account"; 2640 private static final String ACCOUNT_HANDLE = "account_handle"; 2641 private static final String ADDRESS = "handle"; 2642 private static final String SUBSCRIPTION_ADDRESS = "subscription_number"; 2643 private static final String CAPABILITIES = "capabilities"; 2644 private static final String SUPPORTED_AUDIO_ROUTES = "supported_audio_routes"; 2645 private static final String ICON_RES_ID = "icon_res_id"; 2646 private static final String ICON_PACKAGE_NAME = "icon_package_name"; 2647 private static final String ICON_BITMAP = "icon_bitmap"; 2648 private static final String ICON_TINT = "icon_tint"; 2649 private static final String HIGHLIGHT_COLOR = "highlight_color"; 2650 private static final String LABEL = "label"; 2651 private static final String SHORT_DESCRIPTION = "short_description"; 2652 private static final String SUPPORTED_URI_SCHEMES = "supported_uri_schemes"; 2653 private static final String ICON = "icon"; 2654 private static final String EXTRAS = "extras"; 2655 private static final String ENABLED = "enabled"; 2656 private static final String SIMULTANEOUS_CALLING_RESTRICTION 2657 = "simultaneous_calling_restriction"; 2658 2659 @Override 2660 public void writeToXml(PhoneAccount o, XmlSerializer serializer, Context context, 2661 FeatureFlags telephonyFeatureFlags) throws IOException { 2662 if (o != null) { 2663 serializer.startTag(null, CLASS_PHONE_ACCOUNT); 2664 2665 if (o.getAccountHandle() != null) { 2666 serializer.startTag(null, ACCOUNT_HANDLE); 2667 sPhoneAccountHandleXml.writeToXml(o.getAccountHandle(), serializer, context, 2668 telephonyFeatureFlags); 2669 serializer.endTag(null, ACCOUNT_HANDLE); 2670 } 2671 2672 writeTextIfNonNull(ADDRESS, o.getAddress(), serializer); 2673 writeTextIfNonNull(SUBSCRIPTION_ADDRESS, o.getSubscriptionAddress(), serializer); 2674 writeTextIfNonNull(CAPABILITIES, Integer.toString(o.getCapabilities()), serializer); 2675 writeIconIfNonNull(ICON, o.getIcon(), serializer); 2676 writeTextIfNonNull(HIGHLIGHT_COLOR, 2677 Integer.toString(o.getHighlightColor()), serializer); 2678 writeTextIfNonNull(LABEL, o.getLabel(), serializer); 2679 writeTextIfNonNull(SHORT_DESCRIPTION, o.getShortDescription(), serializer); 2680 writeStringList(SUPPORTED_URI_SCHEMES, o.getSupportedUriSchemes(), serializer); 2681 writeBundle(EXTRAS, o.getExtras(), serializer); 2682 writeTextIfNonNull(ENABLED, o.isEnabled() ? "true" : "false" , serializer); 2683 writeTextIfNonNull(SUPPORTED_AUDIO_ROUTES, Integer.toString( 2684 o.getSupportedAudioRoutes()), serializer); 2685 if (o.hasSimultaneousCallingRestriction() 2686 && telephonyFeatureFlags.simultaneousCallingIndications()) { 2687 writePhoneAccountHandleSet(SIMULTANEOUS_CALLING_RESTRICTION, 2688 o.getSimultaneousCallingRestriction(), serializer, context, 2689 telephonyFeatureFlags); 2690 } 2691 2692 serializer.endTag(null, CLASS_PHONE_ACCOUNT); 2693 } 2694 } 2695 2696 public PhoneAccount readFromXml(XmlPullParser parser, int version, Context context, 2697 FeatureFlags telephonyFeatureFlags, 2698 com.android.server.telecom.flags.FeatureFlags telecomFeatureFlags) throws IOException, XmlPullParserException { 2699 if (parser.getName().equals(CLASS_PHONE_ACCOUNT)) { 2700 int outerDepth = parser.getDepth(); 2701 PhoneAccountHandle accountHandle = null; 2702 Uri address = null; 2703 Uri subscriptionAddress = null; 2704 int capabilities = 0; 2705 int supportedAudioRoutes = 0; 2706 int iconResId = PhoneAccount.NO_RESOURCE_ID; 2707 String iconPackageName = null; 2708 Bitmap iconBitmap = null; 2709 int iconTint = PhoneAccount.NO_ICON_TINT; 2710 int highlightColor = PhoneAccount.NO_HIGHLIGHT_COLOR; 2711 String label = null; 2712 String shortDescription = null; 2713 List<String> supportedUriSchemes = null; 2714 Icon icon = null; 2715 boolean enabled = false; 2716 Bundle extras = null; 2717 Set<PhoneAccountHandle> simultaneousCallingRestriction = null; 2718 2719 while (XmlUtils.nextElementWithin(parser, outerDepth)) { 2720 if (parser.getName().equals(ACCOUNT_HANDLE)) { 2721 parser.nextTag(); 2722 accountHandle = sPhoneAccountHandleXml.readFromXml(parser, version, 2723 context, telephonyFeatureFlags, telecomFeatureFlags); 2724 } else if (parser.getName().equals(ADDRESS)) { 2725 parser.next(); 2726 address = Uri.parse(parser.getText()); 2727 } else if (parser.getName().equals(SUBSCRIPTION_ADDRESS)) { 2728 parser.next(); 2729 String nextText = parser.getText(); 2730 subscriptionAddress = nextText == null ? null : Uri.parse(nextText); 2731 } else if (parser.getName().equals(CAPABILITIES)) { 2732 parser.next(); 2733 capabilities = Integer.parseInt(parser.getText()); 2734 } else if (parser.getName().equals(ICON_RES_ID)) { 2735 parser.next(); 2736 iconResId = Integer.parseInt(parser.getText()); 2737 } else if (parser.getName().equals(ICON_PACKAGE_NAME)) { 2738 parser.next(); 2739 iconPackageName = parser.getText(); 2740 } else if (parser.getName().equals(ICON_BITMAP)) { 2741 parser.next(); 2742 iconBitmap = readBitmap(parser); 2743 } else if (parser.getName().equals(ICON_TINT)) { 2744 parser.next(); 2745 iconTint = Integer.parseInt(parser.getText()); 2746 } else if (parser.getName().equals(HIGHLIGHT_COLOR)) { 2747 parser.next(); 2748 highlightColor = Integer.parseInt(parser.getText()); 2749 } else if (parser.getName().equals(LABEL)) { 2750 parser.next(); 2751 label = parser.getText(); 2752 } else if (parser.getName().equals(SHORT_DESCRIPTION)) { 2753 parser.next(); 2754 shortDescription = parser.getText(); 2755 } else if (parser.getName().equals(SUPPORTED_URI_SCHEMES)) { 2756 supportedUriSchemes = readStringList(parser); 2757 } else if (parser.getName().equals(ICON)) { 2758 parser.next(); 2759 icon = readIcon(parser); 2760 } else if (parser.getName().equals(ENABLED)) { 2761 parser.next(); 2762 enabled = "true".equalsIgnoreCase(parser.getText()); 2763 } else if (parser.getName().equals(EXTRAS)) { 2764 extras = readBundle(parser); 2765 } else if (parser.getName().equals(SUPPORTED_AUDIO_ROUTES)) { 2766 parser.next(); 2767 supportedAudioRoutes = Integer.parseInt(parser.getText()); 2768 } else if (parser.getName().equals(SIMULTANEOUS_CALLING_RESTRICTION)) { 2769 // We can not flag this because we always need to handle the case where 2770 // this info is in the XML for parsing reasons. We only flag setting the 2771 // parsed value below based on the flag. 2772 simultaneousCallingRestriction = readPhoneAccountHandleSet(parser, version, 2773 context, telephonyFeatureFlags, telecomFeatureFlags); 2774 } 2775 } 2776 2777 ComponentName pstnComponentName = new ComponentName("com.android.phone", 2778 "com.android.services.telephony.TelephonyConnectionService"); 2779 ComponentName sipComponentName = new ComponentName("com.android.phone", 2780 "com.android.services.telephony.sip.SipConnectionService"); 2781 2782 // Upgrade older phone accounts to specify the supported URI schemes. 2783 if (version < 2) { 2784 supportedUriSchemes = new ArrayList<>(); 2785 2786 // Handle the SIP connection service. 2787 // Check the system settings to see if it also should handle "tel" calls. 2788 if (accountHandle.getComponentName().equals(sipComponentName)) { 2789 boolean useSipForPstn = useSipForPstnCalls(context); 2790 supportedUriSchemes.add(PhoneAccount.SCHEME_SIP); 2791 if (useSipForPstn) { 2792 supportedUriSchemes.add(PhoneAccount.SCHEME_TEL); 2793 } 2794 } else { 2795 supportedUriSchemes.add(PhoneAccount.SCHEME_TEL); 2796 supportedUriSchemes.add(PhoneAccount.SCHEME_VOICEMAIL); 2797 } 2798 } 2799 2800 // Upgrade older phone accounts with explicit package name 2801 if (version < 5) { 2802 if (iconBitmap == null) { 2803 iconPackageName = accountHandle.getComponentName().getPackageName(); 2804 } 2805 } 2806 2807 if (version < 6) { 2808 // Always enable all SIP accounts on upgrade to version 6 2809 if (accountHandle.getComponentName().equals(sipComponentName)) { 2810 enabled = true; 2811 } 2812 } 2813 if (version < 7) { 2814 // Always enabled all PSTN acocunts on upgrade to version 7 2815 if (accountHandle.getComponentName().equals(pstnComponentName)) { 2816 enabled = true; 2817 } 2818 } 2819 if (version < 8) { 2820 // Migrate the SIP account handle ids to use SIP username instead of SIP URI. 2821 if (accountHandle.getComponentName().equals(sipComponentName)) { 2822 Uri accountUri = Uri.parse(accountHandle.getId()); 2823 if (accountUri.getScheme() != null && 2824 accountUri.getScheme().equals(PhoneAccount.SCHEME_SIP)) { 2825 accountHandle = new PhoneAccountHandle(accountHandle.getComponentName(), 2826 accountUri.getSchemeSpecificPart(), 2827 accountHandle.getUserHandle()); 2828 } 2829 } 2830 } 2831 2832 if (version < 9) { 2833 // Set supported audio routes to all by default 2834 supportedAudioRoutes = CallAudioState.ROUTE_ALL; 2835 } 2836 2837 PhoneAccount.Builder builder = PhoneAccount.builder(accountHandle, label) 2838 .setAddress(address) 2839 .setSubscriptionAddress(subscriptionAddress) 2840 .setCapabilities(capabilities) 2841 .setSupportedAudioRoutes(supportedAudioRoutes) 2842 .setShortDescription(shortDescription) 2843 .setSupportedUriSchemes(supportedUriSchemes) 2844 .setHighlightColor(highlightColor) 2845 .setExtras(extras) 2846 .setIsEnabled(enabled); 2847 2848 if (icon != null) { 2849 builder.setIcon(icon); 2850 } else if (iconBitmap != null) { 2851 builder.setIcon(Icon.createWithBitmap(iconBitmap)); 2852 } else if (!TextUtils.isEmpty(iconPackageName)) { 2853 builder.setIcon(Icon.createWithResource(iconPackageName, iconResId)); 2854 // TODO: Need to set tint. 2855 } else if (simultaneousCallingRestriction != null 2856 && telephonyFeatureFlags.simultaneousCallingIndications()) { 2857 builder.setSimultaneousCallingRestriction(simultaneousCallingRestriction); 2858 } 2859 2860 return builder.build(); 2861 } 2862 return null; 2863 } 2864 2865 /** 2866 * Determines if the SIP call settings specify to use SIP for all calls, including PSTN 2867 * calls. 2868 * 2869 * @param context The context. 2870 * @return {@code True} if SIP should be used for all calls. 2871 */ 2872 private boolean useSipForPstnCalls(Context context) { 2873 String option = Settings.System.getStringForUser(context.getContentResolver(), 2874 Settings.System.SIP_CALL_OPTIONS, context.getUserId()); 2875 option = (option != null) ? option : Settings.System.SIP_ADDRESS_ONLY; 2876 return option.equals(Settings.System.SIP_ALWAYS); 2877 } 2878 }; 2879 2880 @VisibleForTesting 2881 public static final XmlSerialization<PhoneAccountHandle> sPhoneAccountHandleXml = 2882 new XmlSerialization<PhoneAccountHandle>() { 2883 private static final String CLASS_PHONE_ACCOUNT_HANDLE = "phone_account_handle"; 2884 private static final String COMPONENT_NAME = "component_name"; 2885 private static final String ID = "id"; 2886 private static final String USER_SERIAL_NUMBER = "user_serial_number"; 2887 2888 @Override 2889 public void writeToXml(PhoneAccountHandle o, XmlSerializer serializer, Context context, 2890 FeatureFlags telephonyFeatureFlags) throws IOException { 2891 if (o != null) { 2892 serializer.startTag(null, CLASS_PHONE_ACCOUNT_HANDLE); 2893 2894 if (o.getComponentName() != null) { 2895 writeTextIfNonNull( 2896 COMPONENT_NAME, o.getComponentName().flattenToString(), serializer); 2897 } 2898 2899 writeTextIfNonNull(ID, o.getId(), serializer); 2900 2901 if (o.getUserHandle() != null && context != null) { 2902 UserManager userManager = context.getSystemService(UserManager.class); 2903 writeLong(USER_SERIAL_NUMBER, 2904 userManager.getSerialNumberForUser(o.getUserHandle()), serializer); 2905 } 2906 2907 serializer.endTag(null, CLASS_PHONE_ACCOUNT_HANDLE); 2908 } 2909 } 2910 2911 @Override 2912 public PhoneAccountHandle readFromXml(XmlPullParser parser, int version, Context context, 2913 FeatureFlags telephonyFeatureFlags, 2914 com.android.server.telecom.flags.FeatureFlags telecomFeatureFlags) 2915 throws IOException, XmlPullParserException { 2916 if (parser.getName().equals(CLASS_PHONE_ACCOUNT_HANDLE)) { 2917 String componentNameString = null; 2918 String idString = null; 2919 String userSerialNumberString = null; 2920 int outerDepth = parser.getDepth(); 2921 2922 UserManager userManager = context.getSystemService(UserManager.class); 2923 2924 while (XmlUtils.nextElementWithin(parser, outerDepth)) { 2925 if (parser.getName().equals(COMPONENT_NAME)) { 2926 parser.next(); 2927 componentNameString = parser.getText(); 2928 } else if (parser.getName().equals(ID)) { 2929 parser.next(); 2930 idString = parser.getText(); 2931 } else if (parser.getName().equals(USER_SERIAL_NUMBER)) { 2932 parser.next(); 2933 userSerialNumberString = parser.getText(); 2934 } 2935 } 2936 if (componentNameString != null) { 2937 UserHandle userHandle = null; 2938 if (userSerialNumberString != null) { 2939 try { 2940 long serialNumber = Long.parseLong(userSerialNumberString); 2941 userHandle = userManager.getUserForSerialNumber(serialNumber); 2942 } catch (NumberFormatException e) { 2943 Log.e(this, e, "Could not parse UserHandle " + userSerialNumberString); 2944 } 2945 } 2946 return new PhoneAccountHandle( 2947 ComponentName.unflattenFromString(componentNameString), 2948 idString, 2949 userHandle); 2950 } 2951 } 2952 return null; 2953 } 2954 }; 2955 2956 /** 2957 * Determines if an app specified by a uid has a phone account for that uid. 2958 * @param uid the uid to check 2959 * @return {@code true} if there is a phone account for that UID, {@code false} otherwise. 2960 */ 2961 public boolean hasPhoneAccountForUid(int uid) { 2962 String[] packageNames = mContext.getPackageManager().getPackagesForUid(uid); 2963 if (packageNames == null || packageNames.length == 0) { 2964 return false; 2965 } 2966 UserHandle userHandle = UserHandle.getUserHandleForUid(uid); 2967 return mState.accounts.stream() 2968 .anyMatch(p -> { 2969 PhoneAccountHandle handle = p.getAccountHandle(); 2970 return handle.getUserHandle().equals(userHandle) 2971 && Arrays.stream(packageNames).anyMatch( s -> s.equals( 2972 handle.getComponentName().getPackageName())); 2973 }); 2974 } 2975 } 2976