/* * 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 mActions = new ArrayMap<>(); static final Comparator ACTIONS_COMPARATOR = new Comparator() { @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 mPackages = new ArrayMap<>(); final ArrayMap 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 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(); } } } }