| /* |
| * 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(); |
| } |
| } |
| } |
| } |