Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 72eee56f authored by Jing Ji's avatar Jing Ji Committed by Android (Google) Code Review
Browse files

Merge "Support aggregation over association sources per process" into sc-dev

parents fd734e66 276ff21a
Loading
Loading
Loading
Loading
+332 −159

File changed.

Preview size limit exceeded, changes collapsed.

+84 −3
Original line number Original line Diff line number Diff line
@@ -63,6 +63,8 @@ import android.util.proto.ProtoOutputStream;
import android.util.proto.ProtoUtils;
import android.util.proto.ProtoUtils;


import com.android.internal.app.ProcessMap;
import com.android.internal.app.ProcessMap;
import com.android.internal.app.procstats.AssociationState.SourceKey;
import com.android.internal.app.procstats.AssociationState.SourceState;
import com.android.internal.app.procstats.ProcessStats.PackageState;
import com.android.internal.app.procstats.ProcessStats.PackageState;
import com.android.internal.app.procstats.ProcessStats.ProcessStateHolder;
import com.android.internal.app.procstats.ProcessStats.ProcessStateHolder;
import com.android.internal.app.procstats.ProcessStats.TotalMemoryUseCollection;
import com.android.internal.app.procstats.ProcessStats.TotalMemoryUseCollection;
@@ -162,6 +164,11 @@ public final class ProcessState {
    // Set in computeProcessTimeLocked and used by COMPARATOR to sort. Be careful.
    // Set in computeProcessTimeLocked and used by COMPARATOR to sort. Be careful.
    private long mTmpTotalTime;
    private long mTmpTotalTime;


    /**
     * The combined source states which has or had an association with this process.
     */
    ArrayMap<SourceKey, SourceState> mCommonSources;

    /**
    /**
     * Create a new top-level process state, for the initial case where there is only
     * Create a new top-level process state, for the initial case where there is only
     * a single package running in a process.  The initial state is not running.
     * a single package running in a process.  The initial state is not running.
@@ -267,6 +274,21 @@ public final class ProcessState {
            addCachedKill(other.mNumCachedKill, other.mMinCachedKillPss,
            addCachedKill(other.mNumCachedKill, other.mMinCachedKillPss,
                    other.mAvgCachedKillPss, other.mMaxCachedKillPss);
                    other.mAvgCachedKillPss, other.mMaxCachedKillPss);
        }
        }
        if (other.mCommonSources != null) {
            if (mCommonSources == null) {
                mCommonSources = new ArrayMap<>();
            }
            int size = other.mCommonSources.size();
            for (int i = 0; i < size; i++) {
                final SourceKey key = other.mCommonSources.keyAt(i);
                SourceState state = mCommonSources.get(key);
                if (state == null) {
                    state = new SourceState(mStats, null, this, key);
                    mCommonSources.put(key, state);
                }
                state.add(other.mCommonSources.valueAt(i));
            }
        }
    }
    }


    public void resetSafely(long now) {
    public void resetSafely(long now) {
@@ -278,6 +300,17 @@ public final class ProcessState {
        mNumExcessiveCpu = 0;
        mNumExcessiveCpu = 0;
        mNumCachedKill = 0;
        mNumCachedKill = 0;
        mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0;
        mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0;
        // Reset the combine source state.
        if (mCommonSources != null) {
            for (int ip = mCommonSources.size() - 1; ip >= 0; ip--) {
                final SourceState state = mCommonSources.valueAt(ip);
                if (state.isInUse()) {
                    state.resetSafely(now);
                } else {
                    mCommonSources.removeAt(ip);
                }
            }
        }
    }
    }


    public void makeDead() {
    public void makeDead() {
@@ -308,9 +341,18 @@ public final class ProcessState {
            out.writeLong(mAvgCachedKillPss);
            out.writeLong(mAvgCachedKillPss);
            out.writeLong(mMaxCachedKillPss);
            out.writeLong(mMaxCachedKillPss);
        }
        }
        // The combined source state of all associations.
        final int numOfSources = mCommonSources != null ? mCommonSources.size() : 0;
        out.writeInt(numOfSources);
        for (int i = 0; i < numOfSources; i++) {
            final SourceKey key = mCommonSources.keyAt(i);
            final SourceState src = mCommonSources.valueAt(i);
            key.writeToParcel(mStats, out);
            src.writeToParcel(out, 0);
        }
    }
    }


    public boolean readFromParcel(Parcel in, boolean fully) {
    boolean readFromParcel(Parcel in, int version, boolean fully) {
        boolean multiPackage = in.readInt() != 0;
        boolean multiPackage = in.readInt() != 0;
        if (fully) {
        if (fully) {
            mMultiPackage = multiPackage;
            mMultiPackage = multiPackage;
@@ -337,6 +379,19 @@ public final class ProcessState {
        } else {
        } else {
            mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0;
            mMinCachedKillPss = mAvgCachedKillPss = mMaxCachedKillPss = 0;
        }
        }

        // The combined source state of all associations.
        final int numOfSources = in.readInt();
        if (numOfSources > 0) {
            mCommonSources = new ArrayMap<>(numOfSources);
            for (int i = 0; i < numOfSources; i++) {
                final SourceKey key = new SourceKey(mStats, in, version);
                final SourceState src = new SourceState(mStats, null, this, key);
                src.readFromParcel(in);
                mCommonSources.put(key, src);
            }
        }

        return true;
        return true;
    }
    }


@@ -433,6 +488,12 @@ public final class ProcessState {
            mTotalRunningStartTime = now;
            mTotalRunningStartTime = now;
        }
        }
        mStartTime = now;
        mStartTime = now;
        if (mCommonSources != null) {
            for (int ip = mCommonSources.size() - 1; ip >= 0; ip--) {
                final SourceState src = mCommonSources.valueAt(ip);
                src.commitStateTime(now);
            }
        }
    }
    }


    public void incActiveServices(String serviceName) {
    public void incActiveServices(String serviceName) {
@@ -722,6 +783,18 @@ public final class ProcessState {
        return mPssTable.getValueForId((byte)state, PSS_RSS_MAXIMUM);
        return mPssTable.getValueForId((byte)state, PSS_RSS_MAXIMUM);
    }
    }


    SourceState getOrCreateSourceState(SourceKey key) {
        if (mCommonSources == null) {
            mCommonSources = new ArrayMap<>();
        }
        SourceState state = mCommonSources.get(key);
        if (state == null) {
            state = new SourceState(mStats, null, this, key);
            mCommonSources.put(key, state);
        }
        return state;
    }

    /**
    /**
     * Sums up the PSS data and adds it to 'data'.
     * Sums up the PSS data and adds it to 'data'.
     *
     *
@@ -1038,7 +1111,8 @@ public final class ProcessState {
        }
        }
    }
    }


    public void dumpInternalLocked(PrintWriter pw, String prefix, boolean dumpAll) {
    void dumpInternalLocked(PrintWriter pw, String prefix, String reqPackage,
            long totalTime, long now, boolean dumpAll) {
        if (dumpAll) {
        if (dumpAll) {
            pw.print(prefix); pw.print("myID=");
            pw.print(prefix); pw.print("myID=");
                    pw.print(Integer.toHexString(System.identityHashCode(this)));
                    pw.print(Integer.toHexString(System.identityHashCode(this)));
@@ -1053,6 +1127,13 @@ public final class ProcessState {
                        pw.print("/"); pw.print(mCommonProcess.mUid);
                        pw.print("/"); pw.print(mCommonProcess.mUid);
                        pw.print(" pkg="); pw.println(mCommonProcess.mPackage);
                        pw.print(" pkg="); pw.println(mCommonProcess.mPackage);
            }
            }
            if (mCommonSources != null) {
                pw.print(prefix); pw.println("Aggregated Association Sources:");
                AssociationState.dumpSources(
                        pw, prefix + "  ", prefix + "    ", prefix + "        ",
                        AssociationState.createSortedAssociations(now, totalTime, mCommonSources),
                        now, totalTime, reqPackage, true, dumpAll);
            }
        }
        }
        if (mActive) {
        if (mActive) {
            pw.print(prefix); pw.print("mActive="); pw.println(mActive);
            pw.print(prefix); pw.print("mActive="); pw.println(mActive);
@@ -1559,7 +1640,7 @@ public final class ProcessState {
        }
        }


        mStats.dumpFilteredAssociationStatesProtoForProc(proto, ProcessStatsProto.ASSOCS,
        mStats.dumpFilteredAssociationStatesProtoForProc(proto, ProcessStatsProto.ASSOCS,
                now, this, procToPkgMap, uidToPkgMap);
                now, this, uidToPkgMap);
        proto.end(token);
        proto.end(token);
    }
    }
}
}
+51 −85
Original line number Original line Diff line number Diff line
@@ -29,7 +29,6 @@ import android.service.procstats.ProcessStatsAssociationProto;
import android.service.procstats.ProcessStatsAvailablePagesProto;
import android.service.procstats.ProcessStatsAvailablePagesProto;
import android.service.procstats.ProcessStatsPackageProto;
import android.service.procstats.ProcessStatsPackageProto;
import android.service.procstats.ProcessStatsSectionProto;
import android.service.procstats.ProcessStatsSectionProto;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.text.format.DateFormat;
import android.util.ArrayMap;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.ArraySet;
@@ -187,7 +186,7 @@ public final class ProcessStats implements Parcelable {
            {"proc", "pkg-proc", "pkg-svc", "pkg-asc", "pkg-all", "all"};
            {"proc", "pkg-proc", "pkg-svc", "pkg-asc", "pkg-all", "all"};


    // Current version of the parcel format.
    // Current version of the parcel format.
    private static final int PARCEL_VERSION = 38;
    private static final int PARCEL_VERSION = 39;
    // In-memory Parcel magic number, used to detect attempts to unmarshall bad data
    // In-memory Parcel magic number, used to detect attempts to unmarshall bad data
    private static final int MAGIC = 0x50535454;
    private static final int MAGIC = 0x50535454;


@@ -1113,12 +1112,12 @@ public final class ProcessStats implements Parcelable {
                final long vers = in.readLong();
                final long vers = in.readLong();
                ProcessState proc = hadData ? mProcesses.get(procName, uid) : null;
                ProcessState proc = hadData ? mProcesses.get(procName, uid) : null;
                if (proc != null) {
                if (proc != null) {
                    if (!proc.readFromParcel(in, false)) {
                    if (!proc.readFromParcel(in, version, false)) {
                        return;
                        return;
                    }
                    }
                } else {
                } else {
                    proc = new ProcessState(this, pkgName, uid, vers, procName);
                    proc = new ProcessState(this, pkgName, uid, vers, procName);
                    if (!proc.readFromParcel(in, true)) {
                    if (!proc.readFromParcel(in, version, true)) {
                        return;
                        return;
                    }
                    }
                }
                }
@@ -1198,13 +1197,13 @@ public final class ProcessStats implements Parcelable {
                            // they will find and use it from the global procs.
                            // they will find and use it from the global procs.
                            ProcessState proc = hadData ? pkgState.mProcesses.get(procName) : null;
                            ProcessState proc = hadData ? pkgState.mProcesses.get(procName) : null;
                            if (proc != null) {
                            if (proc != null) {
                                if (!proc.readFromParcel(in, false)) {
                                if (!proc.readFromParcel(in, version, false)) {
                                    return;
                                    return;
                                }
                                }
                            } else {
                            } else {
                                proc = new ProcessState(commonProc, pkgName, uid, vers, procName,
                                proc = new ProcessState(commonProc, pkgName, uid, vers, procName,
                                        0);
                                        0);
                                if (!proc.readFromParcel(in, true)) {
                                if (!proc.readFromParcel(in, version, true)) {
                                    return;
                                    return;
                                }
                                }
                            }
                            }
@@ -1439,16 +1438,15 @@ public final class ProcessStats implements Parcelable {
        final int NUM = mTrackingAssociations.size();
        final int NUM = mTrackingAssociations.size();
        for (int i = NUM - 1; i >= 0; i--) {
        for (int i = NUM - 1; i >= 0; i--) {
            final AssociationState.SourceState act = mTrackingAssociations.get(i);
            final AssociationState.SourceState act = mTrackingAssociations.get(i);
            if (act.mProcStateSeq != curSeq || act.mProcState >= ProcessStats.STATE_HOME) {
            if (act.stopActiveIfNecessary(curSeq, now)) {
                // If this association did not get touched the last time we computed
                // process states, or its state ended up down in cached, then we no
                // longer have a reason to track it at all.
                act.stopActive(now);
                act.mInTrackingList = false;
                act.mProcState = ProcessStats.STATE_NOTHING;
                mTrackingAssociations.remove(i);
                mTrackingAssociations.remove(i);
            } else {
            } else {
                final ProcessState proc = act.getAssociationState().getProcess();
                final AssociationState asc = act.getAssociationState();
                if (asc == null) {
                    Slog.wtf(TAG, act.toString() + " shouldn't be in the tracking list.");
                    continue;
                }
                final ProcessState proc = asc.getProcess();
                if (proc != null) {
                if (proc != null) {
                    final int procState = proc.getCombinedState() % STATE_COUNT;
                    final int procState = proc.getCombinedState() % STATE_COUNT;
                    if (act.mProcState == procState) {
                    if (act.mProcState == procState) {
@@ -1476,7 +1474,7 @@ public final class ProcessStats implements Parcelable {
                } else {
                } else {
                    // Don't need rate limiting on it.
                    // Don't need rate limiting on it.
                    Slog.wtf(TAG, "Tracking association without process: " + act
                    Slog.wtf(TAG, "Tracking association without process: " + act
                            + " in " + act.getAssociationState());
                            + " in " + asc);
                }
                }
            }
            }
        }
        }
@@ -1640,7 +1638,8 @@ public final class ProcessStats implements Parcelable {
                                            ALL_PROC_STATES, now);
                                            ALL_PROC_STATES, now);
                                    proc.dumpPss(pw, "        ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
                                    proc.dumpPss(pw, "        ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
                                            ALL_PROC_STATES, now);
                                            ALL_PROC_STATES, now);
                                    proc.dumpInternalLocked(pw, "        ", dumpAll);
                                    proc.dumpInternalLocked(pw, "        ", reqPackage,
                                            totalTime, now, dumpAll);
                                }
                                }
                            } else {
                            } else {
                                ArrayList<ProcessState> procs = new ArrayList<ProcessState>();
                                ArrayList<ProcessState> procs = new ArrayList<ProcessState>();
@@ -1696,7 +1695,8 @@ public final class ProcessStats implements Parcelable {
                                }
                                }
                                final AssociationDumpContainer cont =
                                final AssociationDumpContainer cont =
                                        new AssociationDumpContainer(asc);
                                        new AssociationDumpContainer(asc);
                                cont.mSources = asc.createSortedAssociations(now, totalTime);
                                cont.mSources = AssociationState
                                        .createSortedAssociations(now, totalTime, asc.mSources);
                                cont.mTotalTime = asc.getTotalDuration(now);
                                cont.mTotalTime = asc.getTotalDuration(now);
                                cont.mActiveTime = asc.getActiveDuration(now);
                                cont.mActiveTime = asc.getActiveDuration(now);
                                associations.add(cont);
                                associations.add(cont);
@@ -1777,7 +1777,7 @@ public final class ProcessStats implements Parcelable {
                    proc.dumpProcessState(pw, "        ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
                    proc.dumpProcessState(pw, "        ", ALL_SCREEN_ADJ, ALL_MEM_ADJ,
                            ALL_PROC_STATES, now);
                            ALL_PROC_STATES, now);
                    proc.dumpPss(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);
                    proc.dumpInternalLocked(pw, "        ", reqPackage, totalTime, now, dumpAll);
                }
                }
            }
            }
            pw.print("  Total procs: "); pw.print(numShownProcs);
            pw.print("  Total procs: "); pw.print(numShownProcs);
@@ -1792,6 +1792,10 @@ public final class ProcessStats implements Parcelable {
                for (int i = 0; i < mTrackingAssociations.size(); i++) {
                for (int i = 0; i < mTrackingAssociations.size(); i++) {
                    final AssociationState.SourceState src = mTrackingAssociations.get(i);
                    final AssociationState.SourceState src = mTrackingAssociations.get(i);
                    final AssociationState asc = src.getAssociationState();
                    final AssociationState asc = src.getAssociationState();
                    if (asc == null) {
                        Slog.wtf(TAG, src.toString() + " shouldn't be in the tracking list.");
                        continue;
                    }
                    pw.print("  #");
                    pw.print("  #");
                    pw.print(i);
                    pw.print(i);
                    pw.print(": ");
                    pw.print(": ");
@@ -2353,74 +2357,32 @@ public final class ProcessStats implements Parcelable {
     * @param fieldId   The proto output field ID
     * @param fieldId   The proto output field ID
     * @param now       The timestamp when the dump was initiated.
     * @param now       The timestamp when the dump was initiated.
     * @param procState The target process where its association states should be dumped.
     * @param procState The target process where its association states should be dumped.
     * @param proc2Pkg  The map between process to packages running within it.
     * @param uidToPkgMap The map between UID to packages with this UID
     * @param uidToPkgMap The map between UID to packages with this UID
     */
     */
    public void dumpFilteredAssociationStatesProtoForProc(ProtoOutputStream proto,
    public void dumpFilteredAssociationStatesProtoForProc(ProtoOutputStream proto,
            long fieldId, long now, ProcessState procState,
            long fieldId, long now, ProcessState procState,
            final ProcessMap<ArraySet<PackageState>> proc2Pkg,
            final SparseArray<ArraySet<String>> uidToPkgMap) {
            final SparseArray<ArraySet<String>> uidToPkgMap) {
        if (procState.isMultiPackage() && procState.getCommonProcess() != procState) {
        if (procState.isMultiPackage() && procState.getCommonProcess() != procState) {
            // It's a per-package process state, don't bother to write into statsd
            // It's a per-package process state, don't bother to write into statsd
            return;
            return;
        }
        }
        ArrayMap<SourceKey, long[]> assocVals = new ArrayMap<>();
        final ArrayMap<SourceKey, SourceState> sources = procState.mCommonSources;
        final String procName = procState.getName();
        if (sources != null && !sources.isEmpty()) {
        final int procUid = procState.getUid();
        final long procVersion = procState.getVersion();
        final ArraySet<PackageState> packages = proc2Pkg.get(procName, procUid);
        if (packages == null || packages.isEmpty()) {
            // Shouldn't happen
            return;
        }
        for (int i = packages.size() - 1; i >= 0; i--) {
            final PackageState pkgState = packages.valueAt(i);
            final ArrayMap<String, AssociationState> associations = pkgState.mAssociations;
            for (int j = associations.size() - 1; j >= 0; j--) {
                final AssociationState assoc = associations.valueAt(j);
                // Make sure this association is really about this process
                if (!TextUtils.equals(assoc.getProcessName(), procName)) {
                    continue;
                }
                final ArrayMap<SourceKey, SourceState> sources = assoc.mSources;
                for (int k = sources.size() - 1; k >= 0; k--) {
                    final SourceKey key = sources.keyAt(k);
                    final SourceState state = sources.valueAt(k);
                    long[] vals = assocVals.get(key);
                    if (vals == null) {
                        vals = new long[2];
                        assocVals.put(key, vals);
                    }
                    vals[0] += state.mDuration;
                    vals[1] += state.mCount;
                    if (state.mNesting > 0) {
                        vals[0] += now - state.mStartUptime;
                    }
                }
            }
        }
            final IProcessStats procStatsService = IProcessStats.Stub.asInterface(
            final IProcessStats procStatsService = IProcessStats.Stub.asInterface(
                    ServiceManager.getService(SERVICE_NAME));
                    ServiceManager.getService(SERVICE_NAME));
            if (procStatsService != null) {
            if (procStatsService != null) {
                try {
                try {
                    final long minimum = procStatsService.getMinAssociationDumpDuration();
                    final long minimum = procStatsService.getMinAssociationDumpDuration();
                if (minimum > 0) {
                    for (int i = sources.size() - 1; i >= 0; i--) {
                    // Now filter out unnecessary ones.
                        final SourceState src = sources.valueAt(i);
                    for (int i = assocVals.size() - 1; i >= 0; i--) {
                        long duration = src.mDuration;
                        final long[] vals = assocVals.valueAt(i);
                        if (src.mNesting > 0) {
                        if (vals[0] < minimum) {
                            duration += now - src.mStartUptime;
                            assocVals.removeAt(i);
                        }
                    }
                }
            } catch (RemoteException e) {
                // ignore.
                        }
                        }
                        if (duration < minimum) {
                            continue;
                        }
                        }
        if (!assocVals.isEmpty()) {
                        final SourceKey key = sources.keyAt(i);
            for (int i = assocVals.size() - 1; i >= 0; i--) {
                final SourceKey key = assocVals.keyAt(i);
                final long[] vals = assocVals.valueAt(i);
                        final long token = proto.start(fieldId);
                        final long token = proto.start(fieldId);
                        final int idx = uidToPkgMap.indexOfKey(key.mUid);
                        final int idx = uidToPkgMap.indexOfKey(key.mUid);
                        ProcessState.writeCompressedProcessName(proto,
                        ProcessState.writeCompressedProcessName(proto,
@@ -2428,11 +2390,15 @@ public final class ProcessStats implements Parcelable {
                                key.mProcess, key.mPackage,
                                key.mProcess, key.mPackage,
                                idx >= 0 && uidToPkgMap.valueAt(idx).size() > 1);
                                idx >= 0 && uidToPkgMap.valueAt(idx).size() > 1);
                        proto.write(ProcessStatsAssociationProto.ASSOC_UID, key.mUid);
                        proto.write(ProcessStatsAssociationProto.ASSOC_UID, key.mUid);
                proto.write(ProcessStatsAssociationProto.TOTAL_COUNT, (int) vals[1]);
                        proto.write(ProcessStatsAssociationProto.TOTAL_COUNT, src.mCount);
                        proto.write(ProcessStatsAssociationProto.TOTAL_DURATION_SECS,
                        proto.write(ProcessStatsAssociationProto.TOTAL_DURATION_SECS,
                        (int) (vals[0] / 1000));
                                (int) (duration / 1000));
                        proto.end(token);
                        proto.end(token);
                    }
                    }
                } catch (RemoteException e) {
                    // ignore.
                }
            }
        }
        }
    }
    }