Add some recent broadcast and notification events to the dumpsys.

Bug: 197654954
Test: manual
Change-Id: I5a67894c38253711d1eac98ee7bdb32545f5908c
This commit is contained in:
Sudheer Shanka
2022-02-23 11:17:41 +00:00
parent 98e13945e0
commit 1ce3e3fa31
2 changed files with 244 additions and 49 deletions

View File

@@ -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<T extends Data> extends RingBuffer<T> {
LogBuffer(Class<T> 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();
}
}

View File

@@ -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<BroadcastEvent> 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();