Loading src/com/android/server/telecom/PhoneAccountRegistrar.java +54 −7 Original line number Diff line number Diff line Loading @@ -897,13 +897,15 @@ public class PhoneAccountRegistrar { * @throws IllegalArgumentException if MAX_PHONE_ACCOUNT_REGISTRATIONS are reached */ private void enforceMaxPhoneAccountLimit(@NonNull PhoneAccount account) { final PhoneAccountHandle accountHandle = account.getAccountHandle(); final UserHandle user = accountHandle.getUserHandle(); final ComponentName componentName = accountHandle.getComponentName(); if (getPhoneAccountHandles(0, null, componentName.getPackageName(), true /* includeDisabled */, user, false /* crossUserAccess */).size() >= MAX_PHONE_ACCOUNT_REGISTRATIONS) { List<PhoneAccount> unverifiedAccounts = getAccountsForPackage_BypassResolveComp( account.getAccountHandle().getComponentName().getPackageName(), account.getAccountHandle().getUserHandle()); // verify each phone account is backed by a valid ConnectionService. If the // ConnectionService has been disabled or cannot be resolved, unregister the accounts. List<PhoneAccount> verifiedAccounts = cleanupUnresolvableConnectionServiceAccounts(unverifiedAccounts); // enforce the max phone account limit for the application registering accounts if (verifiedAccounts.size() >= MAX_PHONE_ACCOUNT_REGISTRATIONS) { EventLog.writeEvent(0x534e4554, "259064622", Binder.getCallingUid(), "enforceMaxPhoneAccountLimit"); throw new IllegalArgumentException( Loading Loading @@ -1549,6 +1551,51 @@ public class PhoneAccountRegistrar { return accounts; } /** * This getter should be used when you want to bypass the {@link * PhoneAccountRegistrar#resolveComponent(PhoneAccountHandle)} check when fetching accounts */ @VisibleForTesting public List<PhoneAccount> getAccountsForPackage_BypassResolveComp(String packageName, UserHandle userHandle) { List<PhoneAccount> accounts = new ArrayList<>(mState.accounts.size()); for (PhoneAccount m : mState.accounts) { PhoneAccountHandle handle = m.getAccountHandle(); if (packageName != null && !packageName.equals( handle.getComponentName().getPackageName())) { // Not the right package name; skip this one. continue; } if (!isVisibleForUser(m, userHandle, false)) { // Account is not visible for the current user; skip this one. continue; } accounts.add(m); } return accounts; } @VisibleForTesting public List<PhoneAccount> cleanupUnresolvableConnectionServiceAccounts( List<PhoneAccount> accounts) { ArrayList<PhoneAccount> verifiedAccounts = new ArrayList<>(); for (PhoneAccount account : accounts) { PhoneAccountHandle handle = account.getAccountHandle(); // if the ConnectionService has been disabled or can longer be found, remove the handle if (resolveComponent(handle).isEmpty()) { Log.i(this, "Cannot resolve the ConnectionService for handle=[%s]; unregistering" + " account", handle); unregisterPhoneAccount(handle); } else { verifiedAccounts.add(account); } } return verifiedAccounts; } /** * Clean up the orphan {@code PhoneAccount}. An orphan {@code PhoneAccount} is a phone * account that does not have a {@code UserHandle} or belongs to a deleted package. Loading tests/src/com/android/server/telecom/tests/ComponentContextFixture.java +14 −0 Original line number Diff line number Diff line Loading @@ -735,6 +735,14 @@ public class ComponentContextFixture implements TestFixture<Context> { mServiceInfoByComponentName.put(componentName, serviceInfo); } public void removeConnectionService( ComponentName componentName, IConnectionService service) throws Exception { removeService(ConnectionService.SERVICE_INTERFACE, componentName, service); mServiceInfoByComponentName.remove(componentName); } public void addInCallService( ComponentName componentName, IInCallService service, Loading Loading @@ -828,6 +836,12 @@ public class ComponentContextFixture implements TestFixture<Context> { mComponentNameByService.put(service, name); } private void removeService(String action, ComponentName name, IInterface service) { mComponentNamesByAction.remove(action, name); mServiceByComponentName.remove(name); mComponentNameByService.remove(service); } private List<ResolveInfo> doQueryIntentServices(Intent intent, int flags) { List<ResolveInfo> result = new ArrayList<>(); for (ComponentName componentName : mComponentNamesByAction.get(intent.getAction())) { Loading tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java +34 −0 Original line number Diff line number Diff line Loading @@ -353,6 +353,40 @@ public class PhoneAccountRegistrarTest extends TelecomTestCase { PhoneAccount.SCHEME_TEL)); } /** * Verify when a {@link android.telecom.ConnectionService} is disabled or cannot be resolved, * all phone accounts are unregistered when calling * {@link PhoneAccountRegistrar#getAccountsForPackage_BypassResolveComp(String, UserHandle)}. */ @Test public void testCannotResolveServiceUnregistersAccounts() throws Exception { ComponentName componentName = makeQuickConnectionServiceComponentName(); PhoneAccount account = makeQuickAccountBuilder("0", 0, USER_HANDLE_10) .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER | PhoneAccount.CAPABILITY_CALL_PROVIDER).build(); // add the ConnectionService and register a single phone account for it mComponentContextFixture.addConnectionService(componentName, Mockito.mock(IConnectionService.class)); registerAndEnableAccount(account); // verify the start state assertEquals(1, mRegistrar.getAccountsForPackage_BypassResolveComp(componentName.getPackageName(), USER_HANDLE_10).size()); // remove the ConnectionService so that the account cannot be resolved anymore mComponentContextFixture.removeConnectionService(componentName, Mockito.mock(IConnectionService.class)); // verify the account is unregistered when fetching the phone accounts for the package assertEquals(1, mRegistrar.getAccountsForPackage_BypassResolveComp(componentName.getPackageName(), USER_HANDLE_10).size()); assertEquals(0,mRegistrar.cleanupUnresolvableConnectionServiceAccounts( mRegistrar.getAccountsForPackage_BypassResolveComp(componentName.getPackageName(), USER_HANDLE_10)).size()); assertEquals(0, mRegistrar.getAccountsForPackage_BypassResolveComp(componentName.getPackageName(), USER_HANDLE_10).size()); } @MediumTest @Test public void testSimCallManager() throws Exception { Loading Loading
src/com/android/server/telecom/PhoneAccountRegistrar.java +54 −7 Original line number Diff line number Diff line Loading @@ -897,13 +897,15 @@ public class PhoneAccountRegistrar { * @throws IllegalArgumentException if MAX_PHONE_ACCOUNT_REGISTRATIONS are reached */ private void enforceMaxPhoneAccountLimit(@NonNull PhoneAccount account) { final PhoneAccountHandle accountHandle = account.getAccountHandle(); final UserHandle user = accountHandle.getUserHandle(); final ComponentName componentName = accountHandle.getComponentName(); if (getPhoneAccountHandles(0, null, componentName.getPackageName(), true /* includeDisabled */, user, false /* crossUserAccess */).size() >= MAX_PHONE_ACCOUNT_REGISTRATIONS) { List<PhoneAccount> unverifiedAccounts = getAccountsForPackage_BypassResolveComp( account.getAccountHandle().getComponentName().getPackageName(), account.getAccountHandle().getUserHandle()); // verify each phone account is backed by a valid ConnectionService. If the // ConnectionService has been disabled or cannot be resolved, unregister the accounts. List<PhoneAccount> verifiedAccounts = cleanupUnresolvableConnectionServiceAccounts(unverifiedAccounts); // enforce the max phone account limit for the application registering accounts if (verifiedAccounts.size() >= MAX_PHONE_ACCOUNT_REGISTRATIONS) { EventLog.writeEvent(0x534e4554, "259064622", Binder.getCallingUid(), "enforceMaxPhoneAccountLimit"); throw new IllegalArgumentException( Loading Loading @@ -1549,6 +1551,51 @@ public class PhoneAccountRegistrar { return accounts; } /** * This getter should be used when you want to bypass the {@link * PhoneAccountRegistrar#resolveComponent(PhoneAccountHandle)} check when fetching accounts */ @VisibleForTesting public List<PhoneAccount> getAccountsForPackage_BypassResolveComp(String packageName, UserHandle userHandle) { List<PhoneAccount> accounts = new ArrayList<>(mState.accounts.size()); for (PhoneAccount m : mState.accounts) { PhoneAccountHandle handle = m.getAccountHandle(); if (packageName != null && !packageName.equals( handle.getComponentName().getPackageName())) { // Not the right package name; skip this one. continue; } if (!isVisibleForUser(m, userHandle, false)) { // Account is not visible for the current user; skip this one. continue; } accounts.add(m); } return accounts; } @VisibleForTesting public List<PhoneAccount> cleanupUnresolvableConnectionServiceAccounts( List<PhoneAccount> accounts) { ArrayList<PhoneAccount> verifiedAccounts = new ArrayList<>(); for (PhoneAccount account : accounts) { PhoneAccountHandle handle = account.getAccountHandle(); // if the ConnectionService has been disabled or can longer be found, remove the handle if (resolveComponent(handle).isEmpty()) { Log.i(this, "Cannot resolve the ConnectionService for handle=[%s]; unregistering" + " account", handle); unregisterPhoneAccount(handle); } else { verifiedAccounts.add(account); } } return verifiedAccounts; } /** * Clean up the orphan {@code PhoneAccount}. An orphan {@code PhoneAccount} is a phone * account that does not have a {@code UserHandle} or belongs to a deleted package. Loading
tests/src/com/android/server/telecom/tests/ComponentContextFixture.java +14 −0 Original line number Diff line number Diff line Loading @@ -735,6 +735,14 @@ public class ComponentContextFixture implements TestFixture<Context> { mServiceInfoByComponentName.put(componentName, serviceInfo); } public void removeConnectionService( ComponentName componentName, IConnectionService service) throws Exception { removeService(ConnectionService.SERVICE_INTERFACE, componentName, service); mServiceInfoByComponentName.remove(componentName); } public void addInCallService( ComponentName componentName, IInCallService service, Loading Loading @@ -828,6 +836,12 @@ public class ComponentContextFixture implements TestFixture<Context> { mComponentNameByService.put(service, name); } private void removeService(String action, ComponentName name, IInterface service) { mComponentNamesByAction.remove(action, name); mServiceByComponentName.remove(name); mComponentNameByService.remove(service); } private List<ResolveInfo> doQueryIntentServices(Intent intent, int flags) { List<ResolveInfo> result = new ArrayList<>(); for (ComponentName componentName : mComponentNamesByAction.get(intent.getAction())) { Loading
tests/src/com/android/server/telecom/tests/PhoneAccountRegistrarTest.java +34 −0 Original line number Diff line number Diff line Loading @@ -353,6 +353,40 @@ public class PhoneAccountRegistrarTest extends TelecomTestCase { PhoneAccount.SCHEME_TEL)); } /** * Verify when a {@link android.telecom.ConnectionService} is disabled or cannot be resolved, * all phone accounts are unregistered when calling * {@link PhoneAccountRegistrar#getAccountsForPackage_BypassResolveComp(String, UserHandle)}. */ @Test public void testCannotResolveServiceUnregistersAccounts() throws Exception { ComponentName componentName = makeQuickConnectionServiceComponentName(); PhoneAccount account = makeQuickAccountBuilder("0", 0, USER_HANDLE_10) .setCapabilities(PhoneAccount.CAPABILITY_CONNECTION_MANAGER | PhoneAccount.CAPABILITY_CALL_PROVIDER).build(); // add the ConnectionService and register a single phone account for it mComponentContextFixture.addConnectionService(componentName, Mockito.mock(IConnectionService.class)); registerAndEnableAccount(account); // verify the start state assertEquals(1, mRegistrar.getAccountsForPackage_BypassResolveComp(componentName.getPackageName(), USER_HANDLE_10).size()); // remove the ConnectionService so that the account cannot be resolved anymore mComponentContextFixture.removeConnectionService(componentName, Mockito.mock(IConnectionService.class)); // verify the account is unregistered when fetching the phone accounts for the package assertEquals(1, mRegistrar.getAccountsForPackage_BypassResolveComp(componentName.getPackageName(), USER_HANDLE_10).size()); assertEquals(0,mRegistrar.cleanupUnresolvableConnectionServiceAccounts( mRegistrar.getAccountsForPackage_BypassResolveComp(componentName.getPackageName(), USER_HANDLE_10)).size()); assertEquals(0, mRegistrar.getAccountsForPackage_BypassResolveComp(componentName.getPackageName(), USER_HANDLE_10).size()); } @MediumTest @Test public void testSimCallManager() throws Exception { Loading