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

Commit 62bf6357 authored by Matías Hernández's avatar Matías Hernández
Browse files

Prevent apps from supplying non-public ZenDeviceEffects

While allowing the system (and also the user, through probably they won't be toggles for these) to set them.

This also replaces fromSystemOrSystemUi by an enum-like in the public interface of ZenModeHelper, so dovetails with b/308671593 & co.

Fixes: 310938105
Test: atest ZenModeHelperTest
Change-Id: Ib8d2efca65748e67195f4b3a6a7f2f2532bea1da
parent b2e1acac
Loading
Loading
Loading
Loading
+7 −4
Original line number Diff line number Diff line
@@ -1765,8 +1765,7 @@ public class NotificationManagerService extends SystemService {
            if (Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) {
                // update system notification channels
                SystemNotificationChannels.createAll(context);
                mZenModeHelper.updateDefaultZenRules(Binder.getCallingUid(),
                        isCallerIsSystemOrSystemUi());
                mZenModeHelper.updateDefaultZenRules(Binder.getCallingUid());
                mPreferencesHelper.onLocaleChanged(context, ActivityManager.getCurrentUser());
            }
        }
@@ -5316,7 +5315,9 @@ public class NotificationManagerService extends SystemService {
            return mZenModeHelper.addAutomaticZenRule(rulePkg, automaticZenRule,
                    "addAutomaticZenRule", Binder.getCallingUid(),
                    isCallerIsSystemOrSystemUi());
                    // TODO: b/308670715: Distinguish FROM_APP from FROM_USER
                    isCallerIsSystemOrSystemUi() ? ZenModeHelper.FROM_SYSTEM_OR_SYSTEMUI
                            : ZenModeHelper.FROM_APP);
        }
        @Override
@@ -5334,7 +5335,9 @@ public class NotificationManagerService extends SystemService {
            return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
                    "updateAutomaticZenRule", Binder.getCallingUid(),
                    isCallerIsSystemOrSystemUi());
                    // TODO: b/308670715: Distinguish FROM_APP from FROM_USER
                    isCallerIsSystemOrSystemUi() ? ZenModeHelper.FROM_SYSTEM_OR_SYSTEMUI
                            : ZenModeHelper.FROM_APP);
        }
        @Override
+80 −10
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import static android.service.notification.NotificationServiceProto.ROOT_CONFIG;

import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;

