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