diff options
3 files changed, 105 insertions, 4 deletions
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 849f236916a6..76465565db11 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -82,6 +82,8 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BA import static android.app.NotificationManager.zenModeFromInterruptionFilter; import static android.app.StatusBarManager.ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED; import static android.app.StatusBarManager.EXTRA_KM_PRIVATE_NOTIFS_ALLOWED; +import static android.app.backup.NotificationLoggingConstants.DATA_TYPE_ZEN_CONFIG; +import static android.app.backup.NotificationLoggingConstants.ERROR_XML_PARSING; import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT; import static android.content.Context.BIND_AUTO_CREATE; import static android.content.Context.BIND_FOREGROUND_SERVICE; @@ -162,8 +164,6 @@ import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER; import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER; import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER; -import static android.app.backup.NotificationLoggingConstants.DATA_TYPE_ZEN_CONFIG; -import static android.app.backup.NotificationLoggingConstants.ERROR_XML_PARSING; import static com.android.server.notification.Flags.expireBitmaps; import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_ANIM_BUFFER; import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_TIMEOUT; @@ -1929,6 +1929,12 @@ public class NotificationManagerService extends SystemService { hasSensitiveContent, lifespanMs); } + protected void logClassificationChannelAdjustmentReceived(boolean hasPosted, boolean isAlerting, + int classification, int lifespanMs) { + FrameworkStatsLog.write(FrameworkStatsLog.NOTIFICATION_CHANNEL_CLASSIFICATION, + hasPosted, isAlerting, classification, lifespanMs); + } + protected final BroadcastReceiver mLocaleChangeReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -6988,8 +6994,15 @@ public class NotificationManagerService extends SystemService { if (newChannel == null || newChannel.getId().equals(r.getChannel().getId())) { adjustments.remove(KEY_TYPE); } else { + // Save the app-provided type for logging. + int classification = adjustments.getInt(KEY_TYPE); // swap app provided type with the real thing adjustments.putParcelable(KEY_TYPE, newChannel); + // Note that this value of isAlerting does not fully indicate whether a notif + // would make a sound or HUN on device; it is an approximation for metrics. + boolean isAlerting = r.getChannel().getImportance() >= IMPORTANCE_DEFAULT; + logClassificationChannelAdjustmentReceived(isPosted, isAlerting, classification, + r.getLifespanMs(System.currentTimeMillis())); } } r.addAdjustment(adjustment); 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 ac021e122998..87367c547191 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -78,7 +78,6 @@ import static android.app.PendingIntent.FLAG_ONE_SHOT; import static android.app.StatusBarManager.ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED; import static android.app.StatusBarManager.EXTRA_KM_PRIVATE_NOTIFS_ALLOWED; import static android.app.backup.NotificationLoggingConstants.DATA_TYPE_ZEN_CONFIG; -import static android.app.backup.NotificationLoggingConstants.DATA_TYPE_ZEN_RULES; import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; import static android.content.pm.PackageManager.FEATURE_TELECOM; import static android.content.pm.PackageManager.FEATURE_WATCH; @@ -366,7 +365,6 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; -import java.io.OutputStream; import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; @@ -7442,6 +7440,63 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test + @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION) + public void testClassificationChannelAdjustmentsLogged() throws Exception { + NotificationManagerService.WorkerHandler handler = mock( + NotificationManagerService.WorkerHandler.class); + mService.setHandler(handler); + when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); + when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); + + // Set up notifications that will be adjusted + final NotificationRecord r1 = spy(generateNotificationRecord( + mTestNotificationChannel, 1, null, true)); + when(r1.getLifespanMs(anyLong())).thenReturn(234); + + r1.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); + // Enqueues the notification to be posted, so hasPosted will be false. + mService.addEnqueuedNotification(r1); + + // Test an adjustment for an enqueued notification + Bundle signals = new Bundle(); + signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_NEWS); + Adjustment adjustment1 = new Adjustment( + r1.getSbn().getPackageName(), r1.getKey(), signals, "", + r1.getUser().getIdentifier()); + mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment1); + assertTrue(mService.checkLastClassificationChannelLog(false /*hasPosted*/, + true /*isAlerting*/, 3 /*TYPE_NEWS*/, 234)); + + // Set up notifications that will be adjusted + // This notification starts on a low importance channel, so isAlerting is false. + NotificationChannel mLowImportanceNotificationChannel = new NotificationChannel( + TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_LOW); + final NotificationRecord r2 = spy(generateNotificationRecord( + mLowImportanceNotificationChannel, 1, null, true)); + when(r2.getLifespanMs(anyLong())).thenReturn(345); + + r2.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); + // Adds the notification as already posted, so hasPosted will be true. + mService.addNotification(r2); + // The signal is removed when used so it has to be readded. + signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_NEWS); + Adjustment adjustment2 = new Adjustment( + r2.getSbn().getPackageName(), r2.getKey(), signals, "", + r2.getUser().getIdentifier()); + mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment2); + assertTrue(mService.checkLastClassificationChannelLog(true /*hasPosted*/, + false /*isAlerting*/, 3 /*TYPE_NEWS*/, 345)); // currently failing + + signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_PROMOTION); + Adjustment adjustment3 = new Adjustment( + r2.getSbn().getPackageName(), r2.getKey(), signals, "", + r2.getUser().getIdentifier()); + mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment3); + assertTrue(mService.checkLastClassificationChannelLog(true /*hasPosted*/, + false /*isAlerting*/, 1 /*TYPE_PROMOTION*/, 345)); + } + + @Test public void testAdjustmentToImportanceNone_cancelsNotification() throws Exception { NotificationManagerService.WorkerHandler handler = mock( NotificationManagerService.WorkerHandler.class); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java b/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java index 07d25dfd814e..ba91ca2323af 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/TestableNotificationManagerService.java @@ -52,6 +52,14 @@ public class TestableNotificationManagerService extends NotificationManagerServi } public SensitiveLog lastSensitiveLog = null; + private static class ClassificationChannelLog { + public boolean hasPosted; + public boolean isAlerting; + public long classification; + public long lifetime; + } + public ClassificationChannelLog lastClassificationChannelLog = null; + TestableNotificationManagerService(Context context, NotificationRecordLogger logger, InstanceIdSequence notificationInstanceIdSequence) { super(context, logger, notificationInstanceIdSequence); @@ -211,4 +219,29 @@ public class TestableNotificationManagerService extends NotificationManagerServi public interface ComponentPermissionChecker { int check(String permission, int uid, int owningUid, boolean exported); } + + @Override + protected void logClassificationChannelAdjustmentReceived(boolean hasPosted, boolean isAlerting, + int classification, int lifetimeMs) { + lastClassificationChannelLog = new ClassificationChannelLog(); + lastClassificationChannelLog.hasPosted = hasPosted; + lastClassificationChannelLog.isAlerting = isAlerting; + lastClassificationChannelLog.classification = classification; + lastClassificationChannelLog.lifetime = lifetimeMs; + } + + /** + * Returns true if the last recorded classification channel log has all the values specified. + */ + public boolean checkLastClassificationChannelLog(boolean hasPosted, boolean isAlerting, + int classification, int lifetime) { + if (lastClassificationChannelLog == null) { + return false; + } + + return hasPosted == lastClassificationChannelLog.hasPosted + && isAlerting == lastClassificationChannelLog.isAlerting + && classification == lastClassificationChannelLog.classification + && lifetime == lastClassificationChannelLog.lifetime; + } } |