1 /*
2  * Copyright (C) 2016 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.am;
18 
19 import android.os.SystemClock;
20 import android.util.ArrayMap;
21 import android.util.TimeUtils;
22 
23 import java.io.PrintWriter;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.Comparator;
27 
28 public final class BroadcastStats {
29     final long mStartRealtime;
30     final long mStartUptime;
31     long mEndRealtime;
32     long mEndUptime;
33     final ArrayMap<String, ActionEntry> mActions = new ArrayMap<>();
34 
35     static final Comparator<ActionEntry> ACTIONS_COMPARATOR = new Comparator<ActionEntry>() {
36         @Override public int compare(ActionEntry o1, ActionEntry o2) {
37             if (o1.mTotalDispatchTime < o2.mTotalDispatchTime) {
38                 return -1;
39             }
40             if (o1.mTotalDispatchTime > o2.mTotalDispatchTime) {
41                 return 1;
42             }
43             return 0;
44         }
45     };
46 
47     static final class ActionEntry {
48         final String mAction;
49         final ArrayMap<String, PackageEntry> mPackages = new ArrayMap<>();
50         final ArrayMap<String, ViolationEntry> mBackgroundCheckViolations = new ArrayMap<>();
51         int mReceiveCount;
52         int mSkipCount;
53         long mTotalDispatchTime;
54         long mMaxDispatchTime;
55 
ActionEntry(String action)56         ActionEntry(String action) {
57             mAction = action;
58         }
59     }
60 
61     static final class PackageEntry {
62         int mSendCount;
63     }
64 
65     static final class ViolationEntry {
66         int mCount;
67     }
68 
BroadcastStats()69     public BroadcastStats() {
70         mStartRealtime = SystemClock.elapsedRealtime();
71         mStartUptime = SystemClock.uptimeMillis();
72     }
73 
addBroadcast(String action, String srcPackage, int receiveCount, int skipCount, long dispatchTime)74     public void addBroadcast(String action, String srcPackage, int receiveCount,
75             int skipCount, long dispatchTime) {
76         ActionEntry ae = mActions.get(action);
77         if (ae == null) {
78             ae = new ActionEntry(action);
79             mActions.put(action, ae);
80         }
81         ae.mReceiveCount += receiveCount;
82         ae.mSkipCount += skipCount;
83         ae.mTotalDispatchTime += dispatchTime;
84         if (ae.mMaxDispatchTime < dispatchTime) {
85             ae.mMaxDispatchTime = dispatchTime;
86         }
87         PackageEntry pe = ae.mPackages.get(srcPackage);
88         if (pe == null) {
89             pe = new PackageEntry();
90             ae.mPackages.put(srcPackage, pe);
91         }
92         pe.mSendCount++;
93     }
94 
addBackgroundCheckViolation(String action, String targetPackage)95     public void addBackgroundCheckViolation(String action, String targetPackage) {
96         ActionEntry ae = mActions.get(action);
97         if (ae == null) {
98             ae = new ActionEntry(action);
99             mActions.put(action, ae);
100         }
101         ViolationEntry ve = ae.mBackgroundCheckViolations.get(targetPackage);
102         if (ve == null) {
103             ve = new ViolationEntry();
104             ae.mBackgroundCheckViolations.put(targetPackage, ve);
105         }
106         ve.mCount++;
107     }
108 
dumpStats(PrintWriter pw, String prefix, String dumpPackage)109     public boolean dumpStats(PrintWriter pw, String prefix, String dumpPackage) {
110         boolean printedSomething = false;
111         ArrayList<ActionEntry> actions = new ArrayList<>(mActions.size());
112         for (int i=mActions.size()-1; i>=0; i--) {
113             actions.add(mActions.valueAt(i));
114         }
115         Collections.sort(actions, ACTIONS_COMPARATOR);
116         for (int i=actions.size()-1; i>=0; i--) {
117             ActionEntry ae = actions.get(i);
118             if (dumpPackage != null && !ae.mPackages.containsKey(dumpPackage)) {
119                 continue;
120             }
121             printedSomething = true;
122             pw.print(prefix);
123             pw.print(ae.mAction);
124             pw.println(":");
125             pw.print(prefix);
126             pw.print("  Number received: ");
127             pw.print(ae.mReceiveCount);
128             pw.print(", skipped: ");
129             pw.println(ae.mSkipCount);
130             pw.print(prefix);
131             pw.print("  Total dispatch time: ");
132             TimeUtils.formatDuration(ae.mTotalDispatchTime, pw);
133             pw.print(", max: ");
134             TimeUtils.formatDuration(ae.mMaxDispatchTime, pw);
135             pw.println();
136             for (int j=ae.mPackages.size()-1; j>=0; j--) {
137                 pw.print(prefix);
138                 pw.print("  Package ");
139                 pw.print(ae.mPackages.keyAt(j));
140                 pw.print(": ");
141                 PackageEntry pe = ae.mPackages.valueAt(j);
142                 pw.print(pe.mSendCount);
143                 pw.println(" times");
144             }
145             for (int j=ae.mBackgroundCheckViolations.size()-1; j>=0; j--) {
146                 pw.print(prefix);
147                 pw.print("  Bg Check Violation ");
148                 pw.print(ae.mBackgroundCheckViolations.keyAt(j));
149                 pw.print(": ");
150                 ViolationEntry ve = ae.mBackgroundCheckViolations.valueAt(j);
151                 pw.print(ve.mCount);
152                 pw.println(" times");
153             }
154         }
155         return printedSomething;
156     }
157 
dumpCheckinStats(PrintWriter pw, String dumpPackage)158     public void dumpCheckinStats(PrintWriter pw, String dumpPackage) {
159         pw.print("broadcast-stats,1,");
160         pw.print(mStartRealtime);
161         pw.print(",");
162         pw.print(mEndRealtime == 0 ? SystemClock.elapsedRealtime() : mEndRealtime);
163         pw.print(",");
164         pw.println((mEndUptime == 0 ? SystemClock.uptimeMillis() : mEndUptime) - mStartUptime);
165         for (int i=mActions.size()-1; i>=0; i--) {
166             ActionEntry ae = mActions.valueAt(i);
167             if (dumpPackage != null && !ae.mPackages.containsKey(dumpPackage)) {
168                 continue;
169             }
170             pw.print("a,");
171             pw.print(mActions.keyAt(i));
172             pw.print(",");
173             pw.print(ae.mReceiveCount);
174             pw.print(",");
175             pw.print(ae.mSkipCount);
176             pw.print(",");
177             pw.print(ae.mTotalDispatchTime);
178             pw.print(",");
179             pw.print(ae.mMaxDispatchTime);
180             pw.println();
181             for (int j=ae.mPackages.size()-1; j>=0; j--) {
182                 pw.print("p,");
183                 pw.print(ae.mPackages.keyAt(j));
184                 PackageEntry pe = ae.mPackages.valueAt(j);
185                 pw.print(",");
186                 pw.print(pe.mSendCount);
187                 pw.println();
188             }
189             for (int j=ae.mBackgroundCheckViolations.size()-1; j>=0; j--) {
190                 pw.print("v,");
191                 pw.print(ae.mBackgroundCheckViolations.keyAt(j));
192                 ViolationEntry ve = ae.mBackgroundCheckViolations.valueAt(j);
193                 pw.print(",");
194                 pw.print(ve.mCount);
195                 pw.println();
196             }
197         }
198     }
199 }
200