blob: fd2458222a89812d9edb689e9d96188884d941b3 [file] [log] [blame]
/*
* Copyright (C) 2016 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.am;
import android.os.SystemClock;
import android.util.ArrayMap;
import android.util.TimeUtils;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public final class BroadcastStats {
final long mStartRealtime;
final long mStartUptime;
long mEndRealtime;
long mEndUptime;
final ArrayMap<String, ActionEntry> mActions = new ArrayMap<>();
static final Comparator<ActionEntry> ACTIONS_COMPARATOR = new Comparator<ActionEntry>() {
@Override public int compare(ActionEntry o1, ActionEntry o2) {
if (o1.mTotalDispatchTime < o2.mTotalDispatchTime) {
return -1;
}
if (o1.mTotalDispatchTime > o2.mTotalDispatchTime) {
return 1;
}
return 0;
}
};
static final class ActionEntry {
final String mAction;
final ArrayMap<String, PackageEntry> mPackages = new ArrayMap<>();
final ArrayMap<String, ViolationEntry> mBackgroundCheckViolations = new ArrayMap<>();
int mReceiveCount;
int mSkipCount;
long mTotalDispatchTime;
long mMaxDispatchTime;
ActionEntry(String action) {
mAction = action;
}
}
static final class PackageEntry {
int mSendCount;
}
static final class ViolationEntry {
int mCount;
}
public BroadcastStats() {
mStartRealtime = SystemClock.elapsedRealtime();
mStartUptime = SystemClock.uptimeMillis();
}
public void addBroadcast(String action, String srcPackage, int receiveCount,
int skipCount, long dispatchTime) {
ActionEntry ae = mActions.get(action);
if (ae == null) {
ae = new ActionEntry(action);
mActions.put(action, ae);
}
ae.mReceiveCount += receiveCount;
ae.mSkipCount += skipCount;
ae.mTotalDispatchTime += dispatchTime;
if (ae.mMaxDispatchTime < dispatchTime) {
ae.mMaxDispatchTime = dispatchTime;
}
PackageEntry pe = ae.mPackages.get(srcPackage);
if (pe == null) {
pe = new PackageEntry();
ae.mPackages.put(srcPackage, pe);
}
pe.mSendCount++;
}
public void addBackgroundCheckViolation(String action, String targetPackage) {
ActionEntry ae = mActions.get(action);
if (ae == null) {
ae = new ActionEntry(action);
mActions.put(action, ae);
}
ViolationEntry ve = ae.mBackgroundCheckViolations.get(targetPackage);
if (ve == null) {
ve = new ViolationEntry();
ae.mBackgroundCheckViolations.put(targetPackage, ve);
}
ve.mCount++;
}
public boolean dumpStats(PrintWriter pw, String prefix, String dumpPackage) {
boolean printedSomething = false;
ArrayList<ActionEntry> actions = new ArrayList<>(mActions.size());
for (int i=mActions.size()-1; i>=0; i--) {
actions.add(mActions.valueAt(i));
}
Collections.sort(actions, ACTIONS_COMPARATOR);
for (int i=actions.size()-1; i>=0; i--) {
ActionEntry ae = actions.get(i);
if (dumpPackage != null && !ae.mPackages.containsKey(dumpPackage)) {
continue;
}
printedSomething = true;
pw.print(prefix);
pw.print(ae.mAction);
pw.println(":");
pw.print(prefix);
pw.print(" Number received: ");
pw.print(ae.mReceiveCount);
pw.print(", skipped: ");
pw.println(ae.mSkipCount);
pw.print(prefix);
pw.print(" Total dispatch time: ");
TimeUtils.formatDuration(ae.mTotalDispatchTime, pw);
pw.print(", max: ");
TimeUtils.formatDuration(ae.mMaxDispatchTime, pw);
pw.println();
for (int j=ae.mPackages.size()-1; j>=0; j--) {
pw.print(prefix);
pw.print(" Package ");
pw.print(ae.mPackages.keyAt(j));
pw.print(": ");
PackageEntry pe = ae.mPackages.valueAt(j);
pw.print(pe.mSendCount);
pw.println(" times");
}
for (int j=ae.mBackgroundCheckViolations.size()-1; j>=0; j--) {
pw.print(prefix);
pw.print(" Bg Check Violation ");
pw.print(ae.mBackgroundCheckViolations.keyAt(j));
pw.print(": ");
ViolationEntry ve = ae.mBackgroundCheckViolations.valueAt(j);
pw.print(ve.mCount);
pw.println(" times");
}
}
return printedSomething;
}
public void dumpCheckinStats(PrintWriter pw, String dumpPackage) {
pw.print("broadcast-stats,1,");
pw.print(mStartRealtime);
pw.print(",");
pw.print(mEndRealtime == 0 ? SystemClock.elapsedRealtime() : mEndRealtime);
pw.print(",");
pw.println((mEndUptime == 0 ? SystemClock.uptimeMillis() : mEndUptime) - mStartUptime);
for (int i=mActions.size()-1; i>=0; i--) {
ActionEntry ae = mActions.valueAt(i);
if (dumpPackage != null && !ae.mPackages.containsKey(dumpPackage)) {
continue;
}
pw.print("a,");
pw.print(mActions.keyAt(i));
pw.print(",");
pw.print(ae.mReceiveCount);
pw.print(",");
pw.print(ae.mSkipCount);
pw.print(",");
pw.print(ae.mTotalDispatchTime);
pw.print(",");
pw.print(ae.mMaxDispatchTime);
pw.println();
for (int j=ae.mPackages.size()-1; j>=0; j--) {
pw.print("p,");
pw.print(ae.mPackages.keyAt(j));
PackageEntry pe = ae.mPackages.valueAt(j);
pw.print(",");
pw.print(pe.mSendCount);
pw.println();
}
for (int j=ae.mBackgroundCheckViolations.size()-1; j>=0; j--) {
pw.print("v,");
pw.print(ae.mBackgroundCheckViolations.keyAt(j));
ViolationEntry ve = ae.mBackgroundCheckViolations.valueAt(j);
pw.print(",");
pw.print(ve.mCount);
pw.println();
}
}
}
}