import android.annotation.IntDef;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.annotation.UserIdInt;
@@ -73,6 +74,7 @@ import android.provider.Settings;
import android.provider.Settings.Global;
import android.service.notification.Condition;
import android.service.notification.ConditionProviderService;
import android.service.notification.ZenDeviceEffects;
import android.service.notification.ZenModeConfig;
import android.service.notification.ZenModeConfig.ZenRule;
import android.service.notification.ZenModeProto;
@@ -105,6 +107,8 @@ import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -129,6 +133,21 @@ public class ZenModeHelper {
    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
    static final long SEND_ACTIVATION_AZR_STATUSES = 308673617L;

    /** A rule addition or update that is initiated by the System or SystemUI. */
    static final int FROM_SYSTEM_OR_SYSTEMUI = 1;
    /** A rule addition or update that is initiated by the user (through system settings). */
    static final int FROM_USER = 2;
    /** A rule addition or update that is initiated by an app (via NotificationManager APIs). */
    static final int FROM_APP = 3;

    @IntDef(prefix = { "FROM_" }, value = {
            FROM_SYSTEM_OR_SYSTEMUI,
            FROM_USER,
            FROM_APP
    })
    @Retention(RetentionPolicy.SOURCE)
    @interface ChangeOrigin {}

    // pkg|userId => uid
    @VisibleForTesting protected final ArrayMap<String, Integer> mRulesUidCache = new ArrayMap<>();

@@ -378,7 +397,7 @@ public class ZenModeHelper {
    }

    public String addAutomaticZenRule(String pkg, AutomaticZenRule automaticZenRule,
            String reason, int callingUid, boolean fromSystemOrSystemUi) {
            String reason, int callingUid, @ChangeOrigin int origin) {
        if (!ZenModeConfig.SYSTEM_AUTHORITY.equals(pkg)) {
            PackageItemInfo component = getServiceInfo(automaticZenRule.getOwner());
            if (component == null) {
@@ -412,10 +431,10 @@ public class ZenModeHelper {
            }
            newConfig = mConfig.copy();
            ZenRule rule = new ZenRule();
            populateZenRule(pkg, automaticZenRule, rule, true);
            populateZenRule(pkg, automaticZenRule, rule, true, origin);
            newConfig.automaticRules.put(rule.id, rule);
            if (setConfigLocked(newConfig, reason, rule.component, true, callingUid,
                    fromSystemOrSystemUi)) {
                    origin == FROM_SYSTEM_OR_SYSTEMUI)) {
                return rule.id;
            } else {
                throw new AndroidRuntimeException("Could not create rule");
@@ -424,7 +443,7 @@ public class ZenModeHelper {
    }

    public boolean updateAutomaticZenRule(String ruleId, AutomaticZenRule automaticZenRule,
            String reason, int callingUid, boolean fromSystemOrSystemUi) {
            String reason, int callingUid, @ChangeOrigin int origin) {
        ZenModeConfig newConfig;
        synchronized (mConfigLock) {
            if (mConfig == null) return false;
@@ -452,9 +471,9 @@ public class ZenModeHelper {
                }
            }

            populateZenRule(rule.pkg, automaticZenRule, rule, false);
            populateZenRule(rule.pkg, automaticZenRule, rule, false, origin);
            return setConfigLocked(newConfig, reason, rule.component, true, callingUid,
                    fromSystemOrSystemUi);
                    origin == FROM_SYSTEM_OR_SYSTEMUI);
        }
    }

@@ -790,7 +809,7 @@ public class ZenModeHelper {
        }
    }

    protected void updateDefaultZenRules(int callingUid, boolean fromSystemOrSystemUi) {
    protected void updateDefaultZenRules(int callingUid) {
        updateDefaultAutomaticRuleNames();
        synchronized (mConfigLock) {
            for (ZenRule defaultRule : mDefaultConfig.automaticRules.values()) {
@@ -807,7 +826,7 @@ public class ZenModeHelper {
                        // update default rule (if locale changed, name of rule will change)
                        currRule.name = defaultRule.name;
                        updateAutomaticZenRule(defaultRule.id, zenRuleToAutomaticZenRule(currRule),
                                "locale changed", callingUid, fromSystemOrSystemUi);
                                "locale changed", callingUid, FROM_SYSTEM_OR_SYSTEMUI);
                    }
                }
            }
@@ -850,7 +869,11 @@ public class ZenModeHelper {
    }

    private static void populateZenRule(String pkg, AutomaticZenRule automaticZenRule, ZenRule rule,
            boolean isNew) {
            boolean isNew, @ChangeOrigin int origin) {
        // TODO: b/308671593,b/311406021 - Handle origins more precisely:
        //  - FROM_USER can override anything and updates bitmask of user-modified fields;
        //  - FROM_SYSTEM_OR_SYSTEMUI can override anything and preserves bitmask;
        //  - FROM_APP can only update if not user-modified.
        if (rule.enabled != automaticZenRule.isEnabled()) {
            rule.snoozing = false;
        }
@@ -861,7 +884,10 @@ public class ZenModeHelper {
        rule.modified = automaticZenRule.isModified();
        rule.zenPolicy = automaticZenRule.getZenPolicy();
        if (Flags.modesApi()) {
            rule.zenDeviceEffects = automaticZenRule.getDeviceEffects();
            rule.zenDeviceEffects = fixZenDeviceEffects(
                    rule.zenDeviceEffects,
                    automaticZenRule.getDeviceEffects(),
                    origin);
        }
        rule.zenMode = NotificationManager.zenModeFromInterruptionFilter(
                automaticZenRule.getInterruptionFilter(), Global.ZEN_MODE_OFF);
@@ -882,6 +908,50 @@ public class ZenModeHelper {
        }
    }

    /** "
     * Fix" {@link ZenDeviceEffects} that are being stored as part of a new or updated ZenRule.
     *
     * <ul>
     *     <li> Apps cannot turn on hidden effects (those tagged as {@code @hide}) since they are
     *     intended for platform-specific rules (e.g. wearables). If it's a new rule, we blank them
     *     out; if it's an update, we preserve the previous values.
     * </ul>
     */
    @Nullable
    private static ZenDeviceEffects fixZenDeviceEffects(@Nullable ZenDeviceEffects oldEffects,
            @Nullable ZenDeviceEffects newEffects, @ChangeOrigin int origin) {
        // TODO: b/308671593,b/311406021 - Handle origins more precisely:
        //  - FROM_USER can override anything and updates bitmask of user-modified fields;
        //  - FROM_SYSTEM_OR_SYSTEMUI can override anything and preserves bitmask;
        //  - FROM_APP can only update if not user-modified.
        if (origin == FROM_SYSTEM_OR_SYSTEMUI || origin == FROM_USER) {
            return newEffects;
        }

        if (newEffects == null) {
            return null;
        }
        if (oldEffects != null) {
            return new ZenDeviceEffects.Builder(newEffects)
                    .setShouldDisableAutoBrightness(oldEffects.shouldDisableAutoBrightness())
                    .setShouldDisableTapToWake(oldEffects.shouldDisableTapToWake())
                    .setShouldDisableTiltToWake(oldEffects.shouldDisableTiltToWake())
                    .setShouldDisableTouch(oldEffects.shouldDisableTouch())
                    .setShouldMinimizeRadioUsage(oldEffects.shouldMinimizeRadioUsage())
                    .setShouldMaximizeDoze(oldEffects.shouldMaximizeDoze())
                    .build();
        } else {
            return new ZenDeviceEffects.Builder(newEffects)
                    .setShouldDisableAutoBrightness(false)
                    .setShouldDisableTapToWake(false)
                    .setShouldDisableTiltToWake(false)
                    .setShouldDisableTouch(false)
                    .setShouldMinimizeRadioUsage(false)
                    .setShouldMaximizeDoze(false)
                    .build();
        }
    }

    private static AutomaticZenRule zenRuleToAutomaticZenRule(ZenRule rule) {
        AutomaticZenRule azr;
        if (Flags.modesApi()) {
+4 −5
Original line number Diff line number Diff line
@@ -241,7 +241,6 @@ import androidx.test.InstrumentationRegistry;
import com.android.internal.R;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.Flag;
import com.android.internal.config.sysui.TestableFlagResolver;
import com.android.internal.logging.InstanceIdSequence;
import com.android.internal.logging.InstanceIdSequenceFake;
@@ -5296,7 +5295,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
                new Intent(Intent.ACTION_LOCALE_CHANGED));
        verify(mZenModeHelper, times(1)).updateDefaultZenRules(
                anyInt(), anyBoolean());
                anyInt());
    }
    @Test
@@ -8752,7 +8751,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        // verify that zen mode helper gets passed in a package name of "android"
        verify(mockZenModeHelper).addAutomaticZenRule(eq("android"), eq(rule), anyString(),
                anyInt(), eq(true)); // system call counts as "is system or system ui"
                anyInt(), eq(ZenModeHelper.FROM_SYSTEM_OR_SYSTEMUI)); // system call
    }
    @Test
@@ -8774,7 +8773,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        // verify that zen mode helper gets passed in a package name of "android"
        verify(mockZenModeHelper).addAutomaticZenRule(eq("android"), eq(rule), anyString(),
                anyInt(),  eq(true));  // system call counts as "system or system ui"
                anyInt(), eq(ZenModeHelper.FROM_SYSTEM_OR_SYSTEMUI));  // system call
    }
    @Test
@@ -8795,7 +8794,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase {
        // verify that zen mode helper gets passed in the package name from the arg, not the owner
        verify(mockZenModeHelper).addAutomaticZenRule(
                eq("another.package"), eq(rule), anyString(), anyInt(),
                eq(false));  // doesn't count as a system/systemui call
                eq(ZenModeHelper.FROM_APP));  // doesn't count as a system/systemui call
    }
    @Test
+228 −44

File changed.

Preview size limit exceeded, changes collapsed.