Loading services/core/java/com/android/server/notification/ZenLog.java +32 −5 Original line number Diff line number Diff line Loading @@ -31,7 +31,7 @@ import android.service.notification.ZenModeConfig.ConfigOrigin; import android.service.notification.ZenModeDiff; import android.util.LocalLog; import com.android.internal.annotations.VisibleForTesting; import androidx.annotation.VisibleForTesting; import java.io.PrintWriter; import java.util.List; Loading @@ -40,9 +40,23 @@ public class ZenLog { private static final int SIZE = Build.IS_DEBUGGABLE ? 200 : 100; /** * State changes: related to updating ZenModeConfig (e.g. add AZR) and its aftereffects * (e.g. calculated new consolidated policy). */ private static final LocalLog STATE_CHANGES = new LocalLog(SIZE); /** * Interception events: related to decisions about individual notifications (e.g. matches * call filter). */ private static final LocalLog INTERCEPTION_EVENTS = new LocalLog(SIZE); /** * Other events: neither of the above (e.g. NLS updates listener hints). */ private static final LocalLog OTHER_EVENTS = new LocalLog(SIZE); private static final int TYPE_INTERCEPTED = 1; private static final int TYPE_SET_RINGER_MODE_EXTERNAL = 3; private static final int TYPE_SET_RINGER_MODE_INTERNAL = 4; Loading @@ -62,6 +76,7 @@ public class ZenLog { private static final int TYPE_ALERT_ON_UPDATED_INTERCEPT = 21; private static final int TYPE_APPLY_DEVICE_EFFECT = 22; private static final int TYPE_SCHEDULE_APPLY_DEVICE_EFFECT = 23; // If adding new types, consider updating append() to choose the most appropriate LocalLog. public static void traceIntercepted(NotificationRecord record, String reason) { append(TYPE_INTERCEPTED, record.getKey() + "," + reason); Loading Loading @@ -280,10 +295,15 @@ public class ZenLog { private static void append(int type, String msg) { if (type == TYPE_INTERCEPTED || type == TYPE_NOT_INTERCEPTED || type == TYPE_CHECK_REPEAT_CALLER || type == TYPE_RECORD_CALLER || type == TYPE_MATCHES_CALL_FILTER || type == TYPE_ALERT_ON_UPDATED_INTERCEPT) { || type == TYPE_MATCHES_CALL_FILTER || type == TYPE_ALERT_ON_UPDATED_INTERCEPT || type == TYPE_DISABLE_EFFECTS) { synchronized (INTERCEPTION_EVENTS) { INTERCEPTION_EVENTS.log(typeToString(type) + ": " + msg); } } else if (type == TYPE_SUPPRESSOR_CHANGED || type == TYPE_LISTENER_HINTS_CHANGED) { synchronized (OTHER_EVENTS) { OTHER_EVENTS.log(typeToString(type) + ": " + msg); } } else { synchronized (STATE_CHANGES) { STATE_CHANGES.log(typeToString(type) + ": " + msg); Loading @@ -300,9 +320,13 @@ public class ZenLog { pw.printf(prefix + "State Changes:\n"); STATE_CHANGES.dump(prefix, pw); } synchronized (OTHER_EVENTS) { pw.printf(prefix + "Other Events:\n"); OTHER_EVENTS.dump(prefix, pw); } } @VisibleForTesting(/* otherwise = VisibleForTesting.NONE */) @VisibleForTesting(otherwise = VisibleForTesting.NONE) public static void clear() { synchronized (INTERCEPTION_EVENTS) { INTERCEPTION_EVENTS.clear(); Loading @@ -310,5 +334,8 @@ public class ZenLog { synchronized (STATE_CHANGES) { STATE_CHANGES.clear(); } synchronized (OTHER_EVENTS) { OTHER_EVENTS.clear(); } } } services/tests/uiservicestests/src/com/android/server/notification/ZenLogTest.java 0 → 100644 +76 −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 static android.provider.Settings.Global.ZEN_MODE_ALARMS; import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS; import static com.google.common.truth.Truth.assertThat; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.server.UiServiceTestCase; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import java.io.PrintWriter; import java.io.StringWriter; import java.util.regex.Pattern; @SmallTest @RunWith(AndroidJUnit4.class) public class ZenLogTest extends UiServiceTestCase { @Before public void setUp() { ZenLog.clear(); } @Test public void trace_splitsLogs() { ZenLog.traceMatchesCallFilter(true, "is starred", /* callingUid= */ 123); ZenLog.traceSetZenMode(ZEN_MODE_ALARMS, "only alarms plz"); ZenLog.traceListenerHintsChanged(/* oldHints= */ 0, /* newHints= */ HINT_HOST_DISABLE_EFFECTS, /* listenerCount= */ 1); String log = getLog(); assertThat(log).matches(Pattern.compile( "(.*)" // whitespace + "Interception Events:" + "(.*)" // whitespace + timestamp + "matches_call_filter: result=true, reason=is starred, calling uid=123" + "(.*)" + "State Changes:" + "(.*)" + "set_zen_mode: alarms,only alarms plz" + "(.*)" + "Other Events:" + "(.*)" + "listener_hints_changed: none->disable_effects,listeners=1" + "(.*)", Pattern.DOTALL)); } private static String getLog() { StringWriter zenLogWriter = new StringWriter(); ZenLog.dump(new PrintWriter(zenLogWriter), ""); return zenLogWriter.toString(); } } Loading
services/core/java/com/android/server/notification/ZenLog.java +32 −5 Original line number Diff line number Diff line Loading @@ -31,7 +31,7 @@ import android.service.notification.ZenModeConfig.ConfigOrigin; import android.service.notification.ZenModeDiff; import android.util.LocalLog; import com.android.internal.annotations.VisibleForTesting; import androidx.annotation.VisibleForTesting; import java.io.PrintWriter; import java.util.List; Loading @@ -40,9 +40,23 @@ public class ZenLog { private static final int SIZE = Build.IS_DEBUGGABLE ? 200 : 100; /** * State changes: related to updating ZenModeConfig (e.g. add AZR) and its aftereffects * (e.g. calculated new consolidated policy). */ private static final LocalLog STATE_CHANGES = new LocalLog(SIZE); /** * Interception events: related to decisions about individual notifications (e.g. matches * call filter). */ private static final LocalLog INTERCEPTION_EVENTS = new LocalLog(SIZE); /** * Other events: neither of the above (e.g. NLS updates listener hints). */ private static final LocalLog OTHER_EVENTS = new LocalLog(SIZE); private static final int TYPE_INTERCEPTED = 1; private static final int TYPE_SET_RINGER_MODE_EXTERNAL = 3; private static final int TYPE_SET_RINGER_MODE_INTERNAL = 4; Loading @@ -62,6 +76,7 @@ public class ZenLog { private static final int TYPE_ALERT_ON_UPDATED_INTERCEPT = 21; private static final int TYPE_APPLY_DEVICE_EFFECT = 22; private static final int TYPE_SCHEDULE_APPLY_DEVICE_EFFECT = 23; // If adding new types, consider updating append() to choose the most appropriate LocalLog. public static void traceIntercepted(NotificationRecord record, String reason) { append(TYPE_INTERCEPTED, record.getKey() + "," + reason); Loading Loading @@ -280,10 +295,15 @@ public class ZenLog { private static void append(int type, String msg) { if (type == TYPE_INTERCEPTED || type == TYPE_NOT_INTERCEPTED || type == TYPE_CHECK_REPEAT_CALLER || type == TYPE_RECORD_CALLER || type == TYPE_MATCHES_CALL_FILTER || type == TYPE_ALERT_ON_UPDATED_INTERCEPT) { || type == TYPE_MATCHES_CALL_FILTER || type == TYPE_ALERT_ON_UPDATED_INTERCEPT || type == TYPE_DISABLE_EFFECTS) { synchronized (INTERCEPTION_EVENTS) { INTERCEPTION_EVENTS.log(typeToString(type) + ": " + msg); } } else if (type == TYPE_SUPPRESSOR_CHANGED || type == TYPE_LISTENER_HINTS_CHANGED) { synchronized (OTHER_EVENTS) { OTHER_EVENTS.log(typeToString(type) + ": " + msg); } } else { synchronized (STATE_CHANGES) { STATE_CHANGES.log(typeToString(type) + ": " + msg); Loading @@ -300,9 +320,13 @@ public class ZenLog { pw.printf(prefix + "State Changes:\n"); STATE_CHANGES.dump(prefix, pw); } synchronized (OTHER_EVENTS) { pw.printf(prefix + "Other Events:\n"); OTHER_EVENTS.dump(prefix, pw); } } @VisibleForTesting(/* otherwise = VisibleForTesting.NONE */) @VisibleForTesting(otherwise = VisibleForTesting.NONE) public static void clear() { synchronized (INTERCEPTION_EVENTS) { INTERCEPTION_EVENTS.clear(); Loading @@ -310,5 +334,8 @@ public class ZenLog { synchronized (STATE_CHANGES) { STATE_CHANGES.clear(); } synchronized (OTHER_EVENTS) { OTHER_EVENTS.clear(); } } }
services/tests/uiservicestests/src/com/android/server/notification/ZenLogTest.java 0 → 100644 +76 −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 static android.provider.Settings.Global.ZEN_MODE_ALARMS; import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS; import static com.google.common.truth.Truth.assertThat; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.server.UiServiceTestCase; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import java.io.PrintWriter; import java.io.StringWriter; import java.util.regex.Pattern; @SmallTest @RunWith(AndroidJUnit4.class) public class ZenLogTest extends UiServiceTestCase { @Before public void setUp() { ZenLog.clear(); } @Test public void trace_splitsLogs() { ZenLog.traceMatchesCallFilter(true, "is starred", /* callingUid= */ 123); ZenLog.traceSetZenMode(ZEN_MODE_ALARMS, "only alarms plz"); ZenLog.traceListenerHintsChanged(/* oldHints= */ 0, /* newHints= */ HINT_HOST_DISABLE_EFFECTS, /* listenerCount= */ 1); String log = getLog(); assertThat(log).matches(Pattern.compile( "(.*)" // whitespace + "Interception Events:" + "(.*)" // whitespace + timestamp + "matches_call_filter: result=true, reason=is starred, calling uid=123" + "(.*)" + "State Changes:" + "(.*)" + "set_zen_mode: alarms,only alarms plz" + "(.*)" + "Other Events:" + "(.*)" + "listener_hints_changed: none->disable_effects,listeners=1" + "(.*)", Pattern.DOTALL)); } private static String getLog() { StringWriter zenLogWriter = new StringWriter(); ZenLog.dump(new PrintWriter(zenLogWriter), ""); return zenLogWriter.toString(); } }