From 357eafd4e72988ce36e2c5f97d4e554e92e66d4a Mon Sep 17 00:00:00 2001 From: Matías Hernández Date: Wed, 4 Dec 2024 13:40:00 +0100 Subject: Send AZR_STATUS_CHANGED broadcasts with FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT Although apps and ConditionProviderServices shouldn't be able to call setAZRStatus this early, system_server itself might, causing a crash/bootloop. Fixes: 381875093 Test: atest NotificationManagerServiceTest Flag: EXEMPT Safe bugfix Change-Id: I1af575ffb04e5bb5ac7f7609fa215b9ac525dcdf --- services/core/Android.bp | 1 + .../notification/NotificationManagerService.java | 1 + .../android/server/notification/ZenModeHelper.java | 8 ++- .../NotificationManagerServiceTest.java | 59 +++++++++++++++++++++- 4 files changed, 67 insertions(+), 2 deletions(-) diff --git a/services/core/Android.bp b/services/core/Android.bp index 08206150cebb..eab335136cc2 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -157,6 +157,7 @@ java_library_static { "android.hardware.light-V2.0-java", "android.hardware.gnss-V2-java", "android.hardware.vibrator-V3-java", + "androidx.annotation_annotation", "app-compat-annotations", "art_exported_aconfig_flags_lib", "framework-tethering.stubs.module_lib", diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 15af36ba66af..39eea740a902 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -2594,6 +2594,7 @@ public class NotificationManagerService extends SystemService { intent.setPackage(pkg); intent.putExtra(EXTRA_AUTOMATIC_ZEN_RULE_ID, id); intent.putExtra(EXTRA_AUTOMATIC_ZEN_RULE_STATUS, status); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); getContext().sendBroadcastAsUser(intent, UserHandle.of(userId)); }); } diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index dc173b124884..95aff5652bb6 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -112,9 +112,10 @@ import android.util.SparseArray; import android.util.StatsEvent; import android.util.proto.ProtoOutputStream; +import androidx.annotation.VisibleForTesting; + import com.android.internal.R; import com.android.internal.annotations.GuardedBy; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags; import com.android.internal.logging.MetricsLogger; import com.android.internal.util.FrameworkStatsLog; @@ -279,6 +280,11 @@ public class ZenModeHelper { mCallbacks.remove(callback); } + @VisibleForTesting(otherwise = VisibleForTesting.NONE) + public List getCallbacks() { + return mCallbacks; + } + public void initZenMode() { if (DEBUG) Log.d(TAG, "initZenMode"); synchronized (mConfigLock) { diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index 90bf1d36a4ce..060269a5c9aa 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -49,10 +49,14 @@ import static android.app.NotificationChannel.PROMOTIONS_ID; import static android.app.NotificationChannel.RECS_ID; import static android.app.NotificationChannel.SOCIAL_MEDIA_ID; import static android.app.NotificationChannel.USER_LOCKED_ALLOW_BUBBLE; +import static android.app.NotificationManager.ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED; import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED; +import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_ACTIVATED; import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL; import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE; import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED; +import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_ID; +import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_STATUS; import static android.app.NotificationManager.EXTRA_BLOCKED_STATE; import static android.app.NotificationManager.IMPORTANCE_DEFAULT; import static android.app.NotificationManager.IMPORTANCE_HIGH; @@ -369,6 +373,7 @@ import java.io.FileOutputStream; import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; @@ -11273,19 +11278,71 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(102))); } + @Test + @EnableFlags(android.app.Flags.FLAG_MODES_API) + public void onAutomaticRuleStatusChanged_sendsBroadcastToRuleOwner() throws Exception { + mService.mZenModeHelper.getCallbacks().forEach(c -> c.onAutomaticRuleStatusChanged( + mUserId, "rule.owner.pkg", "rule_id", AUTOMATIC_RULE_STATUS_ACTIVATED)); + + Intent expected = new Intent(ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED) + .setPackage("rule.owner.pkg") + .putExtra(EXTRA_AUTOMATIC_ZEN_RULE_ID, "rule_id") + .putExtra(EXTRA_AUTOMATIC_ZEN_RULE_STATUS, AUTOMATIC_RULE_STATUS_ACTIVATED) + .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + + verify(mContext).sendBroadcastAsUser(eqIntent(expected), eq(UserHandle.of(mUserId))); + } + private static Intent eqIntent(Intent wanted) { return ArgumentMatchers.argThat( new ArgumentMatcher() { @Override public boolean matches(Intent argument) { return wanted.filterEquals(argument) - && wanted.getFlags() == argument.getFlags(); + && wanted.getFlags() == argument.getFlags() + && equalBundles(wanted.getExtras(), argument.getExtras()); } @Override public String toString() { return wanted.toString(); } + + private boolean equalBundles(Bundle one, Bundle two) { + if (one == null && two == null) { + return true; + } + if ((one == null) != (two == null)) { + return false; + } + if (one.size() != two.size()) { + return false; + } + + HashSet setOne = new HashSet<>(one.keySet()); + setOne.addAll(two.keySet()); + + for (String key : setOne) { + if (!one.containsKey(key) || !two.containsKey(key)) { + return false; + } + + Object valueOne = one.get(key); + Object valueTwo = two.get(key); + if (valueOne instanceof Bundle + && valueTwo instanceof Bundle + && !equalBundles((Bundle) valueOne, (Bundle) valueTwo)) { + return false; + } else if (valueOne == null) { + if (valueTwo != null) { + return false; + } + } else if (!valueOne.equals(valueTwo)) { + return false; + } + } + return true; + } }); } -- cgit v1.2.3-59-g8ed1b