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