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

Commit 4d425d3b authored by Matías Hernández's avatar Matías Hernández
Browse files

Make "strict zen component validation" less strict

If we detect an invalid CPS or configuration activity in the AutomaticZenRule, we clear it out instead of throwing. (Although we still enforce that at least one of them must be valid).

Bug: 420605963
Test: atest NotificationManagerZenTest
Flag: com.android.server.notification.strict_zen_rule_component_validation
Change-Id: I7bee2c161911d6aa3fda9c24c9c0d7ba580352bc
parent d917e7b4
Loading
Loading
Loading
Loading
+33 −19
Original line number Diff line number Diff line
@@ -6481,7 +6481,7 @@ public class NotificationManagerService extends SystemService {
        @Override
        public String addAutomaticZenRule(AutomaticZenRule automaticZenRule, String pkg,
                boolean fromUser) {
            validateAutomaticZenRule(/* updateId= */ null, automaticZenRule);
            automaticZenRule = validateAutomaticZenRule(/* updateId= */ null, automaticZenRule);
            checkCallerIsSameApp(pkg);
            if (automaticZenRule.getZenPolicy() != null
                    && automaticZenRule.getInterruptionFilter() != INTERRUPTION_FILTER_PRIORITY) {
@@ -6518,7 +6518,7 @@ public class NotificationManagerService extends SystemService {
        @Override
        public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule,
                boolean fromUser) throws RemoteException {
            validateAutomaticZenRule(id, automaticZenRule);
            automaticZenRule = validateAutomaticZenRule(id, automaticZenRule);
            enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
            enforceUserOriginOnlyFromSystem(fromUser, "updateAutomaticZenRule");
            UserHandle zenUser = getCallingZenUser();
@@ -6527,9 +6527,16 @@ public class NotificationManagerService extends SystemService {
                    computeZenOrigin(fromUser), "updateAutomaticZenRule", Binder.getCallingUid());
        }
        private void validateAutomaticZenRule(@Nullable String updateId, AutomaticZenRule rule) {
        /**
         * Validate and potentially "fix" a rule supplied to {@link #addAutomaticZenRule} or
         * {@link #updateAutomaticZenRule}.
         */
        @NonNull
        private AutomaticZenRule validateAutomaticZenRule(@Nullable String updateId,
                AutomaticZenRule rule) {
            Objects.requireNonNull(rule, "automaticZenRule is null");
            Objects.requireNonNull(rule.getName(), "Name is null");
            Objects.requireNonNull(rule.getConditionId(), "ConditionId is null");
            rule.validate();
            // Implicit rules have no ConditionProvider or Activity. We allow the user to customize
@@ -6545,37 +6552,42 @@ public class NotificationManagerService extends SystemService {
                        "Rule must have a ConditionProviderService and/or configuration "
                                + "activity");
            }
            Objects.requireNonNull(rule.getConditionId(), "ConditionId is null");
            // If supplied, both CPS and ConfigurationActivity must be accessible to the calling
            // package. Skip check when the caller is the system: for additions we trust ourselves,
            // and for updates we don't want to block updating a rule in Settings even if the owner
            // package has changed its manifest so that some component is gone.
            // package. Clear them out if invalid -- but at least one must remain.
            if (Flags.strictZenRuleComponentValidation() && !isCallerSystemOrSystemUi()) {
                if (rule.getOwner() != null) {
                    PackageItemInfo ownerInfo = mZenModeHelper.getServiceInfo(rule.getOwner());
                ComponentName ruleOwner = rule.getOwner();
                if (ruleOwner != null) {
                    PackageItemInfo ownerInfo = mZenModeHelper.getServiceInfo(ruleOwner);
                    if (ownerInfo == null) {
                        throw new IllegalArgumentException(
                                "Lacking enabled ConditionProviderService " + rule.getOwner());
                        Slog.e(TAG, "AZR.owner " + ruleOwner
                                + " is not valid. This might throw in a future release.");
                        rule = new AutomaticZenRule.Builder(rule).setOwner(null).build();
                    }
                }
                if (rule.getConfigurationActivity() != null) {
                    PackageItemInfo activityInfo = mZenModeHelper.getActivityInfo(
                            rule.getConfigurationActivity());
                ComponentName ruleActivity = rule.getConfigurationActivity();
                if (ruleActivity != null) {
                    PackageItemInfo activityInfo = mZenModeHelper.getActivityInfo(ruleActivity);
                    if (activityInfo == null) {
                        throw new IllegalArgumentException(
                                "Lacking enabled ConfigurationActivity "
                                        + rule.getConfigurationActivity());
                        Slog.e(TAG, "AZR.configurationActivity " + ruleActivity
                                + " is not valid. This might throw in a future release.");
                        rule = new AutomaticZenRule.Builder(rule)
                                .setConfigurationActivity(null)
                                .build();
                    }
                }
                if (rule.getOwner() == null && rule.getConfigurationActivity() == null) {
                    throw new IllegalArgumentException(
                            "Rule must have a valid (enabled) ConditionProviderService or "
                                    + "configurationActivity");
                }
            }
            if (isCallerSystemOrSystemUi()) {
                return; // System callers can use any type.
                return rule; // System callers can use any type.
            }
            int uid = Binder.getCallingUid();
            int userId = UserHandle.getUserId(uid);
            if (rule.getType() == AutomaticZenRule.TYPE_MANAGED) {
                boolean isDeviceOwner = Binder.withCleanCallingIdentity(
                        () -> mDpm.isActiveDeviceOwner(uid));
@@ -6594,6 +6606,8 @@ public class NotificationManagerService extends SystemService {
                                    + "TYPE_BEDTIME");
                }
            }
            return rule;
        }
        @Override
+86 −8
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@ import static android.app.NotificationSystemUtil.toggleNotificationPolicyAccess;
import static android.service.notification.Condition.STATE_FALSE;
import static android.service.notification.Condition.STATE_TRUE;

import static com.android.server.notification.Flags.FLAG_STRICT_ZEN_RULE_COMPONENT_VALIDATION;

import static com.google.common.truth.Truth.assertThat;

import static org.junit.Assert.assertThrows;
@@ -101,6 +103,8 @@ public class NotificationManagerZenTest {

        AutomaticZenRule savedAzr = mNotificationManager.getAutomaticZenRule(ruleId);
        assertThat(savedAzr).isNotNull();
        assertThat(savedAzr.getOwner()).isEqualTo(CONDITION_PROVIDER_SERVICE);
        assertThat(savedAzr.getConfigurationActivity()).isEqualTo(CONFIGURATION_ACTIVITY);
        assertThat(savedAzr.getPackageName()).isEqualTo(mContext.getPackageName());
    }

@@ -115,6 +119,7 @@ public class NotificationManagerZenTest {

        AutomaticZenRule savedAzr = mNotificationManager.getAutomaticZenRule(ruleId);
        assertThat(savedAzr).isNotNull();
        assertThat(savedAzr.getOwner()).isEqualTo(CONDITION_PROVIDER_SERVICE);
        assertThat(savedAzr.getPackageName()).isEqualTo(mContext.getPackageName());
    }

@@ -129,6 +134,7 @@ public class NotificationManagerZenTest {

        AutomaticZenRule savedAzr = mNotificationManager.getAutomaticZenRule(ruleId);
        assertThat(savedAzr).isNotNull();
        assertThat(savedAzr.getConfigurationActivity()).isEqualTo(CONFIGURATION_ACTIVITY);
        assertThat(savedAzr.getPackageName()).isEqualTo(mContext.getPackageName());
    }

@@ -144,7 +150,7 @@ public class NotificationManagerZenTest {
    }

    @Test
    public void addAutomaticZenRule_invalidCps_rejected() {
    public void addAutomaticZenRule_invalidCpsAndNoConfigActivity_rejected() {
        AutomaticZenRule azr = new AutomaticZenRule.Builder("Invalid CPS", CONDITION_ID)
                .setOwner(new ComponentName(mContext, "android.app.NonExistentCps"))
                .build();
@@ -154,7 +160,24 @@ public class NotificationManagerZenTest {
    }

    @Test
    public void addAutomaticZenRule_invalidConfigActivity_rejected() {
    @RequiresFlagsEnabled(FLAG_STRICT_ZEN_RULE_COMPONENT_VALIDATION)
    public void addAutomaticZenRule_invalidCpsButValidConfigActivity_cpsRemoved() {
        AutomaticZenRule azr = new AutomaticZenRule.Builder("Invalid CPS", CONDITION_ID)
                .setOwner(new ComponentName(mContext, "android.app.NonExistentCps"))
                .setConfigurationActivity(CONFIGURATION_ACTIVITY)
                .build();

        String ruleId = mNotificationManager.addAutomaticZenRule(azr);

        AutomaticZenRule savedAzr = mNotificationManager.getAutomaticZenRule(ruleId);
        assertThat(savedAzr).isNotNull();
        assertThat(savedAzr.getOwner()).isNull();
        assertThat(savedAzr.getConfigurationActivity()).isEqualTo(CONFIGURATION_ACTIVITY);
        assertThat(savedAzr.getPackageName()).isEqualTo(mContext.getPackageName());
    }

    @Test
    public void addAutomaticZenRule_invalidConfigActivityAndNoCps_rejected() {
        AutomaticZenRule azr = new AutomaticZenRule.Builder("Invalid CPS", CONDITION_ID)
                .setConfigurationActivity(
                        new ComponentName(mContext, "android.app.NonExistentActivity"))
@@ -164,6 +187,24 @@ public class NotificationManagerZenTest {
                () -> mNotificationManager.addAutomaticZenRule(azr));
    }

    @Test
    @RequiresFlagsEnabled(FLAG_STRICT_ZEN_RULE_COMPONENT_VALIDATION)
    public void addAutomaticZenRule_invalidConfigActivityButValidCps_configActivityRemoved() {
        AutomaticZenRule azr = new AutomaticZenRule.Builder("Invalid CPS", CONDITION_ID)
                .setOwner(CONDITION_PROVIDER_SERVICE)
                .setConfigurationActivity(
                        new ComponentName(mContext, "android.app.NonExistentActivity"))
                .build();

        String ruleId = mNotificationManager.addAutomaticZenRule(azr);

        AutomaticZenRule savedAzr = mNotificationManager.getAutomaticZenRule(ruleId);
        assertThat(savedAzr).isNotNull();
        assertThat(savedAzr.getOwner()).isEqualTo(CONDITION_PROVIDER_SERVICE);
        assertThat(savedAzr.getConfigurationActivity()).isNull();
        assertThat(savedAzr.getPackageName()).isEqualTo(mContext.getPackageName());
    }

    @Test
    public void addAutomaticZenRule_cpsInDifferentPackage_rejected() {
        AutomaticZenRule azr = new AutomaticZenRule.Builder("System CPS !!", CONDITION_ID)
@@ -186,12 +227,10 @@ public class NotificationManagerZenTest {
    }

    @Test
    @RequiresFlagsEnabled(
            com.android.server.notification.Flags.FLAG_STRICT_ZEN_RULE_COMPONENT_VALIDATION)
    @RequiresFlagsEnabled(FLAG_STRICT_ZEN_RULE_COMPONENT_VALIDATION)
    public void updateAutomaticZenRule_switchToInvalidCps_rejected() {
        AutomaticZenRule original = new AutomaticZenRule.Builder("OK so far", CONDITION_ID)
                .setOwner(CONDITION_PROVIDER_SERVICE)
                .setConfigurationActivity(CONFIGURATION_ACTIVITY)
                .build();

        String ruleId = mNotificationManager.addAutomaticZenRule(original);
@@ -205,13 +244,31 @@ public class NotificationManagerZenTest {
    }

    @Test
    @RequiresFlagsEnabled(
            com.android.server.notification.Flags.FLAG_STRICT_ZEN_RULE_COMPONENT_VALIDATION)
    public void updateAutomaticZenRule_switchToInvalidConfigActivity_rejected() {
    @RequiresFlagsEnabled(FLAG_STRICT_ZEN_RULE_COMPONENT_VALIDATION)
    public void updateAutomaticZenRule_switchToInvalidCpsButWithValidConfigActivity_cpsGone() {
        AutomaticZenRule original = new AutomaticZenRule.Builder("OK so far", CONDITION_ID)
                .setOwner(CONDITION_PROVIDER_SERVICE)
                .setConfigurationActivity(CONFIGURATION_ACTIVITY)
                .build();
        String ruleId = mNotificationManager.addAutomaticZenRule(original);

        AutomaticZenRule sneaky = new AutomaticZenRule.Builder(original)
                .setOwner(ZenModeConfig.getScheduleConditionProvider())
                .build();
        mNotificationManager.updateAutomaticZenRule(ruleId, sneaky);

        AutomaticZenRule savedAzr = mNotificationManager.getAutomaticZenRule(ruleId);
        assertThat(savedAzr).isNotNull();
        assertThat(savedAzr.getOwner()).isNull();
        assertThat(savedAzr.getConfigurationActivity()).isEqualTo(CONFIGURATION_ACTIVITY);
    }

    @Test
    @RequiresFlagsEnabled(FLAG_STRICT_ZEN_RULE_COMPONENT_VALIDATION)
    public void updateAutomaticZenRule_switchToInvalidConfigActivity_rejected() {
        AutomaticZenRule original = new AutomaticZenRule.Builder("OK so far", CONDITION_ID)
                .setConfigurationActivity(CONFIGURATION_ACTIVITY)
                .build();

        String ruleId = mNotificationManager.addAutomaticZenRule(original);

@@ -224,6 +281,27 @@ public class NotificationManagerZenTest {
                () -> mNotificationManager.updateAutomaticZenRule(ruleId, sneaky));
    }

    @Test
    @RequiresFlagsEnabled(FLAG_STRICT_ZEN_RULE_COMPONENT_VALIDATION)
    public void updateAutomaticZenRule_switchToInvalidConfigActivityButWithValidCps_activityGone() {
        AutomaticZenRule original = new AutomaticZenRule.Builder("OK so far", CONDITION_ID)
                .setOwner(CONDITION_PROVIDER_SERVICE)
                .setConfigurationActivity(CONFIGURATION_ACTIVITY)
                .build();
        String ruleId = mNotificationManager.addAutomaticZenRule(original);

        AutomaticZenRule sneaky = new AutomaticZenRule.Builder(original)
                .setConfigurationActivity(
                        new ComponentName("com.android.settings", "Settings$ModesSettingsActivity"))
                .build();
        mNotificationManager.updateAutomaticZenRule(ruleId, sneaky);

        AutomaticZenRule savedAzr = mNotificationManager.getAutomaticZenRule(ruleId);
        assertThat(savedAzr).isNotNull();
        assertThat(savedAzr.getConfigurationActivity()).isNull();
        assertThat(savedAzr.getOwner()).isEqualTo(CONDITION_PROVIDER_SERVICE);
    }

    @Test
    public void addAutomaticZenRule_fromPackage_forcesOwnerPackage() {
        AutomaticZenRule azr = new AutomaticZenRule.Builder("Set wrong package", CONDITION_ID)