Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 01083f3a authored by Thomas Stuart's avatar Thomas Stuart
Browse files

enforcePhoneAccounts should unregister unresolvable accts

Accounts that cannot be resolved anymore should be unregistered to avoid
keeping the unusable account in memory.

Fixes: 281061708
Test: 1 new unit test + manual:
	(1) flash apk that registers accts on diff CS's
        (2) register MAX accts and disable CS
        (3) app should repeat step 2 mutliple times
        expect: accts unregistered after disabling CS and
                registering another acct

Change-Id: Iddd205d4e9c4013fdd6baaeb78e7b299410d2327
parent f3be9529
Loading
Loading
Loading
Loading
+54 −7
Original line number Diff line number Diff line
@@ -900,13 +900,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(
@@ -1552,6 +1554,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.
+14 −0
Original line number Diff line number Diff line
@@ -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,
@@ -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())) {
+34 −0
Original line number Diff line number Diff line
@@ -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 {