Fix mistake in Notification Memory Use logging am: 7ba2e52a61
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/21445386 Change-Id: Ic807406bd9d9ca5e587fee44fc00574fb8bf2a0e Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -20,6 +20,7 @@ package com.android.systemui.statusbar.notification.logging
|
||||
import android.app.StatsManager
|
||||
import android.util.Log
|
||||
import android.util.StatsEvent
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.dagger.qualifiers.Background
|
||||
import com.android.systemui.dagger.qualifiers.Main
|
||||
@@ -143,67 +144,70 @@ constructor(
|
||||
runBlocking(mainDispatcher) {
|
||||
traceSection("NML#getNotifications") { notificationPipeline.allNotifs }
|
||||
}
|
||||
|
||||
/** Aggregates memory usage data by package and style, returning sums. */
|
||||
private fun aggregateMemoryUsageData(
|
||||
notificationMemoryUse: List<NotificationMemoryUsage>
|
||||
): Map<Pair<String, Int>, NotificationMemoryUseAtomBuilder> {
|
||||
return notificationMemoryUse
|
||||
.groupingBy { Pair(it.packageName, it.objectUsage.style) }
|
||||
.aggregate {
|
||||
_,
|
||||
accumulator: NotificationMemoryUseAtomBuilder?,
|
||||
element: NotificationMemoryUsage,
|
||||
first ->
|
||||
val use =
|
||||
if (first) {
|
||||
NotificationMemoryUseAtomBuilder(element.uid, element.objectUsage.style)
|
||||
} else {
|
||||
accumulator!!
|
||||
}
|
||||
|
||||
use.count++
|
||||
// If the views of the notification weren't inflated, the list of memory usage
|
||||
// parameters will be empty.
|
||||
if (element.viewUsage.isNotEmpty()) {
|
||||
use.countWithInflatedViews++
|
||||
}
|
||||
|
||||
use.smallIconObject += element.objectUsage.smallIcon
|
||||
if (element.objectUsage.smallIcon > 0) {
|
||||
use.smallIconBitmapCount++
|
||||
}
|
||||
|
||||
use.largeIconObject += element.objectUsage.largeIcon
|
||||
if (element.objectUsage.largeIcon > 0) {
|
||||
use.largeIconBitmapCount++
|
||||
}
|
||||
|
||||
use.bigPictureObject += element.objectUsage.bigPicture
|
||||
if (element.objectUsage.bigPicture > 0) {
|
||||
use.bigPictureBitmapCount++
|
||||
}
|
||||
|
||||
use.extras += element.objectUsage.extras
|
||||
use.extenders += element.objectUsage.extender
|
||||
|
||||
// Use totals count which are more accurate when aggregated
|
||||
// in this manner.
|
||||
element.viewUsage
|
||||
.firstOrNull { vu -> vu.viewType == ViewType.TOTAL }
|
||||
?.let {
|
||||
use.smallIconViews += it.smallIcon
|
||||
use.largeIconViews += it.largeIcon
|
||||
use.systemIconViews += it.systemIcons
|
||||
use.styleViews += it.style
|
||||
use.customViews += it.style
|
||||
use.softwareBitmaps += it.softwareBitmapsPenalty
|
||||
}
|
||||
|
||||
return@aggregate use
|
||||
}
|
||||
}
|
||||
|
||||
/** Rounds the passed value to the nearest KB - e.g. 700B rounds to 1KB. */
|
||||
private fun toKb(value: Int): Int = (value.toFloat() / 1024f).roundToInt()
|
||||
}
|
||||
|
||||
/** Aggregates memory usage data by package and style, returning sums. */
|
||||
@VisibleForTesting
|
||||
internal fun aggregateMemoryUsageData(
|
||||
notificationMemoryUse: List<NotificationMemoryUsage>
|
||||
): Map<Pair<String, Int>, NotificationMemoryLogger.NotificationMemoryUseAtomBuilder> {
|
||||
return notificationMemoryUse
|
||||
.groupingBy { Pair(it.packageName, it.objectUsage.style) }
|
||||
.aggregate {
|
||||
_,
|
||||
accumulator: NotificationMemoryLogger.NotificationMemoryUseAtomBuilder?,
|
||||
element: NotificationMemoryUsage,
|
||||
first ->
|
||||
val use =
|
||||
if (first) {
|
||||
NotificationMemoryLogger.NotificationMemoryUseAtomBuilder(
|
||||
element.uid,
|
||||
element.objectUsage.style
|
||||
)
|
||||
} else {
|
||||
accumulator!!
|
||||
}
|
||||
|
||||
use.count++
|
||||
// If the views of the notification weren't inflated, the list of memory usage
|
||||
// parameters will be empty.
|
||||
if (element.viewUsage.isNotEmpty()) {
|
||||
use.countWithInflatedViews++
|
||||
}
|
||||
|
||||
use.smallIconObject += element.objectUsage.smallIcon
|
||||
if (element.objectUsage.smallIcon > 0) {
|
||||
use.smallIconBitmapCount++
|
||||
}
|
||||
|
||||
use.largeIconObject += element.objectUsage.largeIcon
|
||||
if (element.objectUsage.largeIcon > 0) {
|
||||
use.largeIconBitmapCount++
|
||||
}
|
||||
|
||||
use.bigPictureObject += element.objectUsage.bigPicture
|
||||
if (element.objectUsage.bigPicture > 0) {
|
||||
use.bigPictureBitmapCount++
|
||||
}
|
||||
|
||||
use.extras += element.objectUsage.extras
|
||||
use.extenders += element.objectUsage.extender
|
||||
|
||||
// Use totals count which are more accurate when aggregated
|
||||
// in this manner.
|
||||
element.viewUsage
|
||||
.firstOrNull { vu -> vu.viewType == ViewType.TOTAL }
|
||||
?.let {
|
||||
use.smallIconViews += it.smallIcon
|
||||
use.largeIconViews += it.largeIcon
|
||||
use.systemIconViews += it.systemIcons
|
||||
use.styleViews += it.style
|
||||
use.customViews += it.customViews
|
||||
use.softwareBitmaps += it.softwareBitmapsPenalty
|
||||
}
|
||||
|
||||
return@aggregate use
|
||||
}
|
||||
}
|
||||
/** Rounds the passed value to the nearest KB - e.g. 700B rounds to 1KB. */
|
||||
private fun toKb(value: Int): Int = (value.toFloat() / 1024f).roundToInt()
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.app.Notification
|
||||
import android.app.StatsManager
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.drawable.Icon
|
||||
import android.stats.sysui.NotificationEnums
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.util.StatsEvent
|
||||
import androidx.test.filters.SmallTest
|
||||
@@ -31,10 +32,12 @@ import com.android.systemui.util.concurrency.FakeExecutor
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
import com.android.systemui.util.time.FakeSystemClock
|
||||
import com.google.common.truth.Expect
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import java.lang.RuntimeException
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
@@ -45,6 +48,8 @@ import org.mockito.MockitoAnnotations
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
class NotificationMemoryLoggerTest : SysuiTestCase() {
|
||||
|
||||
@Rule @JvmField val expect = Expect.create()
|
||||
|
||||
private val bgExecutor = FakeExecutor(FakeSystemClock())
|
||||
private val immediate = Dispatchers.Main.immediate
|
||||
|
||||
@@ -132,6 +137,123 @@ class NotificationMemoryLoggerTest : SysuiTestCase() {
|
||||
.isEqualTo(StatsManager.PULL_SKIP)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aggregateMemoryUsageData_returnsCorrectlyAggregatedSamePackageData() {
|
||||
val usage = getPresetMemoryUsages()
|
||||
val aggregateUsage = aggregateMemoryUsageData(usage)
|
||||
|
||||
assertThat(aggregateUsage).hasSize(3)
|
||||
assertThat(aggregateUsage)
|
||||
.containsKey(Pair("package 1", NotificationEnums.STYLE_BIG_PICTURE))
|
||||
|
||||
// Aggregated fields
|
||||
val aggregatedData =
|
||||
aggregateUsage[Pair("package 1", NotificationEnums.STYLE_BIG_PICTURE)]!!
|
||||
val presetUsage1 = usage[0]
|
||||
val presetUsage2 = usage[1]
|
||||
assertAggregatedData(
|
||||
aggregatedData,
|
||||
2,
|
||||
2,
|
||||
smallIconObject =
|
||||
presetUsage1.objectUsage.smallIcon + presetUsage2.objectUsage.smallIcon,
|
||||
smallIconBitmapCount = 2,
|
||||
largeIconObject =
|
||||
presetUsage1.objectUsage.largeIcon + presetUsage2.objectUsage.largeIcon,
|
||||
largeIconBitmapCount = 2,
|
||||
bigPictureObject =
|
||||
presetUsage1.objectUsage.bigPicture + presetUsage2.objectUsage.bigPicture,
|
||||
bigPictureBitmapCount = 2,
|
||||
extras = presetUsage1.objectUsage.extras + presetUsage2.objectUsage.extras,
|
||||
extenders = presetUsage1.objectUsage.extender + presetUsage2.objectUsage.extender,
|
||||
// Only totals need to be summarized.
|
||||
smallIconViews =
|
||||
presetUsage1.viewUsage[0].smallIcon + presetUsage2.viewUsage[0].smallIcon,
|
||||
largeIconViews =
|
||||
presetUsage1.viewUsage[0].largeIcon + presetUsage2.viewUsage[0].largeIcon,
|
||||
systemIconViews =
|
||||
presetUsage1.viewUsage[0].systemIcons + presetUsage2.viewUsage[0].systemIcons,
|
||||
styleViews = presetUsage1.viewUsage[0].style + presetUsage2.viewUsage[0].style,
|
||||
customViews =
|
||||
presetUsage1.viewUsage[0].customViews + presetUsage2.viewUsage[0].customViews,
|
||||
softwareBitmaps =
|
||||
presetUsage1.viewUsage[0].softwareBitmapsPenalty +
|
||||
presetUsage2.viewUsage[0].softwareBitmapsPenalty,
|
||||
seenCount = 0
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aggregateMemoryUsageData_correctlySeparatesDifferentStyles() {
|
||||
val usage = getPresetMemoryUsages()
|
||||
val aggregateUsage = aggregateMemoryUsageData(usage)
|
||||
|
||||
assertThat(aggregateUsage).hasSize(3)
|
||||
assertThat(aggregateUsage)
|
||||
.containsKey(Pair("package 1", NotificationEnums.STYLE_BIG_PICTURE))
|
||||
assertThat(aggregateUsage).containsKey(Pair("package 1", NotificationEnums.STYLE_BIG_TEXT))
|
||||
|
||||
// Different style should be separate
|
||||
val separateStyleData =
|
||||
aggregateUsage[Pair("package 1", NotificationEnums.STYLE_BIG_TEXT)]!!
|
||||
val presetUsage = usage[2]
|
||||
assertAggregatedData(
|
||||
separateStyleData,
|
||||
1,
|
||||
1,
|
||||
presetUsage.objectUsage.smallIcon,
|
||||
1,
|
||||
presetUsage.objectUsage.largeIcon,
|
||||
1,
|
||||
presetUsage.objectUsage.bigPicture,
|
||||
1,
|
||||
presetUsage.objectUsage.extras,
|
||||
presetUsage.objectUsage.extender,
|
||||
presetUsage.viewUsage[0].smallIcon,
|
||||
presetUsage.viewUsage[0].largeIcon,
|
||||
presetUsage.viewUsage[0].systemIcons,
|
||||
presetUsage.viewUsage[0].style,
|
||||
presetUsage.viewUsage[0].customViews,
|
||||
presetUsage.viewUsage[0].softwareBitmapsPenalty,
|
||||
0
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aggregateMemoryUsageData_correctlySeparatesDifferentProcess() {
|
||||
val usage = getPresetMemoryUsages()
|
||||
val aggregateUsage = aggregateMemoryUsageData(usage)
|
||||
|
||||
assertThat(aggregateUsage).hasSize(3)
|
||||
assertThat(aggregateUsage)
|
||||
.containsKey(Pair("package 2", NotificationEnums.STYLE_BIG_PICTURE))
|
||||
|
||||
// Different UID/package should also be separate
|
||||
val separatePackageData =
|
||||
aggregateUsage[Pair("package 2", NotificationEnums.STYLE_BIG_PICTURE)]!!
|
||||
val presetUsage = usage[3]
|
||||
assertAggregatedData(
|
||||
separatePackageData,
|
||||
1,
|
||||
1,
|
||||
presetUsage.objectUsage.smallIcon,
|
||||
1,
|
||||
presetUsage.objectUsage.largeIcon,
|
||||
1,
|
||||
presetUsage.objectUsage.bigPicture,
|
||||
1,
|
||||
presetUsage.objectUsage.extras,
|
||||
presetUsage.objectUsage.extender,
|
||||
presetUsage.viewUsage[0].smallIcon,
|
||||
presetUsage.viewUsage[0].largeIcon,
|
||||
presetUsage.viewUsage[0].systemIcons,
|
||||
presetUsage.viewUsage[0].style,
|
||||
presetUsage.viewUsage[0].customViews,
|
||||
presetUsage.viewUsage[0].softwareBitmapsPenalty,
|
||||
0
|
||||
)
|
||||
}
|
||||
|
||||
private fun createLoggerWithNotifications(
|
||||
notifications: List<Notification>
|
||||
): NotificationMemoryLogger {
|
||||
@@ -143,4 +265,182 @@ class NotificationMemoryLoggerTest : SysuiTestCase() {
|
||||
whenever(pipeline.allNotifs).thenReturn(notifications)
|
||||
return NotificationMemoryLogger(pipeline, statsManager, immediate, bgExecutor)
|
||||
}
|
||||
|
||||
/**
|
||||
* Short hand for making sure the passed NotificationMemoryUseAtomBuilder object contains
|
||||
* expected values.
|
||||
*/
|
||||
private fun assertAggregatedData(
|
||||
value: NotificationMemoryLogger.NotificationMemoryUseAtomBuilder,
|
||||
count: Int,
|
||||
countWithInflatedViews: Int,
|
||||
smallIconObject: Int,
|
||||
smallIconBitmapCount: Int,
|
||||
largeIconObject: Int,
|
||||
largeIconBitmapCount: Int,
|
||||
bigPictureObject: Int,
|
||||
bigPictureBitmapCount: Int,
|
||||
extras: Int,
|
||||
extenders: Int,
|
||||
smallIconViews: Int,
|
||||
largeIconViews: Int,
|
||||
systemIconViews: Int,
|
||||
styleViews: Int,
|
||||
customViews: Int,
|
||||
softwareBitmaps: Int,
|
||||
seenCount: Int
|
||||
) {
|
||||
expect.withMessage("count").that(value.count).isEqualTo(count)
|
||||
expect
|
||||
.withMessage("countWithInflatedViews")
|
||||
.that(value.countWithInflatedViews)
|
||||
.isEqualTo(countWithInflatedViews)
|
||||
expect.withMessage("smallIconObject").that(value.smallIconObject).isEqualTo(smallIconObject)
|
||||
expect
|
||||
.withMessage("smallIconBitmapCount")
|
||||
.that(value.smallIconBitmapCount)
|
||||
.isEqualTo(smallIconBitmapCount)
|
||||
expect.withMessage("largeIconObject").that(value.largeIconObject).isEqualTo(largeIconObject)
|
||||
expect
|
||||
.withMessage("largeIconBitmapCount")
|
||||
.that(value.largeIconBitmapCount)
|
||||
.isEqualTo(largeIconBitmapCount)
|
||||
expect
|
||||
.withMessage("bigPictureObject")
|
||||
.that(value.bigPictureObject)
|
||||
.isEqualTo(bigPictureObject)
|
||||
expect
|
||||
.withMessage("bigPictureBitmapCount")
|
||||
.that(value.bigPictureBitmapCount)
|
||||
.isEqualTo(bigPictureBitmapCount)
|
||||
expect.withMessage("extras").that(value.extras).isEqualTo(extras)
|
||||
expect.withMessage("extenders").that(value.extenders).isEqualTo(extenders)
|
||||
expect.withMessage("smallIconViews").that(value.smallIconViews).isEqualTo(smallIconViews)
|
||||
expect.withMessage("largeIconViews").that(value.largeIconViews).isEqualTo(largeIconViews)
|
||||
expect.withMessage("systemIconViews").that(value.systemIconViews).isEqualTo(systemIconViews)
|
||||
expect.withMessage("styleViews").that(value.styleViews).isEqualTo(styleViews)
|
||||
expect.withMessage("customViews").that(value.customViews).isEqualTo(customViews)
|
||||
expect.withMessage("softwareBitmaps").that(value.softwareBitmaps).isEqualTo(softwareBitmaps)
|
||||
expect.withMessage("seenCount").that(value.seenCount).isEqualTo(seenCount)
|
||||
}
|
||||
|
||||
/** Generates a static set of [NotificationMemoryUsage] objects. */
|
||||
private fun getPresetMemoryUsages() =
|
||||
listOf(
|
||||
// A pair of notifications that have to be aggregated, same UID and style
|
||||
NotificationMemoryUsage(
|
||||
"package 1",
|
||||
384,
|
||||
"key1",
|
||||
Notification.Builder(context).setStyle(Notification.BigPictureStyle()).build(),
|
||||
NotificationObjectUsage(
|
||||
23,
|
||||
45,
|
||||
67,
|
||||
NotificationEnums.STYLE_BIG_PICTURE,
|
||||
12,
|
||||
483,
|
||||
4382,
|
||||
true
|
||||
),
|
||||
listOf(
|
||||
NotificationViewUsage(ViewType.TOTAL, 493, 584, 4833, 584, 4888, 5843),
|
||||
NotificationViewUsage(
|
||||
ViewType.PRIVATE_CONTRACTED_VIEW,
|
||||
100,
|
||||
250,
|
||||
300,
|
||||
594,
|
||||
6000,
|
||||
5843
|
||||
)
|
||||
)
|
||||
),
|
||||
NotificationMemoryUsage(
|
||||
"package 1",
|
||||
384,
|
||||
"key2",
|
||||
Notification.Builder(context).setStyle(Notification.BigPictureStyle()).build(),
|
||||
NotificationObjectUsage(
|
||||
77,
|
||||
54,
|
||||
34,
|
||||
NotificationEnums.STYLE_BIG_PICTURE,
|
||||
77,
|
||||
432,
|
||||
2342,
|
||||
true
|
||||
),
|
||||
listOf(
|
||||
NotificationViewUsage(ViewType.TOTAL, 3245, 1234, 7653, 543, 765, 7655),
|
||||
NotificationViewUsage(
|
||||
ViewType.PRIVATE_CONTRACTED_VIEW,
|
||||
160,
|
||||
350,
|
||||
300,
|
||||
5544,
|
||||
66500,
|
||||
5433
|
||||
)
|
||||
)
|
||||
),
|
||||
// Different style is different aggregation
|
||||
NotificationMemoryUsage(
|
||||
"package 1",
|
||||
384,
|
||||
"key2",
|
||||
Notification.Builder(context).setStyle(Notification.BigTextStyle()).build(),
|
||||
NotificationObjectUsage(
|
||||
77,
|
||||
54,
|
||||
34,
|
||||
NotificationEnums.STYLE_BIG_TEXT,
|
||||
77,
|
||||
432,
|
||||
2342,
|
||||
true
|
||||
),
|
||||
listOf(
|
||||
NotificationViewUsage(ViewType.TOTAL, 3245, 1234, 7653, 543, 765, 7655),
|
||||
NotificationViewUsage(
|
||||
ViewType.PRIVATE_CONTRACTED_VIEW,
|
||||
160,
|
||||
350,
|
||||
300,
|
||||
5544,
|
||||
66500,
|
||||
5433
|
||||
)
|
||||
)
|
||||
),
|
||||
// Different package is also different aggregation
|
||||
NotificationMemoryUsage(
|
||||
"package 2",
|
||||
684,
|
||||
"key2",
|
||||
Notification.Builder(context).setStyle(Notification.BigPictureStyle()).build(),
|
||||
NotificationObjectUsage(
|
||||
32,
|
||||
654,
|
||||
234,
|
||||
NotificationEnums.STYLE_BIG_PICTURE,
|
||||
211,
|
||||
776,
|
||||
435,
|
||||
true
|
||||
),
|
||||
listOf(
|
||||
NotificationViewUsage(ViewType.TOTAL, 4355, 6543, 4322, 5435, 6546, 65485),
|
||||
NotificationViewUsage(
|
||||
ViewType.PRIVATE_CONTRACTED_VIEW,
|
||||
6546,
|
||||
7657,
|
||||
4353,
|
||||
6546,
|
||||
76575,
|
||||
54654
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user