Loading core/java/android/app/AutomaticZenRule.java +6 −6 Original line number Diff line number Diff line Loading @@ -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)); Loading @@ -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(); } Loading Loading @@ -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); } Loading @@ -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); } Loading core/java/android/service/notification/ZenModeConfig.java +12 −12 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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(); Loading Loading @@ -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); } Loading @@ -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); Loading services/core/java/com/android/server/notification/ConditionProviders.java +11 −2 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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); Loading @@ -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 Loading services/core/java/com/android/server/notification/ZenConfigTrimmer.java 0 → 100644 +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(); } } } } services/core/java/com/android/server/notification/ZenModeHelper.java +9 −6 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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() Loading Loading @@ -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 Loading
core/java/android/app/AutomaticZenRule.java +6 −6 Original line number Diff line number Diff line Loading @@ -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)); Loading @@ -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(); } Loading Loading @@ -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); } Loading @@ -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); } Loading
core/java/android/service/notification/ZenModeConfig.java +12 −12 Original line number Diff line number Diff line Loading @@ -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); Loading @@ -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(); Loading Loading @@ -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); } Loading @@ -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); Loading
services/core/java/com/android/server/notification/ConditionProviders.java +11 −2 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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); Loading @@ -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 Loading
services/core/java/com/android/server/notification/ZenConfigTrimmer.java 0 → 100644 +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(); } } } }
services/core/java/com/android/server/notification/ZenModeHelper.java +9 −6 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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() Loading Loading @@ -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