• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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