1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.usage; 18 19 import static android.app.ActivityManager.procStateToString; 20 21 import static com.android.server.usage.BroadcastResponseStatsTracker.NOTIFICATION_EVENT_TYPE_CANCELLED; 22 import static com.android.server.usage.BroadcastResponseStatsTracker.NOTIFICATION_EVENT_TYPE_POSTED; 23 import static com.android.server.usage.BroadcastResponseStatsTracker.NOTIFICATION_EVENT_TYPE_UPDATED; 24 import static com.android.server.usage.BroadcastResponseStatsTracker.TAG; 25 import static com.android.server.usage.UsageStatsService.DEBUG_RESPONSE_STATS; 26 27 import android.annotation.ElapsedRealtimeLong; 28 import android.annotation.NonNull; 29 import android.annotation.UserIdInt; 30 import android.app.ActivityManager; 31 import android.app.ActivityManager.ProcessState; 32 import android.os.UserHandle; 33 import android.text.TextUtils; 34 import android.util.Slog; 35 import android.util.TimeUtils; 36 37 import com.android.internal.annotations.GuardedBy; 38 import com.android.internal.util.IndentingPrintWriter; 39 import com.android.internal.util.RingBuffer; 40 import com.android.server.usage.BroadcastResponseStatsTracker.NotificationEventType; 41 42 public class BroadcastResponseStatsLogger { 43 44 private static final int MAX_LOG_SIZE = 45 ActivityManager.isLowRamDeviceStatic() ? 20 : 50; 46 47 private final Object mLock = new Object(); 48 49 @GuardedBy("mLock") 50 private final LogBuffer mBroadcastEventsBuffer = new LogBuffer( 51 BroadcastEvent.class, MAX_LOG_SIZE); 52 @GuardedBy("mLock") 53 private final LogBuffer mNotificationEventsBuffer = new LogBuffer( 54 NotificationEvent.class, MAX_LOG_SIZE); 55 logBroadcastDispatchEvent(int sourceUid, @NonNull String targetPackage, UserHandle targetUser, long idForResponseEvent, @ElapsedRealtimeLong long timeStampMs, @ProcessState int targetUidProcessState)56 void logBroadcastDispatchEvent(int sourceUid, @NonNull String targetPackage, 57 UserHandle targetUser, long idForResponseEvent, 58 @ElapsedRealtimeLong long timeStampMs, @ProcessState int targetUidProcessState) { 59 synchronized (mLock) { 60 if (DEBUG_RESPONSE_STATS) { 61 Slog.d(TAG, getBroadcastDispatchEventLog(sourceUid, targetPackage, 62 targetUser.getIdentifier(), idForResponseEvent, timeStampMs, 63 targetUidProcessState)); 64 } 65 mBroadcastEventsBuffer.logBroadcastDispatchEvent(sourceUid, targetPackage, 66 targetUser, idForResponseEvent, timeStampMs, targetUidProcessState); 67 } 68 } 69 logNotificationEvent(@otificationEventType int event, @NonNull String packageName, UserHandle user, @ElapsedRealtimeLong long timestampMs)70 void logNotificationEvent(@NotificationEventType int event, 71 @NonNull String packageName, UserHandle user, @ElapsedRealtimeLong long timestampMs) { 72 synchronized (mLock) { 73 if (DEBUG_RESPONSE_STATS) { 74 Slog.d(TAG, getNotificationEventLog(event, packageName, user.getIdentifier(), 75 timestampMs)); 76 } 77 mNotificationEventsBuffer.logNotificationEvent(event, packageName, user, timestampMs); 78 } 79 } 80 dumpLogs(IndentingPrintWriter ipw)81 void dumpLogs(IndentingPrintWriter ipw) { 82 synchronized (mLock) { 83 ipw.println("Broadcast events (most recent first):"); 84 ipw.increaseIndent(); 85 mBroadcastEventsBuffer.reverseDump(ipw); 86 ipw.decreaseIndent(); 87 88 ipw.println(); 89 ipw.println("Notification events (most recent first):"); 90 ipw.increaseIndent(); 91 mNotificationEventsBuffer.reverseDump(ipw); 92 ipw.decreaseIndent(); 93 } 94 } 95 96 private static final class LogBuffer<T extends Data> extends RingBuffer<T> { 97 LogBuffer(Class<T> classType, int capacity)98 LogBuffer(Class<T> classType, int capacity) { 99 super(classType, capacity); 100 } 101 logBroadcastDispatchEvent(int sourceUid, @NonNull String targetPackage, UserHandle targetUser, long idForResponseEvent, @ElapsedRealtimeLong long timeStampMs, @ProcessState int targetUidProcessState)102 void logBroadcastDispatchEvent(int sourceUid, @NonNull String targetPackage, 103 UserHandle targetUser, long idForResponseEvent, 104 @ElapsedRealtimeLong long timeStampMs, @ProcessState int targetUidProcessState) { 105 final Data data = getNextSlot(); 106 if (data == null) return; 107 108 data.reset(); 109 final BroadcastEvent event = (BroadcastEvent) data; 110 event.sourceUid = sourceUid; 111 event.targetUserId = targetUser.getIdentifier(); 112 event.targetUidProcessState = targetUidProcessState; 113 event.targetPackage = targetPackage; 114 event.idForResponseEvent = idForResponseEvent; 115 event.timestampMs = timeStampMs; 116 } 117 logNotificationEvent(@otificationEventType int type, @NonNull String packageName, UserHandle user, @ElapsedRealtimeLong long timestampMs)118 void logNotificationEvent(@NotificationEventType int type, 119 @NonNull String packageName, UserHandle user, 120 @ElapsedRealtimeLong long timestampMs) { 121 final Data data = getNextSlot(); 122 if (data == null) return; 123 124 data.reset(); 125 final NotificationEvent event = (NotificationEvent) data; 126 event.type = type; 127 event.packageName = packageName; 128 event.userId = user.getIdentifier(); 129 event.timestampMs = timestampMs; 130 } 131 reverseDump(IndentingPrintWriter pw)132 public void reverseDump(IndentingPrintWriter pw) { 133 final Data[] allData = toArray(); 134 for (int i = allData.length - 1; i >= 0; --i) { 135 if (allData[i] == null) { 136 continue; 137 } 138 pw.println(getContent(allData[i])); 139 } 140 } 141 142 @NonNull getContent(Data data)143 public String getContent(Data data) { 144 return data.toString(); 145 } 146 } 147 148 @NonNull getBroadcastDispatchEventLog(int sourceUid, @NonNull String targetPackage, @UserIdInt int targetUserId, long idForResponseEvent, @ElapsedRealtimeLong long timestampMs, @ProcessState int targetUidProcState)149 private static String getBroadcastDispatchEventLog(int sourceUid, @NonNull String targetPackage, 150 @UserIdInt int targetUserId, long idForResponseEvent, 151 @ElapsedRealtimeLong long timestampMs, @ProcessState int targetUidProcState) { 152 return TextUtils.formatSimple( 153 "broadcast:%s; srcUid=%d, tgtPkg=%s, tgtUsr=%d, id=%d, state=%s", 154 TimeUtils.formatDuration(timestampMs), sourceUid, targetPackage, targetUserId, 155 idForResponseEvent, procStateToString(targetUidProcState)); 156 } 157 158 @NonNull getNotificationEventLog(@otificationEventType int event, @NonNull String packageName, @UserIdInt int userId, @ElapsedRealtimeLong long timestampMs)159 private static String getNotificationEventLog(@NotificationEventType int event, 160 @NonNull String packageName, @UserIdInt int userId, 161 @ElapsedRealtimeLong long timestampMs) { 162 return TextUtils.formatSimple("notification:%s; event=<%s>, pkg=%s, usr=%d", 163 TimeUtils.formatDuration(timestampMs), notificationEventToString(event), 164 packageName, userId); 165 } 166 167 @NonNull notificationEventToString(@otificationEventType int event)168 private static String notificationEventToString(@NotificationEventType int event) { 169 switch (event) { 170 case NOTIFICATION_EVENT_TYPE_POSTED: 171 return "posted"; 172 case NOTIFICATION_EVENT_TYPE_UPDATED: 173 return "updated"; 174 case NOTIFICATION_EVENT_TYPE_CANCELLED: 175 return "cancelled"; 176 default: 177 return String.valueOf(event); 178 } 179 } 180 181 public static final class BroadcastEvent implements Data { 182 public int sourceUid; 183 public int targetUserId; 184 public int targetUidProcessState; 185 public String targetPackage; 186 public long idForResponseEvent; 187 public long timestampMs; 188 189 @Override reset()190 public void reset() { 191 targetPackage = null; 192 } 193 194 @Override toString()195 public String toString() { 196 return getBroadcastDispatchEventLog(sourceUid, targetPackage, targetUserId, 197 idForResponseEvent, timestampMs, targetUidProcessState); 198 } 199 } 200 201 public static final class NotificationEvent implements Data { 202 public int type; 203 public String packageName; 204 public int userId; 205 public long timestampMs; 206 207 @Override reset()208 public void reset() { 209 packageName = null; 210 } 211 212 @Override toString()213 public String toString() { 214 return getNotificationEventLog(type, packageName, userId, timestampMs); 215 } 216 } 217 218 public interface Data { reset()219 void reset(); 220 } 221 } 222