From 1ce3e3fa313d1439071c40c916df92ef6bd13419 Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Wed, 23 Feb 2022 11:17:41 +0000 Subject: [PATCH] Add some recent broadcast and notification events to the dumpsys. Bug: 197654954 Test: manual Change-Id: I5a67894c38253711d1eac98ee7bdb32545f5908c --- .../usage/BroadcastResponseStatsLogger.java | 221 ++++++++++++++++++ .../usage/BroadcastResponseStatsTracker.java | 72 ++---- 2 files changed, 244 insertions(+), 49 deletions(-) create mode 100644 services/usage/java/com/android/server/usage/BroadcastResponseStatsLogger.java diff --git a/services/usage/java/com/android/server/usage/BroadcastResponseStatsLogger.java b/services/usage/java/com/android/server/usage/BroadcastResponseStatsLogger.java new file mode 100644 index 0000000000000..bfc17713b6a81 --- /dev/null +++ b/services/usage/java/com/android/server/usage/BroadcastResponseStatsLogger.java @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2022 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.usage; + +import static android.app.ActivityManager.procStateToString; + +import static com.android.server.usage.BroadcastResponseStatsTracker.NOTIFICATION_EVENT_TYPE_CANCELLED; +import static com.android.server.usage.BroadcastResponseStatsTracker.NOTIFICATION_EVENT_TYPE_POSTED; +import static com.android.server.usage.BroadcastResponseStatsTracker.NOTIFICATION_EVENT_TYPE_UPDATED; +import static com.android.server.usage.BroadcastResponseStatsTracker.TAG; +import static com.android.server.usage.UsageStatsService.DEBUG_RESPONSE_STATS; + +import android.annotation.ElapsedRealtimeLong; +import android.annotation.NonNull; +import android.annotation.UserIdInt; +import android.app.ActivityManager; +import android.app.ActivityManager.ProcessState; +import android.os.UserHandle; +import android.text.TextUtils; +import android.util.Slog; +import android.util.TimeUtils; + +import com.android.internal.annotations.GuardedBy; +import com.android.internal.util.IndentingPrintWriter; +import com.android.internal.util.RingBuffer; +import com.android.server.usage.BroadcastResponseStatsTracker.NotificationEventType; + +public class BroadcastResponseStatsLogger { + + private static final int MAX_LOG_SIZE = + ActivityManager.isLowRamDeviceStatic() ? 20 : 50; + + private final Object mLock = new Object(); + + @GuardedBy("mLock") + private final LogBuffer mBroadcastEventsBuffer = new LogBuffer( + BroadcastEvent.class, MAX_LOG_SIZE); + @GuardedBy("mLock") + private final LogBuffer mNotificationEventsBuffer = new LogBuffer( + NotificationEvent.class, MAX_LOG_SIZE); + + void logBroadcastDispatchEvent(int sourceUid, @NonNull String targetPackage, + UserHandle targetUser, long idForResponseEvent, + @ElapsedRealtimeLong long timeStampMs, @ProcessState int targetUidProcessState) { + synchronized (mLock) { + if (DEBUG_RESPONSE_STATS) { + Slog.d(TAG, getBroadcastDispatchEventLog(sourceUid, targetPackage, + targetUser.getIdentifier(), idForResponseEvent, timeStampMs, + targetUidProcessState)); + } + mBroadcastEventsBuffer.logBroadcastDispatchEvent(sourceUid, targetPackage, + targetUser, idForResponseEvent, timeStampMs, targetUidProcessState); + } + } + + void logNotificationEvent(@NotificationEventType int event, + @NonNull String packageName, UserHandle user, @ElapsedRealtimeLong long timestampMs) { + synchronized (mLock) { + if (DEBUG_RESPONSE_STATS) { + Slog.d(TAG, getNotificationEventLog(event, packageName, user.getIdentifier(), + timestampMs)); + } + mNotificationEventsBuffer.logNotificationEvent(event, packageName, user, timestampMs); + } + } + + void dumpLogs(IndentingPrintWriter ipw) { + synchronized (mLock) { + ipw.println("Broadcast events (most recent first):"); + ipw.increaseIndent(); + mBroadcastEventsBuffer.reverseDump(ipw); + ipw.decreaseIndent(); + + ipw.println(); + ipw.println("Notification events (most recent first):"); + ipw.increaseIndent(); + mNotificationEventsBuffer.reverseDump(ipw); + ipw.decreaseIndent(); + } + } + + private static final class LogBuffer extends RingBuffer { + + LogBuffer(Class classType, int capacity) { + super(classType, capacity); + } + + void logBroadcastDispatchEvent(int sourceUid, @NonNull String targetPackage, + UserHandle targetUser, long idForResponseEvent, + @ElapsedRealtimeLong long timeStampMs, @ProcessState int targetUidProcessState) { + final Data data = getNextSlot(); + if (data == null) return; + + data.reset(); + final BroadcastEvent event = (BroadcastEvent) data; + event.sourceUid = sourceUid; + event.targetUserId = targetUser.getIdentifier(); + event.targetUidProcessState = targetUidProcessState; + event.targetPackage = targetPackage; + event.idForResponseEvent = idForResponseEvent; + event.timestampMs = timeStampMs; + } + + void logNotificationEvent(@NotificationEventType int type, + @NonNull String packageName, UserHandle user, + @ElapsedRealtimeLong long timestampMs) { + final Data data = getNextSlot(); + if (data == null) return; + + data.reset(); + final NotificationEvent event = (NotificationEvent) data; + event.type = type; + event.packageName = packageName; + event.userId = user.getIdentifier(); + event.timestampMs = timestampMs; + } + + public void reverseDump(IndentingPrintWriter pw) { + final Data[] allData = toArray(); + for (int i = allData.length - 1; i >= 0; --i) { + if (allData[i] == null) { + continue; + } + pw.println(getContent(allData[i])); + } + } + + @NonNull + public String getContent(Data data) { + return data.toString(); + } + } + + @NonNull + private static String getBroadcastDispatchEventLog(int sourceUid, @NonNull String targetPackage, + @UserIdInt int targetUserId, long idForResponseEvent, + @ElapsedRealtimeLong long timestampMs, @ProcessState int targetUidProcState) { + return TextUtils.formatSimple( + "broadcast:%s; srcUid=%d, tgtPkg=%s, tgtUsr=%d, id=%d, state=%s", + TimeUtils.formatDuration(timestampMs), sourceUid, targetPackage, targetUserId, + idForResponseEvent, procStateToString(targetUidProcState)); + } + + @NonNull + private static String getNotificationEventLog(@NotificationEventType int event, + @NonNull String packageName, @UserIdInt int userId, + @ElapsedRealtimeLong long timestampMs) { + return TextUtils.formatSimple("notification:%s; event=<%s>, pkg=%s, usr=%d", + TimeUtils.formatDuration(timestampMs), notificationEventToString(event), + packageName, userId); + } + + @NonNull + private static String notificationEventToString(@NotificationEventType int event) { + switch (event) { + case NOTIFICATION_EVENT_TYPE_POSTED: + return "posted"; + case NOTIFICATION_EVENT_TYPE_UPDATED: + return "updated"; + case NOTIFICATION_EVENT_TYPE_CANCELLED: + return "cancelled"; + default: + return String.valueOf(event); + } + } + + public static final class BroadcastEvent implements Data { + public int sourceUid; + public int targetUserId; + public int targetUidProcessState; + public String targetPackage; + public long idForResponseEvent; + public long timestampMs; + + @Override + public void reset() { + targetPackage = null; + } + + @Override + public String toString() { + return getBroadcastDispatchEventLog(sourceUid, targetPackage, targetUserId, + idForResponseEvent, timestampMs, targetUidProcessState); + } + } + + public static final class NotificationEvent implements Data { + public int type; + public String packageName; + public int userId; + public long timestampMs; + + @Override + public void reset() { + packageName = null; + } + + @Override + public String toString() { + return getNotificationEventLog(type, packageName, userId, timestampMs); + } + } + + public interface Data { + void reset(); + } +} diff --git a/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java b/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java index ab8f69b121a0d..76d2fe7917fc5 100644 --- a/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java +++ b/services/usage/java/com/android/server/usage/BroadcastResponseStatsTracker.java @@ -16,10 +16,6 @@ package com.android.server.usage; -import static android.app.ActivityManager.procStateToString; - -import static com.android.server.usage.UsageStatsService.DEBUG_RESPONSE_STATS; - import android.annotation.ElapsedRealtimeLong; import android.annotation.IntDef; import android.annotation.IntRange; @@ -29,11 +25,9 @@ import android.annotation.UserIdInt; import android.app.ActivityManager.ProcessState; import android.app.usage.BroadcastResponseStats; import android.os.UserHandle; -import android.text.TextUtils; import android.util.LongSparseArray; import android.util.Slog; import android.util.SparseArray; -import android.util.TimeUtils; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; @@ -44,19 +38,19 @@ import java.util.ArrayList; import java.util.List; class BroadcastResponseStatsTracker { - private static final String TAG = "ResponseStatsTracker"; + static final String TAG = "ResponseStatsTracker"; @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = {"NOTIFICATION_EVENT"}, value = { - NOTIFICATION_EVENT_POSTED, - NOTIFICATION_EVENT_UPDATED, - NOTIFICATION_EVENT_CANCELLED + @IntDef(prefix = {"NOTIFICATION_EVENT_TYPE_"}, value = { + NOTIFICATION_EVENT_TYPE_POSTED, + NOTIFICATION_EVENT_TYPE_UPDATED, + NOTIFICATION_EVENT_TYPE_CANCELLED }) - public @interface NotificationEvent {} + public @interface NotificationEventType {} - private static final int NOTIFICATION_EVENT_POSTED = 0; - private static final int NOTIFICATION_EVENT_UPDATED = 1; - private static final int NOTIFICATION_EVENT_CANCELLED = 2; + static final int NOTIFICATION_EVENT_TYPE_POSTED = 0; + static final int NOTIFICATION_EVENT_TYPE_UPDATED = 1; + static final int NOTIFICATION_EVENT_TYPE_CANCELLED = 2; private final Object mLock = new Object(); @@ -76,21 +70,19 @@ class BroadcastResponseStatsTracker { new SparseArray<>(); private AppStandbyInternal mAppStandby; + private BroadcastResponseStatsLogger mLogger; BroadcastResponseStatsTracker(@NonNull AppStandbyInternal appStandby) { mAppStandby = appStandby; + mLogger = new BroadcastResponseStatsLogger(); } // TODO (206518114): Move all callbacks handling to a handler thread. void reportBroadcastDispatchEvent(int sourceUid, @NonNull String targetPackage, UserHandle targetUser, long idForResponseEvent, @ElapsedRealtimeLong long timestampMs, @ProcessState int targetUidProcState) { - if (DEBUG_RESPONSE_STATS) { - Slog.d(TAG, TextUtils.formatSimple("reportBroadcastDispatchEvent; " - + "srcUid=%d, tgtPkg=%s, tgtUsr=%d, id=%d, ts=%s, state=%s", - sourceUid, targetPackage, targetUser, idForResponseEvent, - TimeUtils.formatDuration(timestampMs), procStateToString(targetUidProcState))); - } + mLogger.logBroadcastDispatchEvent(sourceUid, targetPackage, targetUser, + idForResponseEvent, timestampMs, targetUidProcState); if (targetUidProcState <= mAppStandby.getBroadcastResponseFgThresholdState()) { // No need to track the broadcast response state while the target app is // in the foreground. @@ -110,29 +102,23 @@ class BroadcastResponseStatsTracker { void reportNotificationPosted(@NonNull String packageName, UserHandle user, @ElapsedRealtimeLong long timestampMs) { - reportNotificationEvent(NOTIFICATION_EVENT_POSTED, packageName, user, timestampMs); + reportNotificationEvent(NOTIFICATION_EVENT_TYPE_POSTED, packageName, user, timestampMs); } void reportNotificationUpdated(@NonNull String packageName, UserHandle user, @ElapsedRealtimeLong long timestampMs) { - reportNotificationEvent(NOTIFICATION_EVENT_UPDATED, packageName, user, timestampMs); + reportNotificationEvent(NOTIFICATION_EVENT_TYPE_UPDATED, packageName, user, timestampMs); } void reportNotificationCancelled(@NonNull String packageName, UserHandle user, @ElapsedRealtimeLong long timestampMs) { - reportNotificationEvent(NOTIFICATION_EVENT_CANCELLED, packageName, user, timestampMs); + reportNotificationEvent(NOTIFICATION_EVENT_TYPE_CANCELLED, packageName, user, timestampMs); } - private void reportNotificationEvent(@NotificationEvent int event, + private void reportNotificationEvent(@NotificationEventType int event, @NonNull String packageName, UserHandle user, @ElapsedRealtimeLong long timestampMs) { - if (DEBUG_RESPONSE_STATS) { - Slog.d(TAG, TextUtils.formatSimple( - "reportNotificationEvent; event=<%s>, pkg=%s, usr=%d, ts=%s", - notificationEventToString(event), packageName, user.getIdentifier(), - TimeUtils.formatDuration(timestampMs))); - } - // TODO (206518114): Store last N events to dump for debugging purposes. + mLogger.logNotificationEvent(event, packageName, user, timestampMs); synchronized (mLock) { final LongSparseArray broadcastEvents = getBroadcastEventsLocked(packageName, user); @@ -157,13 +143,13 @@ class BroadcastResponseStatsTracker { continue; } switch (event) { - case NOTIFICATION_EVENT_POSTED: + case NOTIFICATION_EVENT_TYPE_POSTED: responseStats.incrementNotificationsPostedCount(1); break; - case NOTIFICATION_EVENT_UPDATED: + case NOTIFICATION_EVENT_TYPE_UPDATED: responseStats.incrementNotificationsUpdatedCount(1); break; - case NOTIFICATION_EVENT_CANCELLED: + case NOTIFICATION_EVENT_TYPE_CANCELLED: responseStats.incrementNotificationsCancelledCount(1); break; default: @@ -329,20 +315,6 @@ class BroadcastResponseStatsTracker { return userResponseStats.getOrCreateBroadcastResponseStats(broadcastEvent); } - @NonNull - private String notificationEventToString(@NotificationEvent int event) { - switch (event) { - case NOTIFICATION_EVENT_POSTED: - return "posted"; - case NOTIFICATION_EVENT_UPDATED: - return "updated"; - case NOTIFICATION_EVENT_CANCELLED: - return "cancelled"; - default: - return String.valueOf(event); - } - } - void dump(@NonNull IndentingPrintWriter ipw) { ipw.println("Broadcast response stats:"); ipw.increaseIndent(); @@ -351,6 +323,8 @@ class BroadcastResponseStatsTracker { dumpBroadcastEventsLocked(ipw); ipw.println(); dumpResponseStatsLocked(ipw); + ipw.println(); + mLogger.dumpLogs(ipw); } ipw.decreaseIndent();