Merge "NotificationReported atom: Hash free-string ids."
This commit is contained in:
committed by
Android (Google) Code Review
commit
166e81fea3
@@ -3475,27 +3475,25 @@ message NotificationReported {
|
||||
// A small system-assigned identifier for the notification.
|
||||
// Locally probably-unique, but expect collisions across users and/or days.
|
||||
optional int32 instance_id = 4;
|
||||
// The app-assigned notification ID and tag
|
||||
optional int32 notification_id = 5;
|
||||
optional string notification_tag = 6;
|
||||
optional string channel_id = 7; // App-assigned channel ID
|
||||
optional int32 notification_id_hash = 5; // Small hash of the app-assigned notif ID + tag
|
||||
optional int32 channel_id_hash = 6; // Small hash of app-assigned channel ID
|
||||
|
||||
// Grouping information
|
||||
optional string group_id = 8; // Group the notification currently belongs to
|
||||
optional int32 group_instance_id = 9; // Instance_id of the group-summary notification
|
||||
optional bool is_group_summary = 10; // Tags the group-summary notification
|
||||
optional int32 group_id_hash = 7; // Small hash of the group ID of the notification
|
||||
optional int32 group_instance_id = 8; // Instance_id of the group-summary notification
|
||||
optional bool is_group_summary = 9; // Tags the group-summary notification
|
||||
|
||||
// Attributes
|
||||
optional string category = 11; // App-assigned notification category (API-defined strings)
|
||||
optional int32 style = 12; // App-assigned notification style
|
||||
optional int32 num_people = 13; // Number of Person records attached to the notification
|
||||
optional string category = 10; // App-assigned notification category (API-defined strings)
|
||||
optional int32 style = 11; // App-assigned notification style
|
||||
optional int32 num_people = 12; // Number of Person records attached to the notification
|
||||
|
||||
// Ordering, importance and interruptiveness
|
||||
|
||||
optional int32 position = 14; // Position in NotificationManager's list
|
||||
optional int32 position = 13; // Position in NotificationManager's list
|
||||
|
||||
optional android.stats.sysui.NotificationImportance importance = 15;
|
||||
optional int32 alerting = 16; // Bitfield, 1=buzz 2=beep 4=blink
|
||||
optional android.stats.sysui.NotificationImportance importance = 14;
|
||||
optional int32 alerting = 15; // Bitfield, 1=buzz 2=beep 4=blink
|
||||
|
||||
enum NotificationImportanceExplanation {
|
||||
IMPORTANCE_EXPLANATION_UNKNOWN = 0;
|
||||
@@ -3507,12 +3505,12 @@ message NotificationReported {
|
||||
IMPORTANCE_EXPLANATION_APP_PRE_CHANNELS = 5;
|
||||
}
|
||||
|
||||
optional NotificationImportanceExplanation importance_source = 17;
|
||||
optional android.stats.sysui.NotificationImportance importance_initial = 18;
|
||||
optional NotificationImportanceExplanation importance_initial_source = 19;
|
||||
optional android.stats.sysui.NotificationImportance importance_asst = 20;
|
||||
optional int32 assistant_hash = 21;
|
||||
optional float assistant_ranking_score = 22;
|
||||
optional NotificationImportanceExplanation importance_source = 16;
|
||||
optional android.stats.sysui.NotificationImportance importance_initial = 17;
|
||||
optional NotificationImportanceExplanation importance_initial_source = 18;
|
||||
optional android.stats.sysui.NotificationImportance importance_asst = 19;
|
||||
optional int32 assistant_hash = 20;
|
||||
optional float assistant_ranking_score = 21;
|
||||
}
|
||||
|
||||
message Notification {
|
||||
|
||||
@@ -27,6 +27,7 @@ import android.os.Bundle;
|
||||
import android.service.notification.NotificationListenerService;
|
||||
import android.service.notification.NotificationStats;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.logging.UiEvent;
|
||||
import com.android.internal.logging.UiEventLogger;
|
||||
|
||||
@@ -266,5 +267,39 @@ public interface NotificationRecordLogger {
|
||||
int getInstanceId() {
|
||||
return (r.getSbn().getInstanceId() == null ? 0 : r.getSbn().getInstanceId().getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Small hash of the notification ID, and tag (if present).
|
||||
*/
|
||||
int getNotificationIdHash() {
|
||||
return smallHash(Objects.hashCode(r.getSbn().getTag()) ^ r.getSbn().getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Small hash of the channel ID, if present, or 0 otherwise.
|
||||
*/
|
||||
int getChannelIdHash() {
|
||||
return smallHash(Objects.hashCode(r.getSbn().getNotification().getChannelId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Small hash of the group ID, respecting group override if present. 0 otherwise.
|
||||
*/
|
||||
int getGroupIdHash() {
|
||||
return smallHash(Objects.hashCode(r.getSbn().getGroup()));
|
||||
}
|
||||
|
||||
// "Small" hashes will be in the range [0, MAX_HASH).
|
||||
static final int MAX_HASH = (1 << 13);
|
||||
|
||||
/**
|
||||
* Maps in to the range [0, MAX_HASH), keeping similar values distinct.
|
||||
* @param in An arbitrary integer.
|
||||
* @return in mod MAX_HASH, signs chosen to stay in the range [0, MAX_HASH).
|
||||
*/
|
||||
@VisibleForTesting
|
||||
static int smallHash(int in) {
|
||||
return Math.floorMod(in, MAX_HASH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,28 +40,27 @@ public class NotificationRecordLoggerImpl implements NotificationRecordLogger {
|
||||
/* int32 uid = 2 */ r.getUid(),
|
||||
/* string package_name = 3 */ r.getSbn().getPackageName(),
|
||||
/* int32 instance_id = 4 */ p.getInstanceId(),
|
||||
/* int32 notification_id = 5 */ r.getSbn().getId(),
|
||||
/* string notification_tag = 6 */ r.getSbn().getTag(),
|
||||
/* string channel_id = 7 */ r.getSbn().getChannelIdLogTag(),
|
||||
/* string group_id = 8 */ r.getSbn().getGroupLogTag(),
|
||||
/* int32 group_instance_id = 9 */ 0, // TODO generate and fill instance ids
|
||||
/* bool is_group_summary = 10 */ r.getSbn().getNotification().isGroupSummary(),
|
||||
/* string category = 11 */ r.getSbn().getNotification().category,
|
||||
/* int32 style = 12 */ p.getStyle(),
|
||||
/* int32 num_people = 13 */ p.getNumPeople(),
|
||||
/* int32 position = 14 */ position,
|
||||
/* android.stats.sysui.NotificationImportance importance = 15 */ r.getImportance(),
|
||||
/* int32 alerting = 16 */ buzzBeepBlink,
|
||||
/* NotificationImportanceExplanation importance_source = 17 */
|
||||
/* int32 notification_id_hash = 5 */ p.getNotificationIdHash(),
|
||||
/* int32 channel_id_hash = 6 */ p.getChannelIdHash(),
|
||||
/* string group_id_hash = 7 */ p.getGroupIdHash(),
|
||||
/* int32 group_instance_id = 8 */ 0, // TODO generate and fill instance ids
|
||||
/* bool is_group_summary = 9 */ r.getSbn().getNotification().isGroupSummary(),
|
||||
/* string category = 10 */ r.getSbn().getNotification().category,
|
||||
/* int32 style = 11 */ p.getStyle(),
|
||||
/* int32 num_people = 12 */ p.getNumPeople(),
|
||||
/* int32 position = 13 */ position,
|
||||
/* android.stats.sysui.NotificationImportance importance = 14 */ r.getImportance(),
|
||||
/* int32 alerting = 15 */ buzzBeepBlink,
|
||||
/* NotificationImportanceExplanation importance_source = 16 */
|
||||
r.getImportanceExplanationCode(),
|
||||
/* android.stats.sysui.NotificationImportance importance_initial = 18 */
|
||||
/* android.stats.sysui.NotificationImportance importance_initial = 17 */
|
||||
r.getInitialImportance(),
|
||||
/* NotificationImportanceExplanation importance_initial_source = 19 */
|
||||
/* NotificationImportanceExplanation importance_initial_source = 18 */
|
||||
r.getInitialImportanceExplanationCode(),
|
||||
/* android.stats.sysui.NotificationImportance importance_asst = 20 */
|
||||
/* android.stats.sysui.NotificationImportance importance_asst = 19 */
|
||||
r.getAssistantImportance(),
|
||||
/* int32 assistant_hash = 21 */ p.getAssistantHash(),
|
||||
/* float assistant_ranking_score = 22 */ 0 // TODO connect up ranking score
|
||||
/* int32 assistant_hash = 20 */ p.getAssistantHash(),
|
||||
/* float assistant_ranking_score = 21 */ 0 // TODO connect up ranking score
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (C) 2020 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.app.NotificationManager.IMPORTANCE_DEFAULT;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.os.UserHandle;
|
||||
import android.service.notification.StatusBarNotification;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.server.UiServiceTestCase;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class NotificationRecordLoggerTest extends UiServiceTestCase {
|
||||
private static final int UID = 9999;
|
||||
private static final String CHANNEL_ID = "NotificationRecordLoggerTestChannelId";
|
||||
|
||||
private NotificationRecord getNotification(int id, String tag) {
|
||||
final String packageName = mContext.getPackageName();
|
||||
NotificationChannel channel = new NotificationChannel(
|
||||
CHANNEL_ID, CHANNEL_ID, IMPORTANCE_DEFAULT);
|
||||
Notification.Builder nb = new Notification.Builder(mContext, channel.getId());
|
||||
StatusBarNotification sbn = new StatusBarNotification(packageName, packageName, id, tag,
|
||||
UID, 0, nb.build(), new UserHandle(UID), null,
|
||||
0);
|
||||
return new NotificationRecord(mContext, sbn, channel);
|
||||
}
|
||||
|
||||
private NotificationRecordLogger.NotificationRecordPair getNotificationRecordPair(int id,
|
||||
String tag) {
|
||||
return new NotificationRecordLogger.NotificationRecordPair(getNotification(id, tag),
|
||||
null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSmallHash() {
|
||||
assertEquals(0, NotificationRecordLogger.NotificationRecordPair.smallHash(0));
|
||||
final int maxHash = NotificationRecordLogger.NotificationRecordPair.MAX_HASH;
|
||||
assertEquals(0,
|
||||
NotificationRecordLogger.NotificationRecordPair.smallHash(maxHash));
|
||||
assertEquals(0,
|
||||
NotificationRecordLogger.NotificationRecordPair.smallHash(17 * maxHash));
|
||||
assertEquals(maxHash - 1,
|
||||
NotificationRecordLogger.NotificationRecordPair.smallHash(maxHash - 1));
|
||||
assertEquals(maxHash - 1,
|
||||
NotificationRecordLogger.NotificationRecordPair.smallHash(-1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetNotificationIdHash() {
|
||||
assertEquals(0,
|
||||
getNotificationRecordPair(0, null).getNotificationIdHash());
|
||||
assertEquals(1,
|
||||
getNotificationRecordPair(1, null).getNotificationIdHash());
|
||||
assertEquals(NotificationRecordLogger.NotificationRecordPair.MAX_HASH - 1,
|
||||
getNotificationRecordPair(-1, null).getNotificationIdHash());
|
||||
final String tag = "someTag";
|
||||
final int hash = NotificationRecordLogger.NotificationRecordPair.smallHash(tag.hashCode());
|
||||
assertEquals(hash, getNotificationRecordPair(0, tag).getNotificationIdHash());
|
||||
// We xor the tag and hashcode together before compressing the range. The order of
|
||||
// operations doesn't matter if id is small.
|
||||
assertEquals(1 ^ hash,
|
||||
getNotificationRecordPair(1, tag).getNotificationIdHash());
|
||||
// But it does matter for an id with more 1 bits than fit in the small hash.
|
||||
assertEquals(
|
||||
NotificationRecordLogger.NotificationRecordPair.smallHash(-1 ^ tag.hashCode()),
|
||||
getNotificationRecordPair(-1, tag).getNotificationIdHash());
|
||||
assertNotEquals(-1 ^ hash,
|
||||
NotificationRecordLogger.NotificationRecordPair.smallHash(-1 ^ tag.hashCode()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetChannelIdHash() {
|
||||
assertEquals(
|
||||
NotificationRecordLogger.NotificationRecordPair.smallHash(CHANNEL_ID.hashCode()),
|
||||
getNotificationRecordPair(0, null).getChannelIdHash());
|
||||
assertNotEquals(
|
||||
NotificationRecordLogger.NotificationRecordPair.smallHash(CHANNEL_ID.hashCode()),
|
||||
CHANNEL_ID.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetGroupIdHash() {
|
||||
NotificationRecordLogger.NotificationRecordPair p = getNotificationRecordPair(
|
||||
0, null);
|
||||
assertEquals(0, p.getGroupIdHash());
|
||||
final String group = "someGroup";
|
||||
p.r.setOverrideGroupKey(group);
|
||||
assertEquals(
|
||||
NotificationRecordLogger.NotificationRecordPair.smallHash(group.hashCode()),
|
||||
p.getGroupIdHash());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user