Trim strings added to persistent snoozed notification storage.

This is a backport of ag/20581190 and includes the fix in ag/20778075.
Note that on this branch, clearData doesn't seem to actually clear persistent storage.

Bug: 258422365
Test: atest NotificationManagerServiceTest SnoozeHelperTest
Change-Id: If7c7db6694330ffbac551d044efadb26219fe17f
Merged-In: I5a2823f10053ea8c83c612a567d6d4f1b6af23e7
Merged-In: Ie809cb4d648a40622618e0fb374f36b6d8dc972a
Merged-In: If7c7db6694330ffbac551d044efadb26219fe17f
diff --git a/services/core/java/com/android/server/notification/SnoozeHelper.java b/services/core/java/com/android/server/notification/SnoozeHelper.java
index a29ac13..a6cae49 100644
--- a/services/core/java/com/android/server/notification/SnoozeHelper.java
+++ b/services/core/java/com/android/server/notification/SnoozeHelper.java
@@ -62,6 +62,9 @@
 
     static final int CONCURRENT_SNOOZE_LIMIT = 500;
 
+    // A safe size for strings to be put in persistent storage, to avoid breaking the XML write.
+    static final int MAX_STRING_LENGTH = 1000;
+
     protected static final String XML_TAG_NAME = "snoozed-notifications";
 
     private static final String XML_SNOOZED_NOTIFICATION = "notification";
@@ -150,7 +153,7 @@
            ArrayMap<String, Long> snoozed =
                    mPersistedSnoozedNotifications.get(getPkgKey(userId, pkg));
            if (snoozed != null) {
-               time = snoozed.get(key);
+               time = snoozed.get(getTrimmedString(key));
            }
         }
         if (time == null) {
@@ -164,7 +167,7 @@
             ArrayMap<String, String> snoozed =
                     mPersistedSnoozedNotificationsWithContext.get(getPkgKey(userId, pkg));
             if (snoozed != null) {
-                return snoozed.get(key);
+                return snoozed.get(getTrimmedString(key));
             }
         }
         return null;
@@ -249,7 +252,8 @@
         scheduleRepost(pkg, key, userId, duration);
         Long activateAt = System.currentTimeMillis() + duration;
         synchronized (mLock) {
-            storeRecordLocked(pkg, key, userId, mPersistedSnoozedNotifications, activateAt);
+            storeRecordLocked(pkg, getTrimmedString(key), userId, mPersistedSnoozedNotifications,
+                    activateAt);
         }
     }
 
@@ -260,8 +264,10 @@
         int userId = record.getUser().getIdentifier();
         if (contextId != null) {
             synchronized (mLock) {
-                storeRecordLocked(record.getSbn().getPackageName(), record.getKey(),
-                        userId, mPersistedSnoozedNotificationsWithContext, contextId);
+                storeRecordLocked(record.getSbn().getPackageName(),
+                        getTrimmedString(record.getKey()),
+                        userId, mPersistedSnoozedNotificationsWithContext,
+                        getTrimmedString(contextId));
             }
         }
         snooze(record);
@@ -278,6 +284,13 @@
         }
     }
 
+    private String getTrimmedString(String key) {
+        if (key != null && key.length() > MAX_STRING_LENGTH) {
+            return key.substring(0, MAX_STRING_LENGTH);
+        }
+        return key;
+    }
+
     private <T> void storeRecordLocked(String pkg, String key, Integer userId,
             ArrayMap<String, ArrayMap<String, T>> targets, T object) {
 
@@ -382,12 +395,14 @@
     }
 
     protected void repost(String key, int userId, boolean muteOnReturn) {
+        final String trimmedKey = getTrimmedString(key);
+
         NotificationRecord record;
         synchronized (mLock) {
             final String pkg = mPackages.remove(key);
             mUsers.remove(key);
-            removeRecordLocked(pkg, key, userId, mPersistedSnoozedNotifications);
-            removeRecordLocked(pkg, key, userId, mPersistedSnoozedNotificationsWithContext);
+            removeRecordLocked(pkg, trimmedKey, userId, mPersistedSnoozedNotifications);
+            removeRecordLocked(pkg, trimmedKey, userId, mPersistedSnoozedNotificationsWithContext);
             ArrayMap<String, NotificationRecord> records =
                     mSnoozedNotifications.get(getPkgKey(userId, pkg));
             if (records == null) {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
index 83ba710..2b6fbea 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/SnoozeHelperTest.java
@@ -67,6 +67,7 @@
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.util.Collections;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
@@ -246,6 +247,37 @@
     }
 
     @Test
+    public void testLongTagPersistedNotification() throws Exception {
+        String longTag = String.join("", Collections.nCopies(66000, "A"));
+        NotificationRecord r = getNotificationRecord("pkg", 1, longTag, UserHandle.SYSTEM);
+        mSnoozeHelper.snooze(r, 0);
+
+        // We store the full key in temp storage.
+        ArgumentCaptor<PendingIntent> captor = ArgumentCaptor.forClass(PendingIntent.class);
+        verify(mAm).setExactAndAllowWhileIdle(anyInt(), anyLong(), captor.capture());
+        assertEquals(66010, captor.getValue().getIntent().getStringExtra(EXTRA_KEY).length());
+
+        XmlSerializer serializer = Xml.newSerializer();
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
+        serializer.startDocument(null, true);
+        mSnoozeHelper.writeXml(serializer);
+        serializer.endDocument();
+        serializer.flush();
+
+        XmlPullParser parser = Xml.newPullParser();
+        parser.setInput(new BufferedInputStream(
+                new ByteArrayInputStream(baos.toByteArray())), "utf-8");
+        mSnoozeHelper.readXml(parser, 4);
+
+        mSnoozeHelper.scheduleRepostsForPersistedNotifications(5);
+
+        // We trim the key in persistent storage.
+        verify(mAm, times(2)).setExactAndAllowWhileIdle(anyInt(), anyLong(), captor.capture());
+        assertEquals(1000, captor.getValue().getIntent().getStringExtra(EXTRA_KEY).length());
+    }
+
+    @Test
     public void testSnoozeForTime() throws Exception {
         NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
         mSnoozeHelper.snooze(r, 1000);
@@ -593,13 +625,20 @@
     public void testClearData() {
         // snooze 2 from same package
         NotificationRecord r = getNotificationRecord("pkg", 1, "one", UserHandle.SYSTEM);
-        NotificationRecord r2 = getNotificationRecord("pkg", 2, "two", UserHandle.SYSTEM);
+        NotificationRecord r2 = getNotificationRecord("pkg", 2,
+                "two" + String.join("", Collections.nCopies(66000, "2")), UserHandle.SYSTEM);
         mSnoozeHelper.snooze(r, 1000);
         mSnoozeHelper.snooze(r2, 1000);
         assertTrue(mSnoozeHelper.isSnoozed(
                 UserHandle.USER_SYSTEM, r.getSbn().getPackageName(), r.getKey()));
         assertTrue(mSnoozeHelper.isSnoozed(
                 UserHandle.USER_SYSTEM, r2.getSbn().getPackageName(), r2.getKey()));
+        assertFalse(0L == mSnoozeHelper.getSnoozeTimeForUnpostedNotification(
+                r.getUser().getIdentifier(), r.getSbn().getPackageName(),
+                r.getSbn().getKey()));
+        assertFalse(0L == mSnoozeHelper.getSnoozeTimeForUnpostedNotification(
+                r2.getUser().getIdentifier(), r2.getSbn().getPackageName(),
+                r2.getSbn().getKey()));
 
         // clear data
         mSnoozeHelper.clearData(UserHandle.USER_SYSTEM, "pkg");