Loading core/java/com/android/internal/app/procstats/ProcessState.java +1 −0 Original line number Diff line number Diff line Loading @@ -473,6 +473,7 @@ public final class ProcessState { } } mCurCombinedState = state; mStats.mUidStates.get(mUid).updateCombinedState(state, now); } } Loading core/java/com/android/internal/app/procstats/ProcessStats.java +112 −5 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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]; Loading Loading @@ -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); Loading @@ -358,8 +374,20 @@ 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 " Loading Loading @@ -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); Loading Loading @@ -580,6 +609,7 @@ public final class ProcessStats implements Parcelable { } } else { ps.makeDead(); mUidStates.get(uids.keyAt(iu)).removeProcess(ps, now); uids.removeAt(iu); } } Loading @@ -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); } Loading Loading @@ -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)); Loading Loading @@ -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(); } Loading Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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()) { Loading Loading @@ -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) { Loading core/java/com/android/internal/app/procstats/ProcessStatsInternal.java 0 → 100644 +31 −0 Original line number Diff line number Diff line /* * 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); } core/java/com/android/internal/app/procstats/UidState.java 0 → 100644 +315 −0 Original line number Diff line number Diff line /* * 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(); } } } services/core/java/com/android/server/am/ActivityManagerService.java +1 −0 Original line number Diff line number Diff line Loading @@ -2397,6 +2397,7 @@ public class ActivityManagerService extends IActivityManager.Stub mBatteryStatsService.publish(); mAppOpsService.publish(); mProcessStats.publish(); Slog.d("AppOps", "AppOpsService published"); LocalServices.addService(ActivityManagerInternal.class, mInternal); LocalManagerRegistry.addManager(ActivityManagerLocal.class, Loading Loading
core/java/com/android/internal/app/procstats/ProcessState.java +1 −0 Original line number Diff line number Diff line Loading @@ -473,6 +473,7 @@ public final class ProcessState { } } mCurCombinedState = state; mStats.mUidStates.get(mUid).updateCombinedState(state, now); } } Loading
core/java/com/android/internal/app/procstats/ProcessStats.java +112 −5 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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]; Loading Loading @@ -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); Loading @@ -358,8 +374,20 @@ 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 " Loading Loading @@ -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); Loading Loading @@ -580,6 +609,7 @@ public final class ProcessStats implements Parcelable { } } else { ps.makeDead(); mUidStates.get(uids.keyAt(iu)).removeProcess(ps, now); uids.removeAt(iu); } } Loading @@ -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); } Loading Loading @@ -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)); Loading Loading @@ -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(); } Loading Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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()) { Loading Loading @@ -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) { Loading
core/java/com/android/internal/app/procstats/ProcessStatsInternal.java 0 → 100644 +31 −0 Original line number Diff line number Diff line /* * 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); }
core/java/com/android/internal/app/procstats/UidState.java 0 → 100644 +315 −0 Original line number Diff line number Diff line /* * 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(); } } }
services/core/java/com/android/server/am/ActivityManagerService.java +1 −0 Original line number Diff line number Diff line Loading @@ -2397,6 +2397,7 @@ public class ActivityManagerService extends IActivityManager.Stub mBatteryStatsService.publish(); mAppOpsService.publish(); mProcessStats.publish(); Slog.d("AppOps", "AppOpsService published"); LocalServices.addService(ActivityManagerInternal.class, mInternal); LocalManagerRegistry.addManager(ActivityManagerLocal.class, Loading