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

Commit b859ed25 authored by Matías Hernández's avatar Matías Hernández Committed by Android (Google) Code Review
Browse files

Merge "Enforce a limit on the size of ZenModeConfig" into main

parents f5158de8 ee3779d6
Loading
Loading
Loading
Loading
+6 −6
Original line number Diff line number Diff line
@@ -228,7 +228,7 @@ public final class AutomaticZenRule implements Parcelable {
    public AutomaticZenRule(Parcel source) {
        enabled = source.readInt() == ENABLED;
        if (source.readInt() == ENABLED) {
            name = getTrimmedString(source.readString());
            name = getTrimmedString(source.readString8());
        }
        interruptionFilter = source.readInt();
        conditionId = getTrimmedUri(source.readParcelable(null, android.net.Uri.class));
@@ -238,11 +238,11 @@ public final class AutomaticZenRule implements Parcelable {
                source.readParcelable(null, android.content.ComponentName.class));
        creationTime = source.readLong();
        mZenPolicy = source.readParcelable(null, ZenPolicy.class);
        mPkg = source.readString();
        mPkg = source.readString8();
        mDeviceEffects = source.readParcelable(null, ZenDeviceEffects.class);
        mAllowManualInvocation = source.readBoolean();
        mIconResId = source.readInt();
        mTriggerDescription = getTrimmedString(source.readString(), MAX_DESC_LENGTH);
        mTriggerDescription = getTrimmedString(source.readString8(), MAX_DESC_LENGTH);
        mType = source.readInt();
    }

@@ -514,7 +514,7 @@ public final class AutomaticZenRule implements Parcelable {
        dest.writeInt(enabled ? ENABLED : DISABLED);
        if (name != null) {
            dest.writeInt(1);
            dest.writeString(name);
            dest.writeString8(name);
        } else {
            dest.writeInt(0);
        }
@@ -524,11 +524,11 @@ public final class AutomaticZenRule implements Parcelable {
        dest.writeParcelable(configurationActivity, 0);
        dest.writeLong(creationTime);
        dest.writeParcelable(mZenPolicy, 0);
        dest.writeString(mPkg);
        dest.writeString8(mPkg);
        dest.writeParcelable(mDeviceEffects, 0);
        dest.writeBoolean(mAllowManualInvocation);
        dest.writeInt(mIconResId);
        dest.writeString(mTriggerDescription);
        dest.writeString8(mTriggerDescription);
        dest.writeInt(mType);
    }

+12 −12
Original line number Diff line number Diff line
@@ -2636,7 +2636,7 @@ public class ZenModeConfig implements Parcelable {
            enabled = source.readInt() == 1;
            snoozing = source.readInt() == 1;
            if (source.readInt() == 1) {
                name = source.readString();
                name = source.readString8();
            }
            zenMode = source.readInt();
            conditionId = source.readParcelable(null, android.net.Uri.class);
@@ -2644,18 +2644,18 @@ public class ZenModeConfig implements Parcelable {
            component = source.readParcelable(null, android.content.ComponentName.class);
            configurationActivity = source.readParcelable(null, android.content.ComponentName.class);
            if (source.readInt() == 1) {
                id = source.readString();
                id = source.readString8();
            }
            creationTime = source.readLong();
            if (source.readInt() == 1) {
                enabler = source.readString();
                enabler = source.readString8();
            }
            zenPolicy = source.readParcelable(null, android.service.notification.ZenPolicy.class);
            zenDeviceEffects = source.readParcelable(null, ZenDeviceEffects.class);
            pkg = source.readString();
            pkg = source.readString8();
            allowManualInvocation = source.readBoolean();
            iconResName = source.readString();
            triggerDescription = source.readString();
            iconResName = source.readString8();
            triggerDescription = source.readString8();
            type = source.readInt();
            userModifiedFields = source.readInt();
            zenPolicyUserModifiedFields = source.readInt();
@@ -2703,7 +2703,7 @@ public class ZenModeConfig implements Parcelable {
            dest.writeInt(snoozing ? 1 : 0);
            if (name != null) {
                dest.writeInt(1);
                dest.writeString(name);
                dest.writeString8(name);
            } else {
                dest.writeInt(0);
            }
@@ -2714,23 +2714,23 @@ public class ZenModeConfig implements Parcelable {
            dest.writeParcelable(configurationActivity, 0);
            if (id != null) {
                dest.writeInt(1);
                dest.writeString(id);
                dest.writeString8(id);
            } else {
                dest.writeInt(0);
            }
            dest.writeLong(creationTime);
            if (enabler != null) {
                dest.writeInt(1);
                dest.writeString(enabler);
                dest.writeString8(enabler);
            } else {
                dest.writeInt(0);
            }
            dest.writeParcelable(zenPolicy, 0);
            dest.writeParcelable(zenDeviceEffects, 0);
            dest.writeString(pkg);
            dest.writeString8(pkg);
            dest.writeBoolean(allowManualInvocation);
            dest.writeString(iconResName);
            dest.writeString(triggerDescription);
            dest.writeString8(iconResName);
            dest.writeString8(triggerDescription);
            dest.writeInt(type);
            dest.writeInt(userModifiedFields);
            dest.writeInt(zenPolicyUserModifiedFields);
+11 −2
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class ConditionProviders extends ManagedServices {

@@ -202,7 +203,14 @@ public class ConditionProviders extends ManagedServices {

    @Override
    protected void loadDefaultsFromConfig() {
        String defaultDndAccess = mContext.getResources().getString(
        for (String dndPackage : getDefaultDndAccessPackages(mContext)) {
            addDefaultComponentOrPackage(dndPackage);
        }
    }

    static List<String> getDefaultDndAccessPackages(Context context) {
        ArrayList<String> packages = new ArrayList<>();
        String defaultDndAccess = context.getResources().getString(
                R.string.config_defaultDndAccessPackages);
        if (defaultDndAccess != null) {
            String[] dnds = defaultDndAccess.split(ManagedServices.ENABLED_SERVICES_SEPARATOR);
@@ -210,9 +218,10 @@ public class ConditionProviders extends ManagedServices {
                if (TextUtils.isEmpty(dnds[i])) {
                    continue;
                }
                addDefaultComponentOrPackage(dnds[i]);
                packages.add(dnds[i]);
            }
        }
        return packages;
    }

    @Override
+109 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.notification;

import android.content.Context;
import android.os.Parcel;
import android.service.notification.SystemZenRules;
import android.service.notification.ZenModeConfig;
import android.util.Slog;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

class ZenConfigTrimmer {

    private static final String TAG = "ZenConfigTrimmer";
    private static final int MAXIMUM_PARCELED_SIZE = 150_000; // bytes

    private final HashSet<String> mTrustedPackages;

    ZenConfigTrimmer(Context context) {
        mTrustedPackages = new HashSet<>();
        mTrustedPackages.add(SystemZenRules.PACKAGE_ANDROID);
        mTrustedPackages.addAll(ConditionProviders.getDefaultDndAccessPackages(context));
    }

    void trimToMaximumSize(ZenModeConfig config) {
        Map<String, PackageRules> rulesPerPackage = new HashMap<>();
        for (ZenModeConfig.ZenRule rule : config.automaticRules.values()) {
            PackageRules pkgRules = rulesPerPackage.computeIfAbsent(rule.pkg, PackageRules::new);
            pkgRules.mRules.add(rule);
        }

        int totalSize = 0;
        for (PackageRules pkgRules : rulesPerPackage.values()) {
            totalSize += pkgRules.dataSize();
        }

        if (totalSize > MAXIMUM_PARCELED_SIZE) {
            List<PackageRules> deletionCandidates = new ArrayList<>();
            for (PackageRules pkgRules : rulesPerPackage.values()) {
                if (!mTrustedPackages.contains(pkgRules.mPkg)) {
                    deletionCandidates.add(pkgRules);
                }
            }
            deletionCandidates.sort(Comparator.comparingInt(PackageRules::dataSize).reversed());

            evictPackagesFromConfig(config, deletionCandidates, totalSize);
        }
    }

    private static void evictPackagesFromConfig(ZenModeConfig config,
            List<PackageRules> deletionCandidates, int currentSize) {
        while (currentSize > MAXIMUM_PARCELED_SIZE && !deletionCandidates.isEmpty()) {
            PackageRules rulesToDelete = deletionCandidates.removeFirst();
            Slog.w(TAG, String.format("Evicting %s zen rules from package '%s' (%s bytes)",
                    rulesToDelete.mRules.size(), rulesToDelete.mPkg, rulesToDelete.dataSize()));

            for (ZenModeConfig.ZenRule rule : rulesToDelete.mRules) {
                config.automaticRules.remove(rule.id);
            }

            currentSize -= rulesToDelete.dataSize();
        }
    }

    private static class PackageRules {
        private final String mPkg;
        private final List<ZenModeConfig.ZenRule> mRules;
        private int mParceledSize = -1;

        PackageRules(String pkg) {
            mPkg = pkg;
            mRules = new ArrayList<>();
        }

        private int dataSize() {
            if (mParceledSize >= 0) {
                return mParceledSize;
            }
            Parcel parcel = Parcel.obtain();
            try {
                parcel.writeParcelableList(mRules, 0);
                mParceledSize = parcel.dataSize();
                return mParceledSize;
            } finally {
                parcel.recycle();
            }
        }
    }
}
+9 −6
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ import static android.service.notification.ZenModeConfig.isImplicitRuleId;
import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE;
import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.server.notification.Flags.preventZenDeviceEffectsWhileDriving;
import static com.android.server.notification.Flags.limitZenConfigSize;

import static java.util.Objects.requireNonNull;

@@ -192,6 +193,7 @@ public class ZenModeHelper {
    private final ConditionProviders.Config mServiceConfig;
    private final SystemUiSystemPropertiesFlags.FlagResolver mFlagResolver;
    private final ZenModeEventLogger mZenModeEventLogger;
    private final ZenConfigTrimmer mConfigTrimmer;

    @VisibleForTesting protected int mZenMode;
    @VisibleForTesting protected NotificationManager.Policy mConsolidatedPolicy;
@@ -226,6 +228,7 @@ public class ZenModeHelper {
        mClock = clock;
        addCallback(mMetrics);
        mAppOps = context.getSystemService(AppOpsManager.class);
        mConfigTrimmer = new ZenConfigTrimmer(mContext);

        mDefaultConfig = Flags.modesUi()
                ? ZenModeConfig.getDefaultConfig()
@@ -2061,20 +2064,20 @@ public class ZenModeHelper {
                Log.w(TAG, "Invalid config in setConfigLocked; " + config);
                return false;
            }
            if (limitZenConfigSize() && (origin == ORIGIN_APP || origin == ORIGIN_USER_IN_APP)) {
                mConfigTrimmer.trimToMaximumSize(config);
            }

            if (config.user != mUser) {
                // simply store away for background users
                synchronized (mConfigLock) {
                mConfigs.put(config.user, config);
                }
                if (DEBUG) Log.d(TAG, "setConfigLocked: store config for user " + config.user);
                return true;
            }
            // handle CPS backed conditions - danger! may modify config
            mConditions.evaluateConfig(config, null, false /*processSubscriptions*/);

            synchronized (mConfigLock) {
            mConfigs.put(config.user, config);
            }
            if (DEBUG) Log.d(TAG, "setConfigLocked reason=" + reason, new Throwable());
            ZenLog.traceConfig(origin, reason, triggeringComponent, mConfig, config, callingUid);

Loading