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