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

Commit 297d201f authored by Thomas Stuart's avatar Thomas Stuart Committed by Android (Google) Code Review
Browse files

Merge "enforce a character limit in PhoneAccountRegistrar for PAs"

parents 9710b9f8 32b28cbd
Loading
Loading
Loading
Loading
+55 −0
Original line number Diff line number Diff line
@@ -154,6 +154,8 @@ public class PhoneAccountRegistrar {
    @VisibleForTesting
    public static final int EXPECTED_STATE_VERSION = 9;
    public static final int MAX_PHONE_ACCOUNT_REGISTRATIONS = 10;
    public static final int MAX_PHONE_ACCOUNT_EXTAS_KEY_PAIR_LIMIT = 100;
    public static final int MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT = 256;

    /** Keep in sync with the same in SipSettings.java */
    private static final String SIP_SHARED_PREFERENCES = "SIP_PREFERENCES";
@@ -874,10 +876,63 @@ public class PhoneAccountRegistrar {
                            + " because the limit, " + MAX_PHONE_ACCOUNT_REGISTRATIONS
                            + ", has been reached");
        }
        // Enforce a character limit on all PA and PAH string or char-sequence fields.
        enforceCharacterLimit(account);

        addOrReplacePhoneAccount(account);
    }

    /**
     * All {@link PhoneAccount} and{@link PhoneAccountHandle} String and Char-Sequence fields
     * should be restricted to character limit of MAX_PHONE_ACCOUNT_CHAR_LIMIT to prevent exceptions
     * when writing large character streams to XML-Serializer.
     *
     * @param account to enforce character limit checks on
     */
    public void enforceCharacterLimit(PhoneAccount account) {
        if (account == null) {
            return;
        }
        PhoneAccountHandle handle = account.getAccountHandle();

        String[] fields =
                {"Package Name", "Class Name", "PhoneAccountHandle Id", "Label", "ShortDescription",
                        "GroupId"};
        CharSequence[] args = {handle.getComponentName().getPackageName(),
                handle.getComponentName().getClassName(), handle.getId(), account.getLabel(),
                account.getShortDescription(), account.getGroupId()};

        for (int i = 0; i < fields.length; i++) {
            if (args[i] != null && args[i].length() > MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT) {
                throw new IllegalArgumentException("The PhoneAccount or PhoneAccountHandle"
                        + fields[i] + " field has an invalid character count. PhoneAccount and "
                        + "PhoneAccountHandle String and Char-Sequence fields are limited to "
                        + MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT + " characters.");
            }
        }

        Bundle extras = account.getExtras();
        if (extras != null) {
            if (extras.keySet().size() > MAX_PHONE_ACCOUNT_EXTAS_KEY_PAIR_LIMIT) {
                throw new IllegalArgumentException("The PhoneAccount#mExtras is limited to " +
                        MAX_PHONE_ACCOUNT_EXTAS_KEY_PAIR_LIMIT + " (key,value) pairs.");
            }

            for (String key : extras.keySet()) {
                Object value = extras.get(key);

                if ((key != null && key.length() > MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT) ||
                        (value instanceof String &&
                                ((String) value).length() > MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT)) {
                    throw new IllegalArgumentException("The PhoneAccount#mExtras contains a String"
                            + " key or value that has an invalid character count. PhoneAccount and "
                            + "PhoneAccountHandle String and Char-Sequence fields are limited to "
                            + MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT + " characters.");
                }
            }
        }
    }

    /**
     * Adds a {@code PhoneAccount}, replacing an existing one if found.
     *
+252 −0
Original line number Diff line number Diff line
@@ -89,13 +89,18 @@ import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

@RunWith(JUnit4.class)
public class PhoneAccountRegistrarTest extends TelecomTestCase {

    private static final int MAX_VERSION = Integer.MAX_VALUE;
    private static final int INVALID_CHAR_LIMIT_COUNT =
            PhoneAccountRegistrar.MAX_PHONE_ACCOUNT_FIELD_CHAR_LIMIT + 1;
    private static final String INVALID_STR = "a".repeat(INVALID_CHAR_LIMIT_COUNT);
    private static final String FILE_NAME = "phone-account-registrar-test-1223.xml";
    private static final String TEST_LABEL = "right";
    private static final String TEST_ID = "123";
    private final String PACKAGE_1 = "PACKAGE_1";
    private final String PACKAGE_2 = "PACKAGE_2";
    private final String COMPONENT_NAME = "com.android.server.telecom.tests.MockConnectionService";
@@ -1334,6 +1339,253 @@ public class PhoneAccountRegistrarTest extends TelecomTestCase {
                defaultPhoneAccountHandle.phoneAccountHandle.getId());
    }

    /**
     * Test that an {@link IllegalArgumentException} is thrown when a package registers a
     * {@link PhoneAccountHandle} with a { PhoneAccountHandle#packageName} that is over the
     * character limit set
     */
    @Test
    public void testInvalidPhoneAccountHandlePackageNameThrowsException() {
        // GIVEN
        String invalidPackageName = INVALID_STR;
        PhoneAccountHandle handle = makeQuickAccountHandle(
                new ComponentName(invalidPackageName, this.getClass().getName()), TEST_ID);
        PhoneAccount.Builder builder = makeBuilderWithBindCapabilities(handle);

        // THEN
        try {
            PhoneAccount account = builder.build();
            assertEquals(invalidPackageName,
                    account.getAccountHandle().getComponentName().getPackageName());
            mRegistrar.registerPhoneAccount(account);
            fail("failed to throw IllegalArgumentException");
        } catch (IllegalArgumentException e) {
            // pass test
        } finally {
            mRegistrar.unregisterPhoneAccount(handle);
        }
    }

    /**
     * Test that an {@link IllegalArgumentException} is thrown when a package registers a
     * {@link PhoneAccountHandle} with a { PhoneAccountHandle#className} that is over the
     * character limit set
     */
    @Test
    public void testInvalidPhoneAccountHandleClassNameThrowsException() {
        // GIVEN
        String invalidClassName = INVALID_STR;
        PhoneAccountHandle handle = makeQuickAccountHandle(
                new ComponentName(this.getClass().getPackageName(), invalidClassName), TEST_ID);
        PhoneAccount.Builder builder = makeBuilderWithBindCapabilities(handle);

        // THEN
        try {
            PhoneAccount account = builder.build();
            assertEquals(invalidClassName,
                    account.getAccountHandle().getComponentName().getClassName());
            mRegistrar.registerPhoneAccount(account);
            fail("failed to throw IllegalArgumentException");
        } catch (IllegalArgumentException e) {
            // pass test
        } finally {
            mRegistrar.unregisterPhoneAccount(handle);
        }
    }

    /**
     * Test that an {@link IllegalArgumentException} is thrown when a package registers a
     * {@link PhoneAccountHandle} with a { PhoneAccount#mId} that is over the character limit set
     */
    @Test
    public void testInvalidPhoneAccountHandleIdThrowsException() {
        // GIVEN
        String invalidId = INVALID_STR;
        PhoneAccountHandle handle = makeQuickAccountHandle(invalidId);
        PhoneAccount.Builder builder = makeBuilderWithBindCapabilities(handle);

        // THEN
        try {
            PhoneAccount account = builder.build();
            assertEquals(invalidId, account.getAccountHandle().getId());
            mRegistrar.registerPhoneAccount(account);
            fail("failed to throw IllegalArgumentException");
        } catch (IllegalArgumentException e) {
            // pass test
        } finally {
            mRegistrar.unregisterPhoneAccount(handle);
        }
    }

    /**
     * Test that an {@link IllegalArgumentException} is thrown when a package registers a
     * {@link PhoneAccount} with a { PhoneAccount#mLabel} that is over the character limit set
     */
    @Test
    public void testInvalidLabelThrowsException() {
        // GIVEN
        String invalidLabel = INVALID_STR;
        PhoneAccountHandle handle = makeQuickAccountHandle(TEST_ID);
        PhoneAccount.Builder builder = new PhoneAccount.Builder(handle, invalidLabel)
                .setCapabilities(PhoneAccount.CAPABILITY_SUPPORTS_TRANSACTIONAL_OPERATIONS);

        // WHEN
        when(mAppLabelProxy.getAppLabel(anyString())).thenReturn(invalidLabel);

        // THEN
        try {
            PhoneAccount account = builder.build();
            assertEquals(invalidLabel, account.getLabel());
            mRegistrar.registerPhoneAccount(account);
            fail("failed to throw IllegalArgumentException");
        } catch (IllegalArgumentException e) {
            // pass test
        } finally {
            mRegistrar.unregisterPhoneAccount(handle);
        }
    }

    /**
     * Test that an {@link IllegalArgumentException} is thrown when a package registers a
     * {@link PhoneAccount} with a {PhoneAccount#mShortDescription} that is over the character
     * limit set
     */
    @Test
    public void testInvalidShortDescriptionThrowsException() {
        // GIVEN
        String invalidShortDescription = INVALID_STR;
        PhoneAccountHandle handle = makeQuickAccountHandle(TEST_ID);
        PhoneAccount.Builder builder = makeBuilderWithBindCapabilities(handle)
                .setShortDescription(invalidShortDescription);

        // THEN
        try {
            PhoneAccount account = builder.build();
            assertEquals(invalidShortDescription, account.getShortDescription());
            mRegistrar.registerPhoneAccount(account);
            fail("failed to throw IllegalArgumentException");
        } catch (IllegalArgumentException e) {
            // pass test
        } finally {
            mRegistrar.unregisterPhoneAccount(handle);
        }
    }

    /**
     * Test that an {@link IllegalArgumentException} is thrown when a package registers a
     * {@link PhoneAccount} with a {PhoneAccount#mGroupId} that is over the character limit set
     */
    @Test
    public void testInvalidGroupIdThrowsException() {
        // GIVEN
        String invalidGroupId = INVALID_STR;
        PhoneAccountHandle handle = makeQuickAccountHandle(TEST_ID);
        PhoneAccount.Builder builder = makeBuilderWithBindCapabilities(handle)
                .setGroupId(invalidGroupId);

        // THEN
        try {
            PhoneAccount account = builder.build();
            assertEquals(invalidGroupId, account.getGroupId());
            mRegistrar.registerPhoneAccount(account);
            fail("failed to throw IllegalArgumentException");
        } catch (IllegalArgumentException e) {
            // pass test
        } finally {
            mRegistrar.unregisterPhoneAccount(handle);
        }
    }

    /**
     * Test that an {@link IllegalArgumentException} is thrown when a package registers a
     * {@link PhoneAccount} with a {PhoneAccount#mExtras} that is over the character limit set
     */
    @Test
    public void testInvalidExtraStringKeyThrowsException() {
        // GIVEN
        String invalidBundleKey = INVALID_STR;
        String keyValue = "value";
        Bundle extras = new Bundle();
        extras.putString(invalidBundleKey, keyValue);
        PhoneAccountHandle handle = makeQuickAccountHandle(TEST_ID);
        PhoneAccount.Builder builder = makeBuilderWithBindCapabilities(handle)
                .setExtras(extras);

        // THEN
        try {
            PhoneAccount account = builder.build();
            assertEquals(keyValue, account.getExtras().getString(invalidBundleKey));
            mRegistrar.registerPhoneAccount(account);
            fail("failed to throw IllegalArgumentException");
        } catch (IllegalArgumentException e) {
            // pass test
        } finally {
            mRegistrar.unregisterPhoneAccount(handle);
        }
    }

    /**
     * Test that an {@link IllegalArgumentException} is thrown when a package registers a
     * {@link PhoneAccount} with a {PhoneAccount#mExtras} that is over the character limit set
     */
    @Test
    public void testInvalidExtraStringValueThrowsException() {
        // GIVEN
        String extrasKey = "ExtrasStringKey";
        String invalidBundleValue = INVALID_STR;
        Bundle extras = new Bundle();
        extras.putString(extrasKey, invalidBundleValue);
        PhoneAccountHandle handle = makeQuickAccountHandle(TEST_ID);
        PhoneAccount.Builder builder = makeBuilderWithBindCapabilities(handle)
                .setExtras(extras);

        // THEN
        try {
            PhoneAccount account = builder.build();
            assertEquals(invalidBundleValue, account.getExtras().getString(extrasKey));
            mRegistrar.registerPhoneAccount(account);
            fail("failed to throw IllegalArgumentException");
        } catch (IllegalArgumentException e) {
            // pass test
        } finally {
            mRegistrar.unregisterPhoneAccount(handle);
        }
    }

    /**
     * Test that an {@link IllegalArgumentException} is thrown when a package registers a
     * {@link PhoneAccount} with a {PhoneAccount#mExtras} that is over the (key,value) pair limit
     */
    @Test
    public void testInvalidExtraElementsExceedsLimitAndThrowsException() {
        // GIVEN
        int invalidBundleExtrasLimit =
                PhoneAccountRegistrar.MAX_PHONE_ACCOUNT_EXTAS_KEY_PAIR_LIMIT + 1;
        Bundle extras = new Bundle();
        for (int i = 0; i < invalidBundleExtrasLimit; i++) {
            extras.putString(UUID.randomUUID().toString(), "value");
        }
        PhoneAccountHandle handle = makeQuickAccountHandle(TEST_ID);
        PhoneAccount.Builder builder = makeBuilderWithBindCapabilities(handle)
                .setExtras(extras);
        // THEN
        try {
            PhoneAccount account = builder.build();
            assertEquals(invalidBundleExtrasLimit, account.getExtras().size());
            mRegistrar.registerPhoneAccount(account);
            fail("failed to throw IllegalArgumentException");
        } catch (IllegalArgumentException e) {
            // Test Pass
        } finally {
            mRegistrar.unregisterPhoneAccount(handle);
        }
    }

    private static PhoneAccount.Builder makeBuilderWithBindCapabilities(PhoneAccountHandle handle){
        return new PhoneAccount.Builder(handle, TEST_LABEL)
                .setCapabilities(PhoneAccount.CAPABILITY_SUPPORTS_TRANSACTIONAL_OPERATIONS);
    }

    private static ComponentName makeQuickConnectionServiceComponentName() {
        return new ComponentName(
                "com.android.server.telecom.tests",