Support time-in-state proc stats for UIDs
Bug: 200326767 Test: atest ProcStatsValidationTests Test: atest ProcessStatsDumpsysTest Test: Manual - dumpsys procstats -a Change-Id: Ic2da178c244706bb43488e57fb808a77225bad6d
This commit is contained in:
@@ -473,6 +473,7 @@ public final class ProcessState {
|
||||
}
|
||||
}
|
||||
mCurCombinedState = state;
|
||||
mStats.mUidStates.get(mUid).updateCombinedState(state, now);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -179,17 +179,19 @@ public final class ProcessStats implements Parcelable {
|
||||
public static final int REPORT_PKG_ASC_STATS = 0x08;
|
||||
// Should report package stats.
|
||||
public static final int REPORT_PKG_STATS = 0x0E;
|
||||
// Should report uid stats.
|
||||
public static final int REPORT_UID_STATS = 0x10;
|
||||
// Should report all stats.
|
||||
public static final int REPORT_ALL = 0x0F;
|
||||
public static final int REPORT_ALL = 0x1F;
|
||||
|
||||
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};
|
||||
REPORT_PKG_STATS, REPORT_UID_STATS, REPORT_ALL};
|
||||
public static final String[] OPTIONS_STR =
|
||||
{"proc", "pkg-proc", "pkg-svc", "pkg-asc", "pkg-all", "all"};
|
||||
{"proc", "pkg-proc", "pkg-svc", "pkg-asc", "pkg-all", "uid", "all"};
|
||||
|
||||
// Current version of the parcel format.
|
||||
private static final int PARCEL_VERSION = 40;
|
||||
private static final int PARCEL_VERSION = 41;
|
||||
// In-memory Parcel magic number, used to detect attempts to unmarshall bad data
|
||||
private static final int MAGIC = 0x50535454;
|
||||
|
||||
@@ -200,6 +202,8 @@ public final class ProcessStats implements Parcelable {
|
||||
public final ProcessMap<LongSparseArray<PackageState>> mPackages = new ProcessMap<>();
|
||||
public final ProcessMap<ProcessState> mProcesses = new ProcessMap<>();
|
||||
|
||||
public final SparseArray<UidState> mUidStates = new SparseArray<>();
|
||||
|
||||
public final ArrayList<AssociationState.SourceState> mTrackingAssociations = new ArrayList<>();
|
||||
|
||||
public final long[] mMemFactorDurations = new long[ADJ_COUNT];
|
||||
@@ -337,6 +341,18 @@ public final class ProcessStats implements Parcelable {
|
||||
}
|
||||
}
|
||||
|
||||
SparseArray<UidState> uidStates = other.mUidStates;
|
||||
for (int ip = 0, size = uidStates.size(); ip < size; ip++) {
|
||||
final int uid = uidStates.keyAt(ip);
|
||||
UidState uidState = mUidStates.get(uid);
|
||||
if (uidState == null) {
|
||||
uidState = uidStates.valueAt(ip).clone();
|
||||
mUidStates.put(uid, uidState);
|
||||
} else {
|
||||
uidState.add(uidStates.valueAt(ip));
|
||||
}
|
||||
}
|
||||
|
||||
ArrayMap<String, SparseArray<ProcessState>> procMap = other.mProcesses.getMap();
|
||||
for (int ip=0; ip<procMap.size(); ip++) {
|
||||
SparseArray<ProcessState> uids = procMap.valueAt(ip);
|
||||
@@ -358,9 +374,21 @@ public final class ProcessStats implements Parcelable {
|
||||
}
|
||||
}
|
||||
thisProc.add(otherProc);
|
||||
if (thisProc.isActive()) {
|
||||
UidState uidState = mUidStates.get(uid);
|
||||
if (uidState == null) {
|
||||
uidState = new UidState(this, uid);
|
||||
mUidStates.put(uid, uidState);
|
||||
}
|
||||
uidState.addProcess(thisProc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int ip = 0, size = mUidStates.size(); ip < size; ip++) {
|
||||
mUidStates.valueAt(ip).updateCombinedState(-1);
|
||||
}
|
||||
|
||||
for (int i=0; i<ADJ_COUNT; i++) {
|
||||
if (DEBUG) Slog.d(TAG, "Total duration #" + i + " inc by "
|
||||
+ other.mMemFactorDurations[i] + " from "
|
||||
@@ -488,6 +516,7 @@ public final class ProcessStats implements Parcelable {
|
||||
resetCommon();
|
||||
mPackages.getMap().clear();
|
||||
mProcesses.getMap().clear();
|
||||
mUidStates.clear();
|
||||
mMemFactor = STATE_NOTHING;
|
||||
mStartTime = 0;
|
||||
if (DEBUG) Slog.d(TAG, "State reset; now " + mTimePeriodStartClockStr);
|
||||
@@ -580,6 +609,7 @@ public final class ProcessStats implements Parcelable {
|
||||
}
|
||||
} else {
|
||||
ps.makeDead();
|
||||
mUidStates.get(uids.keyAt(iu)).removeProcess(ps, now);
|
||||
uids.removeAt(iu);
|
||||
}
|
||||
}
|
||||
@@ -588,6 +618,15 @@ public final class ProcessStats implements Parcelable {
|
||||
}
|
||||
}
|
||||
|
||||
for (int ip = mUidStates.size() - 1; ip >= 0; ip--) {
|
||||
final UidState uidState = mUidStates.valueAt(ip);
|
||||
if (uidState.isInUse()) {
|
||||
mUidStates.valueAt(ip).resetSafely(now);
|
||||
} else {
|
||||
mUidStates.removeAt(ip);
|
||||
}
|
||||
}
|
||||
|
||||
mStartTime = now;
|
||||
if (DEBUG) Slog.d(TAG, "State reset; now " + mTimePeriodStartClockStr);
|
||||
}
|
||||
@@ -900,6 +939,13 @@ public final class ProcessStats implements Parcelable {
|
||||
|
||||
mSysMemUsage.writeToParcel(out);
|
||||
|
||||
final int numOfUids = mUidStates.size();
|
||||
out.writeInt(numOfUids);
|
||||
for (int ip = 0; ip < numOfUids; ip++) {
|
||||
out.writeInt(mUidStates.keyAt(ip));
|
||||
mUidStates.valueAt(ip).writeToParcel(out, now);
|
||||
}
|
||||
|
||||
out.writeInt(NPROC);
|
||||
for (int ip=0; ip<NPROC; ip++) {
|
||||
writeCommonString(out, procMap.keyAt(ip));
|
||||
@@ -1026,7 +1072,8 @@ public final class ProcessStats implements Parcelable {
|
||||
|
||||
public void readFromParcel(Parcel in) {
|
||||
final boolean hadData = mPackages.getMap().size() > 0
|
||||
|| mProcesses.getMap().size() > 0;
|
||||
|| mProcesses.getMap().size() > 0
|
||||
|| mUidStates.size() > 0;
|
||||
if (hadData) {
|
||||
resetSafely();
|
||||
}
|
||||
@@ -1083,6 +1130,16 @@ public final class ProcessStats implements Parcelable {
|
||||
return;
|
||||
}
|
||||
|
||||
final int numOfUids = in.readInt();
|
||||
for (int ip = 0; ip < numOfUids; ip++) {
|
||||
final int uid = in.readInt();
|
||||
final UidState uidState = new UidState(this, uid);
|
||||
if (!uidState.readFromParcel(in)) {
|
||||
return;
|
||||
}
|
||||
mUidStates.put(uid, uidState);
|
||||
}
|
||||
|
||||
int NPROC = in.readInt();
|
||||
if (NPROC < 0) {
|
||||
mReadError = "bad process count: " + NPROC;
|
||||
@@ -1127,9 +1184,17 @@ public final class ProcessStats implements Parcelable {
|
||||
if (DEBUG_PARCEL) Slog.d(TAG, "Adding process: " + procName + " " + uid
|
||||
+ " " + proc);
|
||||
mProcesses.put(procName, uid, proc);
|
||||
|
||||
if (proc.isActive()) {
|
||||
mUidStates.get(uid).addProcess(proc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int ip = 0; ip < numOfUids; ip++) {
|
||||
mUidStates.valueAt(ip).updateCombinedState(-1);
|
||||
}
|
||||
|
||||
if (DEBUG_PARCEL) Slog.d(TAG, "Read " + mProcesses.getMap().size() + " processes");
|
||||
|
||||
int NPKG = in.readInt();
|
||||
@@ -1327,6 +1392,12 @@ public final class ProcessStats implements Parcelable {
|
||||
commonProc = new ProcessState(this, pkgState.mPackageName, pkgState.mUid,
|
||||
pkgState.mVersionCode, processName);
|
||||
mProcesses.put(processName, pkgState.mUid, commonProc);
|
||||
UidState uidState = mUidStates.get(pkgState.mUid);
|
||||
if (uidState == null) {
|
||||
uidState = new UidState(this, pkgState.mUid);
|
||||
mUidStates.put(pkgState.mUid, uidState);
|
||||
}
|
||||
uidState.addProcess(commonProc);
|
||||
if (DEBUG) Slog.d(TAG, "GETPROC created new common " + commonProc);
|
||||
}
|
||||
if (!commonProc.isMultiPackage()) {
|
||||
@@ -1787,6 +1858,42 @@ public final class ProcessStats implements Parcelable {
|
||||
pw.print(" shown of "); pw.print(numTotalProcs); pw.println(" total");
|
||||
}
|
||||
|
||||
if ((section & REPORT_UID_STATS) != 0) {
|
||||
SparseArray<UidState> uidStates = mUidStates;
|
||||
int numShownUids = 0, numTotalUids = 0;
|
||||
printedHeader = false;
|
||||
for (int iu = 0, size = uidStates.size(); iu < size; iu++) {
|
||||
final int uid = uidStates.keyAt(iu);
|
||||
final UidState uidState = uidStates.valueAt(iu);
|
||||
numTotalUids++;
|
||||
if (reqPackage != null && !uidState.hasPackage(reqPackage)) {
|
||||
continue;
|
||||
}
|
||||
numShownUids++;
|
||||
pw.println();
|
||||
if (!printedHeader) {
|
||||
pw.println("Per-UID Stats:");
|
||||
printedHeader = true;
|
||||
}
|
||||
if (activeOnly && !uidState.isInUse()) {
|
||||
pw.print(" (Not active: ");
|
||||
pw.print(UserHandle.formatUid(uid));
|
||||
pw.println(")");
|
||||
continue;
|
||||
}
|
||||
pw.print(" * ");
|
||||
UserHandle.formatUid(pw, uid);
|
||||
pw.print(" (");
|
||||
pw.print(uidState.getDurationsBucketCount());
|
||||
pw.print(" entries)");
|
||||
pw.println(":");
|
||||
uidState.dumpState(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
|
||||
ALL_PROC_STATES, now);
|
||||
}
|
||||
pw.print(" Total UIDs: "); pw.print(numShownUids);
|
||||
pw.print(" shown of "); pw.print(numTotalUids); pw.println(" total");
|
||||
}
|
||||
|
||||
if (dumpAll) {
|
||||
pw.println();
|
||||
if (mTrackingAssociations.size() > 0) {
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.internal.app.procstats;
|
||||
|
||||
import android.util.SparseArray;
|
||||
|
||||
/**
|
||||
* The internal interface to access the process stats service, to be used within
|
||||
* system_server only.
|
||||
*/
|
||||
public abstract class ProcessStatsInternal {
|
||||
/**
|
||||
* Return the duration over the given time, that an UID spent in each processs state
|
||||
* which is defined in the {@link ProcessStats}, the key of the array is the uid.
|
||||
*/
|
||||
public abstract SparseArray<long[]> getUidProcStateStatsOverTime(long minTime);
|
||||
}
|
||||
315
core/java/com/android/internal/app/procstats/UidState.java
Normal file
315
core/java/com/android/internal/app/procstats/UidState.java
Normal file
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.internal.app.procstats;
|
||||
|
||||
import static com.android.internal.app.procstats.ProcessStats.STATE_COUNT;
|
||||
import static com.android.internal.app.procstats.ProcessStats.STATE_NOTHING;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.UserHandle;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArraySet;
|
||||
import android.util.TimeUtils;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* The class to track the individual time-in-state of a UID.
|
||||
*/
|
||||
public final class UidState {
|
||||
private static final String TAG = "ProcessStats";
|
||||
|
||||
private final ProcessStats mStats;
|
||||
private final int mUid;
|
||||
private final DurationsTable mDurations;
|
||||
|
||||
private ArraySet<ProcessState> mProcesses = new ArraySet<>();
|
||||
private int mCurCombinedState = STATE_NOTHING;
|
||||
private long mStartTime;
|
||||
|
||||
private long mTotalRunningStartTime;
|
||||
private long mTotalRunningDuration;
|
||||
|
||||
/**
|
||||
* Create a new UID state. The initial state is not running.
|
||||
*/
|
||||
public UidState(ProcessStats processStats, int uid) {
|
||||
mStats = processStats;
|
||||
mUid = uid;
|
||||
mDurations = new DurationsTable(processStats.mTableData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a copy of this instance.
|
||||
*/
|
||||
public UidState clone() {
|
||||
UidState unew = new UidState(mStats, mUid);
|
||||
unew.mDurations.addDurations(mDurations);
|
||||
unew.mCurCombinedState = mCurCombinedState;
|
||||
unew.mStartTime = mStartTime;
|
||||
unew.mTotalRunningStartTime = mTotalRunningStartTime;
|
||||
unew.mTotalRunningDuration = mTotalRunningDuration;
|
||||
return unew;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the current state of the UID, it should be a combination
|
||||
* of all running processes in this UID.
|
||||
*/
|
||||
public void updateCombinedState(int state, long now) {
|
||||
if (mCurCombinedState != state) {
|
||||
updateCombinedState(now);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the current state of the UID, it should be a combination
|
||||
* of all running processes in this UID.
|
||||
*/
|
||||
public void updateCombinedState(long now) {
|
||||
setCombinedStateInner(calcCombinedState(), now);
|
||||
}
|
||||
|
||||
private int calcCombinedState() {
|
||||
int minCombined = STATE_NOTHING;
|
||||
int min = STATE_NOTHING;
|
||||
for (int i = 0, size = mProcesses.size(); i < size; i++) {
|
||||
final int combinedState = mProcesses.valueAt(i).getCombinedState();
|
||||
final int state = combinedState % STATE_COUNT;
|
||||
if (combinedState != STATE_NOTHING) {
|
||||
if (min == STATE_NOTHING || state < min) {
|
||||
minCombined = combinedState;
|
||||
min = state;
|
||||
}
|
||||
}
|
||||
}
|
||||
return minCombined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the combined state and commit the state.
|
||||
*
|
||||
* @param now When it's negative, the previous state won't be committed.
|
||||
*/
|
||||
private void setCombinedStateInner(int state, long now) {
|
||||
if (mCurCombinedState != state) {
|
||||
if (now >= 0) {
|
||||
commitStateTime(now);
|
||||
if (state == STATE_NOTHING) {
|
||||
// We are transitioning to a no longer running state... stop counting run time.
|
||||
mTotalRunningDuration += now - mTotalRunningStartTime;
|
||||
} else if (mCurCombinedState == STATE_NOTHING) {
|
||||
// We previously weren't running... now starting again, clear out total
|
||||
// running info.
|
||||
mTotalRunningDuration = 0;
|
||||
}
|
||||
}
|
||||
mCurCombinedState = state;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The current combine state of the UID.
|
||||
*/
|
||||
public int getCombinedState() {
|
||||
return mCurCombinedState;
|
||||
}
|
||||
|
||||
/**
|
||||
* Commit the current state's duration into stats.
|
||||
*/
|
||||
public void commitStateTime(long now) {
|
||||
if (mCurCombinedState != STATE_NOTHING) {
|
||||
long dur = now - mStartTime;
|
||||
if (dur > 0) {
|
||||
mDurations.addDuration(mCurCombinedState, dur);
|
||||
}
|
||||
mTotalRunningDuration += now - mTotalRunningStartTime;
|
||||
mTotalRunningStartTime = now;
|
||||
}
|
||||
mStartTime = now;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the UID stats safely.
|
||||
*/
|
||||
public void resetSafely(long now) {
|
||||
mDurations.resetTable();
|
||||
mStartTime = now;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether this UID stats is still being used or not.
|
||||
*/
|
||||
public boolean isInUse() {
|
||||
for (int i = 0, size = mProcesses.size(); i < size; i++) {
|
||||
if (mProcesses.valueAt(i).isInUse()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether the given package belongs to this UID or not.
|
||||
*/
|
||||
public boolean hasPackage(String packageName) {
|
||||
for (int i = 0, size = mProcesses.size(); i < size; i++) {
|
||||
final ProcessState proc = mProcesses.valueAt(i);
|
||||
if (TextUtils.equals(packageName, proc.getName())
|
||||
&& TextUtils.equals(packageName, proc.getPackage())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add stats data from another instance to this one.
|
||||
*/
|
||||
public void add(UidState other) {
|
||||
mDurations.addDurations(other.mDurations);
|
||||
mTotalRunningDuration += other.mTotalRunningDuration;
|
||||
}
|
||||
|
||||
void addProcess(ProcessState proc) {
|
||||
mProcesses.add(proc);
|
||||
}
|
||||
|
||||
void addProcess(ProcessState proc, long now) {
|
||||
mProcesses.add(proc);
|
||||
setCombinedStateInner(proc.getCombinedState(), now);
|
||||
}
|
||||
|
||||
void removeProcess(ProcessState proc, long now) {
|
||||
mProcesses.remove(proc);
|
||||
setCombinedStateInner(proc.getCombinedState(), now);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The total amount of stats it's currently tracking.
|
||||
*/
|
||||
public int getDurationsBucketCount() {
|
||||
return mDurations.getKeyCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The total running duration of this UID.
|
||||
*/
|
||||
public long getTotalRunningDuration(long now) {
|
||||
return mTotalRunningDuration
|
||||
+ (mTotalRunningStartTime != 0 ? (now - mTotalRunningStartTime) : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The duration in the given state.
|
||||
*/
|
||||
public long getDuration(int state, long now) {
|
||||
long time = mDurations.getValueForId((byte) state);
|
||||
if (mCurCombinedState == state) {
|
||||
time += now - mStartTime;
|
||||
}
|
||||
return time;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The durations in each process state, the mem/screen factors
|
||||
* are consolidated into the bucket with the same process state.
|
||||
*/
|
||||
public long[] getAggregatedDurationsInStates() {
|
||||
final long[] states = new long[STATE_COUNT];
|
||||
final int numOfBuckets = getDurationsBucketCount();
|
||||
for (int i = 0; i < numOfBuckets; i++) {
|
||||
final int key = mDurations.getKeyAt(i);
|
||||
final int combinedState = SparseMappingTable.getIdFromKey(key);
|
||||
states[combinedState % STATE_COUNT] += mDurations.getValue(key);
|
||||
}
|
||||
return states;
|
||||
}
|
||||
|
||||
void writeToParcel(Parcel out, long now) {
|
||||
mDurations.writeToParcel(out);
|
||||
out.writeLong(getTotalRunningDuration(now));
|
||||
}
|
||||
|
||||
boolean readFromParcel(Parcel in) {
|
||||
if (!mDurations.readFromParcel(in)) {
|
||||
return false;
|
||||
}
|
||||
mTotalRunningDuration = in.readLong();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(128);
|
||||
sb.append("UidState{").append(Integer.toHexString(System.identityHashCode(this)))
|
||||
.append(" ").append(UserHandle.formatUid(mUid)).append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
void dumpState(PrintWriter pw, String prefix,
|
||||
int[] screenStates, int[] memStates, int[] procStates, long now) {
|
||||
long totalTime = 0;
|
||||
int printedScreen = -1;
|
||||
for (int is = 0; is < screenStates.length; is++) {
|
||||
int printedMem = -1;
|
||||
for (int im = 0; im < memStates.length; im++) {
|
||||
for (int ip = 0; ip < procStates.length; ip++) {
|
||||
final int iscreen = screenStates[is];
|
||||
final int imem = memStates[im];
|
||||
final int bucket = ((iscreen + imem) * STATE_COUNT) + procStates[ip];
|
||||
long time = mDurations.getValueForId((byte) bucket);
|
||||
String running = "";
|
||||
if (mCurCombinedState == bucket) {
|
||||
running = " (running)";
|
||||
time += now - mStartTime;
|
||||
}
|
||||
if (time != 0) {
|
||||
pw.print(prefix);
|
||||
if (screenStates.length > 1) {
|
||||
DumpUtils.printScreenLabel(pw, printedScreen != iscreen
|
||||
? iscreen : STATE_NOTHING);
|
||||
printedScreen = iscreen;
|
||||
}
|
||||
if (memStates.length > 1) {
|
||||
DumpUtils.printMemLabel(pw,
|
||||
printedMem != imem ? imem : STATE_NOTHING, '/');
|
||||
printedMem = imem;
|
||||
}
|
||||
pw.print(DumpUtils.STATE_LABELS[procStates[ip]]); pw.print(": ");
|
||||
TimeUtils.formatDuration(time, pw); pw.println(running);
|
||||
totalTime += time;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (totalTime != 0) {
|
||||
pw.print(prefix);
|
||||
if (screenStates.length > 1) {
|
||||
DumpUtils.printScreenLabel(pw, STATE_NOTHING);
|
||||
}
|
||||
if (memStates.length > 1) {
|
||||
DumpUtils.printMemLabel(pw, STATE_NOTHING, '/');
|
||||
}
|
||||
pw.print(DumpUtils.STATE_LABEL_TOTAL);
|
||||
pw.print(": ");
|
||||
TimeUtils.formatDuration(totalTime, pw);
|
||||
pw.println();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2397,6 +2397,7 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
CriticalEventLog.init();
|
||||
mBatteryStatsService.publish();
|
||||
mAppOpsService.publish();
|
||||
mProcessStats.publish();
|
||||
Slog.d("AppOps", "AppOpsService published");
|
||||
LocalServices.addService(ActivityManagerInternal.class, mInternal);
|
||||
LocalManagerRegistry.addManager(ActivityManagerLocal.class,
|
||||
|
||||
@@ -38,8 +38,11 @@ import com.android.internal.app.procstats.DumpUtils;
|
||||
import com.android.internal.app.procstats.IProcessStats;
|
||||
import com.android.internal.app.procstats.ProcessState;
|
||||
import com.android.internal.app.procstats.ProcessStats;
|
||||
import com.android.internal.app.procstats.ProcessStatsInternal;
|
||||
import com.android.internal.app.procstats.ServiceState;
|
||||
import com.android.internal.app.procstats.UidState;
|
||||
import com.android.internal.os.BackgroundThread;
|
||||
import com.android.server.LocalServices;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileDescriptor;
|
||||
@@ -783,6 +786,64 @@ public final class ProcessStatsService extends IProcessStats.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
private SparseArray<long[]> getUidProcStateStatsOverTime(long minTime) {
|
||||
final Parcel current = Parcel.obtain();
|
||||
final ProcessStats stats = new ProcessStats();
|
||||
long curTime;
|
||||
synchronized (mLock) {
|
||||
final long now = SystemClock.uptimeMillis();
|
||||
mProcessStats.mTimePeriodEndRealtime = SystemClock.elapsedRealtime();
|
||||
mProcessStats.mTimePeriodEndUptime = now;
|
||||
stats.add(mProcessStats);
|
||||
curTime = mProcessStats.mTimePeriodEndRealtime - mProcessStats.mTimePeriodStartRealtime;
|
||||
}
|
||||
if (curTime < minTime) {
|
||||
try {
|
||||
mFileLock.lock();
|
||||
// Need to add in older stats to reach desired time.
|
||||
ArrayList<String> files = getCommittedFilesLF(0, false, true);
|
||||
if (files != null && files.size() > 0) {
|
||||
int i = files.size() - 1;
|
||||
while (i >= 0 && (stats.mTimePeriodEndRealtime
|
||||
- stats.mTimePeriodStartRealtime) < minTime) {
|
||||
AtomicFile file = new AtomicFile(new File(files.get(i)));
|
||||
i--;
|
||||
ProcessStats moreStats = new ProcessStats(false);
|
||||
readLF(moreStats, file);
|
||||
if (moreStats.mReadError == null) {
|
||||
stats.add(moreStats);
|
||||
} else {
|
||||
Slog.w(TAG, "Failure reading " + files.get(i + 1) + "; "
|
||||
+ moreStats.mReadError);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
mFileLock.unlock();
|
||||
}
|
||||
}
|
||||
final SparseArray<UidState> uidStates = stats.mUidStates;
|
||||
final SparseArray<long[]> results = new SparseArray<>();
|
||||
for (int i = 0, size = uidStates.size(); i < size; i++) {
|
||||
final int uid = uidStates.keyAt(i);
|
||||
final UidState uidState = uidStates.valueAt(i);
|
||||
results.put(uid, uidState.getAggregatedDurationsInStates());
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
void publish() {
|
||||
LocalServices.addService(ProcessStatsInternal.class, new LocalService());
|
||||
}
|
||||
|
||||
private final class LocalService extends ProcessStatsInternal {
|
||||
@Override
|
||||
public SparseArray<long[]> getUidProcStateStatsOverTime(long minTime) {
|
||||
return ProcessStatsService.this.getUidProcStateStatsOverTime(minTime);
|
||||
}
|
||||
}
|
||||
|
||||
private void dumpAggregatedStats(PrintWriter pw, long aggregateHours, long now,
|
||||
String reqPackage, boolean isCompact, boolean dumpDetails, boolean dumpFullDetails,
|
||||
boolean dumpAll, boolean activeOnly, int section) {
|
||||
|
||||
Reference in New Issue
Block a user