Merge "add api to get sections of procstats"

This commit is contained in:
TreeHugger Robot
2018-09-26 15:07:51 +00:00
committed by Android (Google) Code Review
3 changed files with 457 additions and 256 deletions

View File

@@ -24,4 +24,14 @@ interface IProcessStats {
byte[] getCurrentStats(out List<ParcelFileDescriptor> historic);
ParcelFileDescriptor getStatsOverTime(long minTime);
int getCurrentMemoryState();
/**
* Get stats committed after highWaterMarkMs
* @param highWaterMarkMs Report stats committed after this time.
* @param section Integer mask to indicate which sections to include in the stats.
* @param doAggregate Whether to aggregate the stats or keep them separated.
* @param List of Files of individual commits in protobuf binary or one that is merged from them.
*/
long getCommittedStats(long highWaterMarkMs, int section, boolean doAggregate,
out List<ParcelFileDescriptor> committedStats);
}

View File

@@ -158,6 +158,25 @@ public final class ProcessStats implements Parcelable {
STATE_CACHED_ACTIVITY_CLIENT, STATE_CACHED_EMPTY
};
// Should report process stats.
public static final int REPORT_PROC_STATS = 0x01;
// Should report package process stats.
public static final int REPORT_PKG_PROC_STATS = 0x02;
// Should report package service stats.
public static final int REPORT_PKG_SVC_STATS = 0x04;
// Should report package association stats.
public static final int REPORT_PKG_ASC_STATS = 0x08;
// Should report package stats.
public static final int REPORT_PKG_STATS = 0x0E;
// Should report all stats.
public static final int REPORT_ALL = 0x0F;
public static final int[] OPTIONS =
{REPORT_PROC_STATS, REPORT_PKG_PROC_STATS, REPORT_PKG_SVC_STATS, REPORT_PKG_ASC_STATS,
REPORT_PKG_STATS, REPORT_ALL};
public static final String[] OPTIONS_STR =
{"proc", "pkg-proc", "pkg-svc", "pkg-asc", "pkg-all", "all"};
// Current version of the parcel format.
private static final int PARCEL_VERSION = 34;
// In-memory Parcel magic number, used to detect attempts to unmarshall bad data
@@ -1412,7 +1431,7 @@ public final class ProcessStats implements Parcelable {
}
public void dumpLocked(PrintWriter pw, String reqPackage, long now, boolean dumpSummary,
boolean dumpDetails, boolean dumpAll, boolean activeOnly) {
boolean dumpDetails, boolean dumpAll, boolean activeOnly, int section) {
long totalTime = DumpUtils.dumpSingleTime(null, null, mMemFactorDurations, mMemFactor,
mStartTime, now);
boolean sepNeeded = false;
@@ -1421,176 +1440,205 @@ public final class ProcessStats implements Parcelable {
mSysMemUsage.dump(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ);
sepNeeded = true;
}
ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap = mPackages.getMap();
boolean printedHeader = false;
for (int ip=0; ip<pkgMap.size(); ip++) {
final String pkgName = pkgMap.keyAt(ip);
final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
for (int iu=0; iu<uids.size(); iu++) {
final int uid = uids.keyAt(iu);
final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu);
for (int iv=0; iv<vpkgs.size(); iv++) {
final long vers = vpkgs.keyAt(iv);
final PackageState pkgState = vpkgs.valueAt(iv);
final int NPROCS = pkgState.mProcesses.size();
final int NSRVS = pkgState.mServices.size();
final int NASCS = pkgState.mAssociations.size();
final boolean pkgMatch = reqPackage == null || reqPackage.equals(pkgName);
if (!pkgMatch) {
boolean procMatch = false;
for (int iproc=0; iproc<NPROCS; iproc++) {
ProcessState proc = pkgState.mProcesses.valueAt(iproc);
if (reqPackage.equals(proc.getName())) {
procMatch = true;
break;
if ((section & REPORT_PKG_STATS) != 0) {
ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap =
mPackages.getMap();
for (int ip = 0; ip < pkgMap.size(); ip++) {
final String pkgName = pkgMap.keyAt(ip);
final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
for (int iu = 0; iu < uids.size(); iu++) {
final int uid = uids.keyAt(iu);
final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu);
for (int iv = 0; iv < vpkgs.size(); iv++) {
final long vers = vpkgs.keyAt(iv);
final PackageState pkgState = vpkgs.valueAt(iv);
final int NPROCS = pkgState.mProcesses.size();
final int NSRVS = pkgState.mServices.size();
final int NASCS = pkgState.mAssociations.size();
final boolean pkgMatch = reqPackage == null || reqPackage.equals(pkgName);
if (!pkgMatch) {
boolean procMatch = false;
for (int iproc = 0; iproc < NPROCS; iproc++) {
ProcessState proc = pkgState.mProcesses.valueAt(iproc);
if (reqPackage.equals(proc.getName())) {
procMatch = true;
break;
}
}
}
if (!procMatch) {
continue;
}
}
if (NPROCS > 0 || NSRVS > 0 || NASCS > 0) {
if (!printedHeader) {
if (sepNeeded) pw.println();
pw.println("Per-Package Stats:");
printedHeader = true;
sepNeeded = true;
}
pw.print(" * "); pw.print(pkgName); pw.print(" / ");
UserHandle.formatUid(pw, uid); pw.print(" / v");
pw.print(vers); pw.println(":");
}
if (!dumpSummary || dumpAll) {
for (int iproc=0; iproc<NPROCS; iproc++) {
ProcessState proc = pkgState.mProcesses.valueAt(iproc);
if (!pkgMatch && !reqPackage.equals(proc.getName())) {
if (!procMatch) {
continue;
}
if (activeOnly && !proc.isInUse()) {
pw.print(" (Not active: ");
pw.print(pkgState.mProcesses.keyAt(iproc)); pw.println(")");
continue;
}
if (NPROCS > 0 || NSRVS > 0 || NASCS > 0) {
if (!printedHeader) {
if (sepNeeded) pw.println();
pw.println("Per-Package Stats:");
printedHeader = true;
sepNeeded = true;
}
pw.print(" Process ");
pw.print(pkgState.mProcesses.keyAt(iproc));
if (proc.getCommonProcess().isMultiPackage()) {
pw.print(" (multi, ");
} else {
pw.print(" (unique, ");
}
pw.print(proc.getDurationsBucketCount());
pw.print(" entries)");
pw.print(" * ");
pw.print(pkgName);
pw.print(" / ");
UserHandle.formatUid(pw, uid);
pw.print(" / v");
pw.print(vers);
pw.println(":");
proc.dumpProcessState(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
ALL_PROC_STATES, now);
proc.dumpPss(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
ALL_PROC_STATES, now);
proc.dumpInternalLocked(pw, " ", dumpAll);
}
} else {
ArrayList<ProcessState> procs = new ArrayList<ProcessState>();
for (int iproc=0; iproc<NPROCS; iproc++) {
ProcessState proc = pkgState.mProcesses.valueAt(iproc);
if (!pkgMatch && !reqPackage.equals(proc.getName())) {
continue;
if ((section & REPORT_PKG_PROC_STATS) != 0) {
if (!dumpSummary || dumpAll) {
for (int iproc = 0; iproc < NPROCS; iproc++) {
ProcessState proc = pkgState.mProcesses.valueAt(iproc);
if (!pkgMatch && !reqPackage.equals(proc.getName())) {
continue;
}
if (activeOnly && !proc.isInUse()) {
pw.print(" (Not active: ");
pw.print(pkgState.mProcesses.keyAt(iproc));
pw.println(")");
continue;
}
pw.print(" Process ");
pw.print(pkgState.mProcesses.keyAt(iproc));
if (proc.getCommonProcess().isMultiPackage()) {
pw.print(" (multi, ");
} else {
pw.print(" (unique, ");
}
pw.print(proc.getDurationsBucketCount());
pw.print(" entries)");
pw.println(":");
proc.dumpProcessState(pw, " ", ALL_SCREEN_ADJ,
ALL_MEM_ADJ,
ALL_PROC_STATES, now);
proc.dumpPss(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
ALL_PROC_STATES, now);
proc.dumpInternalLocked(pw, " ", dumpAll);
}
} else {
ArrayList<ProcessState> procs = new ArrayList<ProcessState>();
for (int iproc = 0; iproc < NPROCS; iproc++) {
ProcessState proc = pkgState.mProcesses.valueAt(iproc);
if (!pkgMatch && !reqPackage.equals(proc.getName())) {
continue;
}
if (activeOnly && !proc.isInUse()) {
continue;
}
procs.add(proc);
}
DumpUtils.dumpProcessSummaryLocked(pw, " ", "Prc ", procs,
ALL_SCREEN_ADJ, ALL_MEM_ADJ, NON_CACHED_PROC_STATES,
now, totalTime);
}
if (activeOnly && !proc.isInUse()) {
continue;
}
if ((section & REPORT_PKG_SVC_STATS) != 0) {
for (int isvc = 0; isvc < NSRVS; isvc++) {
ServiceState svc = pkgState.mServices.valueAt(isvc);
if (!pkgMatch && !reqPackage.equals(svc.getProcessName())) {
continue;
}
if (activeOnly && !svc.isInUse()) {
pw.print(" (Not active service: ");
pw.print(pkgState.mServices.keyAt(isvc));
pw.println(")");
continue;
}
if (dumpAll) {
pw.print(" Service ");
} else {
pw.print(" * Svc ");
}
pw.print(pkgState.mServices.keyAt(isvc));
pw.println(":");
pw.print(" Process: ");
pw.println(svc.getProcessName());
svc.dumpStats(pw, " ", " ", " ",
now, totalTime, dumpSummary, dumpAll);
}
procs.add(proc);
}
DumpUtils.dumpProcessSummaryLocked(pw, " ", "Prc ", procs,
ALL_SCREEN_ADJ, ALL_MEM_ADJ, NON_CACHED_PROC_STATES,
now, totalTime);
}
for (int isvc=0; isvc<NSRVS; isvc++) {
ServiceState svc = pkgState.mServices.valueAt(isvc);
if (!pkgMatch && !reqPackage.equals(svc.getProcessName())) {
continue;
if ((section & REPORT_PKG_ASC_STATS) != 0) {
for (int iasc = 0; iasc < NASCS; iasc++) {
AssociationState asc = pkgState.mAssociations.valueAt(iasc);
if (!pkgMatch && !reqPackage.equals(asc.getProcessName())) {
continue;
}
if (activeOnly && !asc.isInUse()) {
pw.print(" (Not active association: ");
pw.print(pkgState.mAssociations.keyAt(iasc));
pw.println(")");
continue;
}
if (dumpAll) {
pw.print(" Association ");
} else {
pw.print(" * Asc ");
}
pw.print(pkgState.mAssociations.keyAt(iasc));
pw.println(":");
pw.print(" Process: ");
pw.println(asc.getProcessName());
asc.dumpStats(pw, " ", " ", " ",
now, totalTime, dumpDetails, dumpAll);
}
}
if (activeOnly && !svc.isInUse()) {
pw.print(" (Not active service: ");
pw.print(pkgState.mServices.keyAt(isvc)); pw.println(")");
continue;
}
if (dumpAll) {
pw.print(" Service ");
} else {
pw.print(" * Svc ");
}
pw.print(pkgState.mServices.keyAt(isvc));
pw.println(":");
pw.print(" Process: "); pw.println(svc.getProcessName());
svc.dumpStats(pw, " ", " ", " ",
now, totalTime, dumpSummary, dumpAll);
}
for (int iasc=0; iasc<NASCS; iasc++) {
AssociationState asc = pkgState.mAssociations.valueAt(iasc);
if (!pkgMatch && !reqPackage.equals(asc.getProcessName())) {
continue;
}
if (activeOnly && !asc.isInUse()) {
pw.print(" (Not active association: ");
pw.print(pkgState.mAssociations.keyAt(iasc)); pw.println(")");
continue;
}
if (dumpAll) {
pw.print(" Association ");
} else {
pw.print(" * Asc ");
}
pw.print(pkgState.mAssociations.keyAt(iasc));
pw.println(":");
pw.print(" Process: "); pw.println(asc.getProcessName());
asc.dumpStats(pw, " ", " ", " ",
now, totalTime, dumpDetails, dumpAll);
}
}
}
}
ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
printedHeader = false;
int numShownProcs = 0, numTotalProcs = 0;
for (int ip=0; ip<procMap.size(); ip++) {
String procName = procMap.keyAt(ip);
SparseArray<ProcessState> uids = procMap.valueAt(ip);
for (int iu=0; iu<uids.size(); iu++) {
int uid = uids.keyAt(iu);
numTotalProcs++;
final ProcessState proc = uids.valueAt(iu);
if (!proc.hasAnyData()) {
continue;
if ((section & REPORT_PROC_STATS) != 0) {
ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
printedHeader = false;
int numShownProcs = 0, numTotalProcs = 0;
for (int ip = 0; ip < procMap.size(); ip++) {
String procName = procMap.keyAt(ip);
SparseArray<ProcessState> uids = procMap.valueAt(ip);
for (int iu = 0; iu < uids.size(); iu++) {
int uid = uids.keyAt(iu);
numTotalProcs++;
final ProcessState proc = uids.valueAt(iu);
if (!proc.hasAnyData()) {
continue;
}
if (!proc.isMultiPackage()) {
continue;
}
if (reqPackage != null && !reqPackage.equals(procName)
&& !reqPackage.equals(proc.getPackage())) {
continue;
}
numShownProcs++;
if (sepNeeded) {
pw.println();
}
sepNeeded = true;
if (!printedHeader) {
pw.println("Multi-Package Common Processes:");
printedHeader = true;
}
if (activeOnly && !proc.isInUse()) {
pw.print(" (Not active: ");
pw.print(procName);
pw.println(")");
continue;
}
pw.print(" * ");
pw.print(procName);
pw.print(" / ");
UserHandle.formatUid(pw, uid);
pw.print(" (");
pw.print(proc.getDurationsBucketCount());
pw.print(" entries)");
pw.println(":");
proc.dumpProcessState(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
ALL_PROC_STATES, now);
proc.dumpPss(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ, ALL_PROC_STATES, now);
proc.dumpInternalLocked(pw, " ", dumpAll);
}
if (!proc.isMultiPackage()) {
continue;
}
if (reqPackage != null && !reqPackage.equals(procName)
&& !reqPackage.equals(proc.getPackage())) {
continue;
}
numShownProcs++;
if (sepNeeded) {
pw.println();
}
sepNeeded = true;
if (!printedHeader) {
pw.println("Multi-Package Common Processes:");
printedHeader = true;
}
if (activeOnly && !proc.isInUse()) {
pw.print(" (Not active: "); pw.print(procName); pw.println(")");
continue;
}
pw.print(" * "); pw.print(procName); pw.print(" / ");
UserHandle.formatUid(pw, uid);
pw.print(" ("); pw.print(proc.getDurationsBucketCount());
pw.print(" entries)"); pw.println(":");
proc.dumpProcessState(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
ALL_PROC_STATES, now);
proc.dumpPss(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ, ALL_PROC_STATES, now);
proc.dumpInternalLocked(pw, " ", dumpAll);
}
pw.print(" Total procs: "); pw.print(numShownProcs);
pw.print(" shown of "); pw.print(numTotalProcs); pw.println(" total");
}
if (dumpAll) {
@@ -1598,8 +1646,7 @@ public final class ProcessStats implements Parcelable {
pw.println();
}
sepNeeded = true;
pw.print(" Total procs: "); pw.print(numShownProcs);
pw.print(" shown of "); pw.print(numTotalProcs); pw.println(" total");
if (mTrackingAssociations.size() > 0) {
pw.println();
pw.println("Tracking associations:");
@@ -1866,7 +1913,10 @@ public final class ProcessStats implements Parcelable {
return outProcs;
}
public void dumpCheckinLocked(PrintWriter pw, String reqPackage) {
/**
* Prints checkin style stats dump.
*/
public void dumpCheckinLocked(PrintWriter pw, String reqPackage, int section) {
final long now = SystemClock.uptimeMillis();
final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap =
mPackages.getMap();
@@ -1895,50 +1945,61 @@ public final class ProcessStats implements Parcelable {
}
pw.println();
pw.print("config,"); pw.println(mRuntime);
for (int ip=0; ip<pkgMap.size(); ip++) {
final String pkgName = pkgMap.keyAt(ip);
if (reqPackage != null && !reqPackage.equals(pkgName)) {
continue;
}
final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
for (int iu=0; iu<uids.size(); iu++) {
final int uid = uids.keyAt(iu);
final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu);
for (int iv=0; iv<vpkgs.size(); iv++) {
final long vers = vpkgs.keyAt(iv);
final PackageState pkgState = vpkgs.valueAt(iv);
final int NPROCS = pkgState.mProcesses.size();
final int NSRVS = pkgState.mServices.size();
final int NASCS = pkgState.mAssociations.size();
for (int iproc=0; iproc<NPROCS; iproc++) {
ProcessState proc = pkgState.mProcesses.valueAt(iproc);
proc.dumpPackageProcCheckin(pw, pkgName, uid, vers,
pkgState.mProcesses.keyAt(iproc), now);
}
for (int isvc=0; isvc<NSRVS; isvc++) {
final String serviceName = DumpUtils.collapseString(pkgName,
pkgState.mServices.keyAt(isvc));
final ServiceState svc = pkgState.mServices.valueAt(isvc);
svc.dumpTimesCheckin(pw, pkgName, uid, vers, serviceName, now);
}
for (int iasc=0; iasc<NASCS; iasc++) {
final String associationName = DumpUtils.collapseString(pkgName,
pkgState.mAssociations.keyAt(iasc));
final AssociationState asc = pkgState.mAssociations.valueAt(iasc);
asc.dumpTimesCheckin(pw, pkgName, uid, vers, associationName, now);
if ((section & REPORT_PKG_STATS) != 0) {
for (int ip = 0; ip < pkgMap.size(); ip++) {
final String pkgName = pkgMap.keyAt(ip);
if (reqPackage != null && !reqPackage.equals(pkgName)) {
continue;
}
final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
for (int iu = 0; iu < uids.size(); iu++) {
final int uid = uids.keyAt(iu);
final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu);
for (int iv = 0; iv < vpkgs.size(); iv++) {
final long vers = vpkgs.keyAt(iv);
final PackageState pkgState = vpkgs.valueAt(iv);
final int NPROCS = pkgState.mProcesses.size();
final int NSRVS = pkgState.mServices.size();
final int NASCS = pkgState.mAssociations.size();
if ((section & REPORT_PKG_PROC_STATS) != 0) {
for (int iproc = 0; iproc < NPROCS; iproc++) {
ProcessState proc = pkgState.mProcesses.valueAt(iproc);
proc.dumpPackageProcCheckin(pw, pkgName, uid, vers,
pkgState.mProcesses.keyAt(iproc), now);
}
}
if ((section & REPORT_PKG_SVC_STATS) != 0) {
for (int isvc = 0; isvc < NSRVS; isvc++) {
final String serviceName = DumpUtils.collapseString(pkgName,
pkgState.mServices.keyAt(isvc));
final ServiceState svc = pkgState.mServices.valueAt(isvc);
svc.dumpTimesCheckin(pw, pkgName, uid, vers, serviceName, now);
}
}
if ((section & REPORT_PKG_ASC_STATS) != 0) {
for (int iasc = 0; iasc < NASCS; iasc++) {
final String associationName = DumpUtils.collapseString(pkgName,
pkgState.mAssociations.keyAt(iasc));
final AssociationState asc = pkgState.mAssociations.valueAt(iasc);
asc.dumpTimesCheckin(pw, pkgName, uid, vers, associationName, now);
}
}
}
}
}
}
ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
for (int ip=0; ip<procMap.size(); ip++) {
String procName = procMap.keyAt(ip);
SparseArray<ProcessState> uids = procMap.valueAt(ip);
for (int iu=0; iu<uids.size(); iu++) {
final int uid = uids.keyAt(iu);
final ProcessState procState = uids.valueAt(iu);
procState.dumpProcCheckin(pw, procName, uid, now);
if ((section & REPORT_PROC_STATS) != 0) {
ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
for (int ip = 0; ip < procMap.size(); ip++) {
String procName = procMap.keyAt(ip);
SparseArray<ProcessState> uids = procMap.valueAt(ip);
for (int iu = 0; iu < uids.size(); iu++) {
final int uid = uids.keyAt(iu);
final ProcessState procState = uids.valueAt(iu);
procState.dumpProcCheckin(pw, procName, uid, now);
}
}
}
pw.print("total");
@@ -2013,9 +2074,10 @@ public final class ProcessStats implements Parcelable {
}
}
public void writeToProto(ProtoOutputStream proto, long fieldId, long now) {
final long token = proto.start(fieldId);
/**
* Writes to ProtoOutputStream.
*/
public void writeToProto(ProtoOutputStream proto, long now, int section) {
proto.write(ProcessStatsSectionProto.START_REALTIME_MS, mTimePeriodStartRealtime);
proto.write(ProcessStatsSectionProto.END_REALTIME_MS,
mRunning ? SystemClock.elapsedRealtime() : mTimePeriodEndRealtime);
@@ -2024,15 +2086,15 @@ public final class ProcessStats implements Parcelable {
proto.write(ProcessStatsSectionProto.RUNTIME, mRuntime);
proto.write(ProcessStatsSectionProto.HAS_SWAPPED_PSS, mHasSwappedOutPss);
boolean partial = true;
if ((mFlags&FLAG_SHUTDOWN) != 0) {
if ((mFlags & FLAG_SHUTDOWN) != 0) {
proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_SHUTDOWN);
partial = false;
}
if ((mFlags&FLAG_SYSPROPS) != 0) {
if ((mFlags & FLAG_SYSPROPS) != 0) {
proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_SYSPROPS);
partial = false;
}
if ((mFlags&FLAG_COMPLETE) != 0) {
if ((mFlags & FLAG_COMPLETE) != 0) {
proto.write(ProcessStatsSectionProto.STATUS, ProcessStatsSectionProto.STATUS_COMPLETE);
partial = false;
}
@@ -2041,31 +2103,34 @@ public final class ProcessStats implements Parcelable {
}
final ArrayMap<String, SparseArray<ProcessState>> procMap = mProcesses.getMap();
for (int ip=0; ip<procMap.size(); ip++) {
final String procName = procMap.keyAt(ip);
final SparseArray<ProcessState> uids = procMap.valueAt(ip);
for (int iu=0; iu<uids.size(); iu++) {
final int uid = uids.keyAt(iu);
final ProcessState procState = uids.valueAt(iu);
procState.writeToProto(proto, ProcessStatsSectionProto.PROCESS_STATS, procName,
uid, now);
}
}
final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap =
mPackages.getMap();
for (int ip = 0; ip < pkgMap.size(); ip++) {
final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
for (int iu = 0; iu < uids.size(); iu++) {
final LongSparseArray<PackageState> vers = uids.valueAt(iu);
for (int iv = 0; iv < vers.size(); iv++) {
final PackageState pkgState = vers.valueAt(iv);
pkgState.writeToProto(proto, ProcessStatsSectionProto.PACKAGE_STATS, now);
if ((section & REPORT_PROC_STATS) != 0) {
for (int ip = 0; ip < procMap.size(); ip++) {
final String procName = procMap.keyAt(ip);
final SparseArray<ProcessState> uids = procMap.valueAt(ip);
for (int iu = 0; iu < uids.size(); iu++) {
final int uid = uids.keyAt(iu);
final ProcessState procState = uids.valueAt(iu);
procState.writeToProto(proto, ProcessStatsSectionProto.PROCESS_STATS, procName,
uid, now);
}
}
}
proto.end(token);
if ((section & REPORT_PKG_STATS) != 0) {
final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap =
mPackages.getMap();
for (int ip = 0; ip < pkgMap.size(); ip++) {
final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
for (int iu = 0; iu < uids.size(); iu++) {
final LongSparseArray<PackageState> vers = uids.valueAt(iu);
for (int iv = 0; iv < vers.size(); iv++) {
final PackageState pkgState = vers.valueAt(iv);
pkgState.writeToProto(proto, ProcessStatsSectionProto.PACKAGE_STATS, now,
section);
}
}
}
}
}
final public static class ProcessStateHolder {
@@ -2110,30 +2175,39 @@ public final class ProcessStats implements Parcelable {
return as;
}
public void writeToProto(ProtoOutputStream proto, long fieldId, long now) {
/**
* Writes the containing stats into proto, with options to choose smaller sections.
*/
public void writeToProto(ProtoOutputStream proto, long fieldId, long now, int section) {
final long token = proto.start(fieldId);
proto.write(ProcessStatsPackageProto.PACKAGE, mPackageName);
proto.write(ProcessStatsPackageProto.UID, mUid);
proto.write(ProcessStatsPackageProto.VERSION, mVersionCode);
for (int ip = 0; ip < mProcesses.size(); ip++) {
final String procName = mProcesses.keyAt(ip);
final ProcessState procState = mProcesses.valueAt(ip);
procState.writeToProto(proto, ProcessStatsPackageProto.PROCESS_STATS, procName,
mUid, now);
if ((section & ProcessStats.REPORT_PKG_PROC_STATS) != 0) {
for (int ip = 0; ip < mProcesses.size(); ip++) {
final String procName = mProcesses.keyAt(ip);
final ProcessState procState = mProcesses.valueAt(ip);
procState.writeToProto(proto, ProcessStatsPackageProto.PROCESS_STATS, procName,
mUid, now);
}
}
for (int is = 0; is < mServices.size(); is++) {
final ServiceState serviceState = mServices.valueAt(is);
serviceState.writeToProto(proto, ProcessStatsPackageProto.SERVICE_STATS,
now);
if ((section & ProcessStats.REPORT_PKG_SVC_STATS) != 0) {
for (int is = 0; is < mServices.size(); is++) {
final ServiceState serviceState = mServices.valueAt(is);
serviceState.writeToProto(proto, ProcessStatsPackageProto.SERVICE_STATS,
now);
}
}
for (int ia=0; ia<mAssociations.size(); ia++) {
final AssociationState ascState = mAssociations.valueAt(ia);
ascState.writeToProto(proto, ProcessStatsPackageProto.ASSOCIATION_STATS,
now);
if ((section & ProcessStats.REPORT_PKG_ASC_STATS) != 0) {
for (int ia = 0; ia < mAssociations.size(); ia++) {
final AssociationState ascState = mAssociations.valueAt(ia);
ascState.writeToProto(proto, ProcessStatsPackageProto.ASSOCIATION_STATS,
now);
}
}
proto.end(token);

View File

@@ -23,8 +23,10 @@ import android.os.RemoteException;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.service.procstats.ProcessStatsServiceDumpProto;
import android.text.format.DateFormat;
import android.util.ArrayMap;
import android.util.AtomicFile;
import android.util.Log;
import android.util.LongSparseArray;
import android.util.Slog;
import android.util.SparseArray;
@@ -47,6 +49,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
@@ -482,6 +485,23 @@ public final class ProcessStatsService extends IProcessStats.Stub {
return finalRes;
}
static int parseSectionOptions(String optionsStr) {
final String sep = ",";
String[] sectionsStr = optionsStr.split(sep);
if (sectionsStr.length == 0) {
return ProcessStats.REPORT_ALL;
}
int res = 0;
List<String> optionStrList = Arrays.asList(ProcessStats.OPTIONS_STR);
for (String sectionStr : sectionsStr) {
int optionIndex = optionStrList.indexOf(sectionStr);
if (optionIndex != -1) {
res |= ProcessStats.OPTIONS[optionIndex];
}
}
return res;
}
public byte[] getCurrentStats(List<ParcelFileDescriptor> historic) {
mAm.mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.PACKAGE_USAGE_STATS, null);
@@ -514,6 +534,95 @@ public final class ProcessStatsService extends IProcessStats.Stub {
return current.marshall();
}
/**
* Get stats committed after highWaterMarkMs
* @param highWaterMarkMs Report stats committed after this time.
* @param section Integer mask to indicage which sections to include in the stats.
* @param doAggregate Whether to aggregate the stats or keep them separated.
* @return List of proto binary of individual commit files or one that is merged from them.
*/
@Override
public long getCommittedStats(long highWaterMarkMs, int section, boolean doAggregate,
List<ParcelFileDescriptor> committedStats) {
mAm.mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.PACKAGE_USAGE_STATS, null);
ProcessStats mergedStats = new ProcessStats(false);
long newHighWaterMark = highWaterMarkMs;
mWriteLock.lock();
try {
ArrayList<String> files = getCommittedFiles(0, false, true);
if (files != null) {
String highWaterMarkStr =
DateFormat.format("yyyy-MM-dd-HH-mm-ss", highWaterMarkMs).toString();
ProcessStats stats = new ProcessStats(false);
for (int i = files.size() - 1; i >= 0; i--) {
String fileName = files.get(i);
try {
String startTimeStr = fileName.substring(
fileName.lastIndexOf(STATE_FILE_PREFIX)
+ STATE_FILE_PREFIX.length(),
fileName.lastIndexOf(STATE_FILE_SUFFIX));
if (startTimeStr.compareToIgnoreCase(highWaterMarkStr) > 0) {
ParcelFileDescriptor pfd = ParcelFileDescriptor.open(
new File(fileName),
ParcelFileDescriptor.MODE_READ_ONLY);
InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
stats.reset();
stats.read(is);
is.close();
if (stats.mTimePeriodStartClock > newHighWaterMark) {
newHighWaterMark = stats.mTimePeriodStartClock;
}
if (doAggregate) {
mergedStats.add(stats);
} else {
committedStats.add(protoToParcelFileDescriptor(stats, section));
}
if (stats.mReadError != null) {
Log.w(TAG, "Failure reading process stats: " + stats.mReadError);
continue;
}
}
} catch (IOException e) {
Slog.w(TAG, "Failure opening procstat file " + fileName, e);
} catch (IndexOutOfBoundsException e) {
Slog.w(TAG, "Failure to read and parse commit file " + fileName, e);
}
}
if (doAggregate) {
committedStats.add(protoToParcelFileDescriptor(mergedStats, section));
}
return newHighWaterMark;
}
} catch (IOException e) {
Slog.w(TAG, "Failure opening procstat file", e);
} finally {
mWriteLock.unlock();
}
return newHighWaterMark;
}
private ParcelFileDescriptor protoToParcelFileDescriptor(ProcessStats stats, int section)
throws IOException {
final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createPipe();
Thread thr = new Thread("ProcessStats pipe output") {
public void run() {
try {
FileOutputStream fout = new ParcelFileDescriptor.AutoCloseOutputStream(fds[1]);
final ProtoOutputStream proto = new ProtoOutputStream(fout);
stats.writeToProto(proto, stats.mTimePeriodEndRealtime, section);
proto.flush();
fout.close();
} catch (IOException e) {
Slog.w(TAG, "Failure writing pipe", e);
}
}
};
thr.start();
return fds[0];
}
public ParcelFileDescriptor getStatsOverTime(long minTime) {
mAm.mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.PACKAGE_USAGE_STATS, null);
@@ -594,7 +703,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {
private void dumpAggregatedStats(PrintWriter pw, long aggregateHours, long now,
String reqPackage, boolean isCompact, boolean dumpDetails, boolean dumpFullDetails,
boolean dumpAll, boolean activeOnly) {
boolean dumpAll, boolean activeOnly, int section) {
ParcelFileDescriptor pfd = getStatsOverTime(aggregateHours*60*60*1000
- (ProcessStats.COMMIT_PERIOD/2));
if (pfd == null) {
@@ -609,11 +718,11 @@ public final class ProcessStatsService extends IProcessStats.Stub {
return;
}
if (isCompact) {
stats.dumpCheckinLocked(pw, reqPackage);
stats.dumpCheckinLocked(pw, reqPackage, section);
} else {
if (dumpDetails || dumpFullDetails) {
stats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails, dumpAll,
activeOnly);
activeOnly, section);
} else {
stats.dumpSummaryLocked(pw, reqPackage, now, activeOnly);
}
@@ -643,6 +752,8 @@ public final class ProcessStatsService extends IProcessStats.Stub {
pw.println(" --max: for -a, max num of historical batches to print.");
pw.println(" --active: only show currently active processes/services.");
pw.println(" --commit: commit current stats to disk and reset to start new stats.");
pw.println(" --section: proc|pkg-proc|pkg-svc|pkg-asc|pkg-all|all ");
pw.println(" options can be combined to select desired stats");
pw.println(" --reset: reset current stats, without committing.");
pw.println(" --clear: clear all stats; does both --reset and deletes old stats.");
pw.println(" --write: write current in-memory stats to disk.");
@@ -696,6 +807,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {
int[] csvMemStats = new int[] { ProcessStats.ADJ_MEM_FACTOR_CRITICAL};
boolean csvSepProcStats = true;
int[] csvProcStats = ProcessStats.ALL_PROC_STATES;
int section = ProcessStats.REPORT_ALL;
if (args != null) {
for (int i=0; i<args.length; i++) {
String arg = args[i];
@@ -814,13 +926,14 @@ public final class ProcessStatsService extends IProcessStats.Stub {
pw.println("Process stats committed.");
quit = true;
}
} else if ("--reset".equals(arg)) {
synchronized (mAm) {
mProcessStats.resetSafely();
mAm.requestPssAllProcsLocked(SystemClock.uptimeMillis(), true, false);
pw.println("Process stats reset.");
quit = true;
} else if ("--section".equals(arg)) {
i++;
if (i >= args.length) {
pw.println("Error: argument required for --section");
dumpHelp(pw);
return;
}
section = parseSectionOptions(args[i]);
} else if ("--clear".equals(arg)) {
synchronized (mAm) {
mProcessStats.resetSafely();
@@ -946,7 +1059,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {
} else if (aggregateHours != 0) {
pw.print("AGGREGATED OVER LAST "); pw.print(aggregateHours); pw.println(" HOURS:");
dumpAggregatedStats(pw, aggregateHours, now, reqPackage, isCompact,
dumpDetails, dumpFullDetails, dumpAll, activeOnly);
dumpDetails, dumpFullDetails, dumpAll, activeOnly, section);
return;
} else if (lastIndex > 0) {
pw.print("LAST STATS AT INDEX "); pw.print(lastIndex); pw.println(":");
@@ -968,7 +1081,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {
boolean checkedIn = fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX);
if (isCheckin || isCompact) {
// Don't really need to lock because we uniquely own this object.
processStats.dumpCheckinLocked(pw, reqPackage);
processStats.dumpCheckinLocked(pw, reqPackage, section);
} else {
pw.print("COMMITTED STATS FROM ");
pw.print(processStats.mTimePeriodStartClockStr);
@@ -976,7 +1089,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {
pw.println(":");
if (dumpDetails || dumpFullDetails) {
processStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails,
dumpAll, activeOnly);
dumpAll, activeOnly, section);
if (dumpAll) {
pw.print(" mFile="); pw.println(mFile.getBaseFile());
}
@@ -1015,7 +1128,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {
boolean checkedIn = fileStr.endsWith(STATE_FILE_CHECKIN_SUFFIX);
if (isCheckin || isCompact) {
// Don't really need to lock because we uniquely own this object.
processStats.dumpCheckinLocked(pw, reqPackage);
processStats.dumpCheckinLocked(pw, reqPackage, section);
} else {
if (sepNeeded) {
pw.println();
@@ -1031,7 +1144,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {
// much crud.
if (dumpFullDetails) {
processStats.dumpLocked(pw, reqPackage, now, false, false,
false, activeOnly);
false, activeOnly, section);
} else {
processStats.dumpSummaryLocked(pw, reqPackage, now, activeOnly);
}
@@ -1054,7 +1167,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {
if (!isCheckin) {
synchronized (mAm) {
if (isCompact) {
mProcessStats.dumpCheckinLocked(pw, reqPackage);
mProcessStats.dumpCheckinLocked(pw, reqPackage, section);
} else {
if (sepNeeded) {
pw.println();
@@ -1062,7 +1175,7 @@ public final class ProcessStatsService extends IProcessStats.Stub {
pw.println("CURRENT STATS:");
if (dumpDetails || dumpFullDetails) {
mProcessStats.dumpLocked(pw, reqPackage, now, !dumpFullDetails, dumpDetails,
dumpAll, activeOnly);
dumpAll, activeOnly, section);
if (dumpAll) {
pw.print(" mFile="); pw.println(mFile.getBaseFile());
}
@@ -1078,11 +1191,11 @@ public final class ProcessStatsService extends IProcessStats.Stub {
}
pw.println("AGGREGATED OVER LAST 24 HOURS:");
dumpAggregatedStats(pw, 24, now, reqPackage, isCompact,
dumpDetails, dumpFullDetails, dumpAll, activeOnly);
dumpDetails, dumpFullDetails, dumpAll, activeOnly, section);
pw.println();
pw.println("AGGREGATED OVER LAST 3 HOURS:");
dumpAggregatedStats(pw, 3, now, reqPackage, isCompact,
dumpDetails, dumpFullDetails, dumpAll, activeOnly);
dumpDetails, dumpFullDetails, dumpAll, activeOnly, section);
}
}
}
@@ -1099,7 +1212,9 @@ public final class ProcessStatsService extends IProcessStats.Stub {
if (stats.mReadError != null) {
return;
}
stats.writeToProto(proto, fieldId, now);
final long token = proto.start(fieldId);
stats.writeToProto(proto, now, ProcessStats.REPORT_ALL);
proto.end(token);
}
private void dumpProto(FileDescriptor fd) {
@@ -1109,7 +1224,9 @@ public final class ProcessStatsService extends IProcessStats.Stub {
long now;
synchronized (mAm) {
now = SystemClock.uptimeMillis();
mProcessStats.writeToProto(proto,ProcessStatsServiceDumpProto.PROCSTATS_NOW, now);
final long token = proto.start(ProcessStatsServiceDumpProto.PROCSTATS_NOW);
mProcessStats.writeToProto(proto, now, ProcessStats.REPORT_ALL);
proto.end(token);
}
// aggregated over last 3 hours procstats