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
17package com.android.server.am;
18
19import android.os.SystemClock;
20import android.util.ArrayMap;
21import android.util.TimeUtils;
22
23import java.io.PrintWriter;
24import java.util.ArrayList;
25import java.util.Collections;
26import java.util.Comparator;
27
28public 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        int mReceiveCount;
51        int mSkipCount;
52        long mTotalDispatchTime;
53        long mMaxDispatchTime;
54
55        ActionEntry(String action) {
56            mAction = action;
57        }
58    }
59
60    static final class PackageEntry {
61        int mSendCount;
62    }
63
64    public BroadcastStats() {
65        mStartRealtime = SystemClock.elapsedRealtime();
66        mStartUptime = SystemClock.uptimeMillis();
67    }
68
69    public void addBroadcast(String action, String srcPackage, int receiveCount,
70            int skipCount, long dispatchTime) {
71        ActionEntry ae = mActions.get(action);
72        if (ae == null) {
73            ae = new ActionEntry(action);
74            mActions.put(action, ae);
75        }
76        ae.mReceiveCount += receiveCount;
77        ae.mSkipCount += skipCount;
78        ae.mTotalDispatchTime += dispatchTime;
79        if (ae.mMaxDispatchTime < dispatchTime) {
80            ae.mMaxDispatchTime = dispatchTime;
81        }
82        PackageEntry pe = ae.mPackages.get(srcPackage);
83        if (pe == null) {
84            pe = new PackageEntry();
85            ae.mPackages.put(srcPackage, pe);
86        }
87        pe.mSendCount++;
88    }
89
90    public boolean dumpStats(PrintWriter pw, String prefix, String dumpPackage) {
91        boolean printedSomething = false;
92        ArrayList<ActionEntry> actions = new ArrayList<>(mActions.size());
93        for (int i=mActions.size()-1; i>=0; i--) {
94            actions.add(mActions.valueAt(i));
95        }
96        Collections.sort(actions, ACTIONS_COMPARATOR);
97        for (int i=actions.size()-1; i>=0; i--) {
98            ActionEntry ae = actions.get(i);
99            if (dumpPackage != null && !ae.mPackages.containsKey(dumpPackage)) {
100                continue;
101            }
102            printedSomething = true;
103            pw.print(prefix);
104            pw.print(ae.mAction);
105            pw.println(":");
106            pw.print(prefix);
107            pw.print("  Number received: ");
108            pw.print(ae.mReceiveCount);
109            pw.print(", skipped: ");
110            pw.println(ae.mSkipCount);
111            pw.print(prefix);
112            pw.print("  Total dispatch time: ");
113            TimeUtils.formatDuration(ae.mTotalDispatchTime, pw);
114            pw.print(", max: ");
115            TimeUtils.formatDuration(ae.mMaxDispatchTime, pw);
116            pw.println();
117            for (int j=ae.mPackages.size()-1; j>=0; j--) {
118                pw.print(prefix);
119                pw.print("  Package ");
120                pw.print(ae.mPackages.keyAt(j));
121                pw.print(": ");
122                PackageEntry pe = ae.mPackages.valueAt(j);
123                pw.print(pe.mSendCount);
124                pw.println(" times");
125            }
126        }
127        return printedSomething;
128    }
129
130    public void dumpCheckinStats(PrintWriter pw, String dumpPackage) {
131        pw.print("broadcast-stats,1,");
132        pw.print(mStartRealtime);
133        pw.print(",");
134        pw.print(mEndRealtime == 0 ? SystemClock.elapsedRealtime() : mEndRealtime);
135        pw.print(",");
136        pw.println((mEndUptime == 0 ? SystemClock.uptimeMillis() : mEndUptime) - mStartUptime);
137        for (int i=mActions.size()-1; i>=0; i--) {
138            ActionEntry ae = mActions.valueAt(i);
139            if (dumpPackage != null && !ae.mPackages.containsKey(dumpPackage)) {
140                continue;
141            }
142            pw.print("a,");
143            pw.print(mActions.keyAt(i));
144            pw.print(",");
145            pw.print(ae.mReceiveCount);
146            pw.print(",");
147            pw.print(ae.mSkipCount);
148            pw.print(",");
149            pw.print(ae.mTotalDispatchTime);
150            pw.print(",");
151            pw.print(ae.mMaxDispatchTime);
152            pw.println();
153            for (int j=ae.mPackages.size()-1; j>=0; j--) {
154                pw.print("p,");
155                pw.print(ae.mPackages.keyAt(j));
156                PackageEntry pe = ae.mPackages.valueAt(j);
157                pw.print(",");
158                pw.print(pe.mSendCount);
159                pw.println();
160            }
161        }
162    }
163}
164