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

Commit c0b67c93 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add more data (fg services, associations) to procstats."

parents 1a81a745 2aec55a6
Loading
Loading
Loading
Loading
+293 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 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.os.Parcel;
import android.os.SystemClock;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.TimeUtils;

import java.io.PrintWriter;
import java.util.Objects;

public final class AssociationState {
    private static final String TAG = "ProcessStats";
    private static final boolean DEBUG = false;

    private final String mPackage;
    private final String mProcessName;
    private final String mName;
    private final DurationsTable mDurations;

    public final class SourceState {
        public void stop() {
            mNesting--;
            if (mNesting == 0) {
                mDuration += SystemClock.uptimeMillis() - mStartTime;
                mNumActive--;
            }
        }

        int mNesting;
        int mCount;
        long mStartTime;
        long mDuration;
    }

    final static class SourceKey {
        int mUid;
        String mProcess;

        SourceKey(int uid, String process) {
            mUid = uid;
            mProcess = process;
        }

        public boolean equals(Object o) {
            if (!(o instanceof SourceKey)) {
                return false;
            }
            SourceKey s = (SourceKey) o;
            return s.mUid == mUid && Objects.equals(s.mProcess, mProcess);
        }

        @Override
        public int hashCode() {
            return Integer.hashCode(mUid) ^ (mProcess == null ? 0 : mProcess.hashCode());
        }

        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder(64);
            sb.append("SourceKey{");
            UserHandle.formatUid(sb, mUid);
            sb.append(' ');
            sb.append(mProcess);
            sb.append('}');
            return sb.toString();
        }

    }

    /**
     * All known sources for this target component...  uid -> process name -> source state.
     */
    private final ArrayMap<SourceKey, SourceState> mSources = new ArrayMap<>();

    private final SourceKey mTmpSourceKey = new SourceKey(0, null);

    private int mNumActive;

    public AssociationState(ProcessStats processStats, String pkg, String name,
            String processName) {
        mPackage = pkg;
        mName = name;
        mProcessName = processName;
        mDurations = new DurationsTable(processStats.mTableData);
    }

    public String getPackage() {
        return mPackage;
    }

    public String getProcessName() {
        return mProcessName;
    }

    public String getName() {
        return mName;
    }

    public SourceState startSource(int uid, String processName) {
        mTmpSourceKey.mUid = uid;
        mTmpSourceKey.mProcess = processName;
        SourceState src = mSources.get(mTmpSourceKey);
        if (src == null) {
            src = new SourceState();
            mSources.put(new SourceKey(uid, processName), src);
        }
        src.mNesting++;
        if (src.mNesting == 1) {
            src.mCount++;
            src.mStartTime = SystemClock.uptimeMillis();
            mNumActive++;
        }
        return src;
    }

    public void add(AssociationState other) {
        mDurations.addDurations(other.mDurations);
        for (int isrc = other.mSources.size() - 1; isrc >= 0; isrc--) {
            final SourceKey key = other.mSources.keyAt(isrc);
            final SourceState otherSrc = other.mSources.valueAt(isrc);
            SourceState mySrc = mSources.get(key);
            if (mySrc == null) {
                mySrc = new SourceState();
                mSources.put(key, mySrc);
            }
            mySrc.mCount += otherSrc.mCount;
            mySrc.mDuration += otherSrc.mDuration;
        }
    }

    public boolean isInUse() {
        return mNumActive > 0;
    }

    public void resetSafely(long now) {
        mDurations.resetTable();
        if (!isInUse()) {
            mSources.clear();
        } else {
            // We have some active sources...  clear out everything but those.
            for (int isrc = mSources.size() - 1; isrc >= 0; isrc--) {
                SourceState src = mSources.valueAt(isrc);
                if (src.mNesting > 0) {
                    src.mCount = 1;
                    src.mStartTime = now;
                    src.mDuration = 0;
                } else {
                    mSources.removeAt(isrc);
                }
            }
        }
    }

    public void writeToParcel(ProcessStats stats, Parcel out, long now) {
        mDurations.writeToParcel(out);
        final int NSRC = mSources.size();
        out.writeInt(NSRC);
        for (int isrc = 0; isrc < NSRC; isrc++) {
            final SourceKey key = mSources.keyAt(isrc);
            final SourceState src = mSources.valueAt(isrc);
            out.writeInt(key.mUid);
            stats.writeCommonString(out, key.mProcess);
            out.writeInt(src.mCount);
            out.writeLong(src.mDuration);
        }
    }

    public String readFromParcel(ProcessStats stats, Parcel in, int parcelVersion) {
        if (!mDurations.readFromParcel(in)) {
            return "Duration table corrupt";
        }
        final int NSRC = in.readInt();
        if (NSRC < 0 || NSRC > 100000) {
            return "Association with bad src count: " + NSRC;
        }
        for (int isrc = 0; isrc < NSRC; isrc++) {
            final int uid = in.readInt();
            final String procName = stats.readCommonString(in, parcelVersion);
            final SourceKey key = new SourceKey(uid, procName);
            final SourceState src = new SourceState();
            src.mCount = in.readInt();
            src.mDuration = in.readLong();
            mSources.put(key, src);
        }
        return null;
    }

    public void commitStateTime(long now) {
        if (isInUse()) {
            for (int isrc = mSources.size() - 1; isrc >= 0; isrc--) {
                SourceState src = mSources.valueAt(isrc);
                if (src.mNesting > 0) {
                    src.mDuration += now - src.mStartTime;
                    src.mStartTime = now;
                }
            }
        }
    }

    public void dumpStats(PrintWriter pw, String prefix, String prefixInner, String headerPrefix,
            long now, long totalTime, boolean dumpSummary, boolean dumpAll) {
        if (dumpAll) {
            pw.print(prefix);
            pw.print("mNumActive=");
            pw.println(mNumActive);
        }
        final int NSRC = mSources.size();
        for (int isrc = 0; isrc < NSRC; isrc++) {
            final SourceKey key = mSources.keyAt(isrc);
            final SourceState src = mSources.valueAt(isrc);
            pw.print(prefixInner);
            pw.print("<- ");
            pw.print(key.mProcess);
            pw.print(" / ");
            UserHandle.formatUid(pw, key.mUid);
            pw.println(":");
            pw.print(prefixInner);
            pw.print("   Count ");
            pw.print(src.mCount);
            long duration = src.mDuration;
            if (src.mNesting > 0) {
                duration += now - src.mStartTime;
            }
            if (dumpAll) {
                pw.print(" / Duration ");
                TimeUtils.formatDuration(duration, pw);
                pw.print(" / ");
            } else {
                pw.print(" / time ");
            }
            DumpUtils.printPercent(pw, (double)duration/(double)totalTime);
            if (src.mNesting > 0) {
                pw.print(" (running)");
            }
            pw.println();
        }
    }

    public void dumpTimesCheckin(PrintWriter pw, String pkgName, int uid, long vers,
            String associationName, long now) {
        final int NSRC = mSources.size();
        for (int isrc = 0; isrc < NSRC; isrc++) {
            final SourceKey key = mSources.keyAt(isrc);
            final SourceState src = mSources.valueAt(isrc);
            pw.print("pkgasc");
            pw.print(",");
            pw.print(pkgName);
            pw.print(",");
            pw.print(uid);
            pw.print(",");
            pw.print(vers);
            pw.print(",");
            pw.print(associationName);
            pw.print(",");
            pw.print(key.mProcess);
            pw.print(",");
            pw.print(key.mUid);
            pw.print(",");
            pw.print(src.mCount);
            long duration = src.mDuration;
            if (src.mNesting > 0) {
                duration += now - src.mStartTime;
            }
            pw.print(",");
            pw.print(duration);
            pw.println();
        }
    }

    public String toString() {
        return "AssociationState{" + Integer.toHexString(System.identityHashCode(this))
                + " " + mName + " pkg=" + mPackage + " proc="
                + Integer.toHexString(System.identityHashCode(this)) + "}";
    }
}
+3 −2
Original line number Diff line number Diff line
@@ -362,12 +362,13 @@ public final class DumpUtils {
        }
    }

    public static void dumpProcessSummaryLocked(PrintWriter pw, String prefix,
    public static void dumpProcessSummaryLocked(PrintWriter pw, String prefix, String header,
            ArrayList<ProcessState> procs, int[] screenStates, int[] memStates, int[] procStates,
            long now, long totalTime) {
        for (int i=procs.size()-1; i>=0; i--) {
            final ProcessState proc = procs.get(i);
            proc.dumpSummary(pw, prefix, screenStates, memStates, procStates, now, totalTime);
            proc.dumpSummary(pw, prefix, header, screenStates, memStates, procStates, now,
                    totalTime);
        }
    }

+9 −6
Original line number Diff line number Diff line
@@ -580,7 +580,7 @@ public final class ProcessState {
        ProcessStateHolder holder = pkgList.valueAt(index);
        ProcessState proc = holder.state;
        if (mDead && proc.mCommonProcess != proc) {
            // Somehow we are contining to use a process state that is dead, because
            // Somehow we are continuing to use a process state that is dead, because
            // it was not being told it was active during the last commit.  We can recover
            // from this by generating a fresh new state, but this is bad because we
            // are losing whatever data we had in the old process state.
@@ -600,17 +600,17 @@ public final class ProcessState {
                        + pkgList.keyAt(index) + "/" + proc.mUid
                        + " for multi-proc " + proc.mName);
            }
            PackageState pkg = vpkg.get(proc.mVersion);
            if (pkg == null) {
            PackageState expkg = vpkg.get(proc.mVersion);
            if (expkg == null) {
                throw new IllegalStateException("No existing package "
                        + pkgList.keyAt(index) + "/" + proc.mUid
                        + " for multi-proc " + proc.mName + " version " + proc.mVersion);
            }
            String savedName = proc.mName;
            proc = pkg.mProcesses.get(proc.mName);
            proc = expkg.mProcesses.get(proc.mName);
            if (proc == null) {
                throw new IllegalStateException("Didn't create per-package process "
                        + savedName + " in pkg " + pkg.mPackageName + "/" + pkg.mUid);
                        + savedName + " in pkg " + expkg.mPackageName + "/" + expkg.mUid);
            }
            holder.state = proc;
        }
@@ -769,11 +769,14 @@ public final class ProcessState {
        return totalTime;
    }

    public void dumpSummary(PrintWriter pw, String prefix,
    public void dumpSummary(PrintWriter pw, String prefix, String header,
            int[] screenStates, int[] memStates, int[] procStates,
            long now, long totalTime) {
        pw.print(prefix);
        pw.print("* ");
        if (header != null) {
            pw.print(header);
        }
        pw.print(mName);
        pw.print(" / ");
        UserHandle.formatUid(pw, mUid);
+158 −30

File changed.

Preview size limit exceeded, changes collapsed.

+81 −24
Original line number Diff line number Diff line
@@ -18,30 +18,13 @@ package com.android.internal.app.procstats;


import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.text.format.DateFormat;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;

import com.android.internal.app.procstats.ProcessStats;
import static com.android.internal.app.procstats.ProcessStats.STATE_NOTHING;

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.Comparator;
import java.util.Objects;

public final class ServiceState {
    private static final String TAG = "ProcessStats";
@@ -51,7 +34,8 @@ public final class ServiceState {
    public static final int SERVICE_STARTED = 1;
    public static final int SERVICE_BOUND = 2;
    public static final int SERVICE_EXEC = 3;
    public static final int SERVICE_COUNT = 4;
    public static final int SERVICE_FOREGROUND = 4;
    public static final int SERVICE_COUNT = 5;

    private final String mPackage;
    private final String mProcessName;
@@ -79,6 +63,10 @@ public final class ServiceState {
    private int mExecState = STATE_NOTHING;
    private long mExecStartTime;

    private int mForegroundCount;
    private int mForegroundState = STATE_NOTHING;
    private long mForegroundStartTime;

    public ServiceState(ProcessStats processStats, String pkg, String name,
            String processName, ProcessState proc) {
        mPackage = pkg;
@@ -121,6 +109,9 @@ public final class ServiceState {
            if (mExecState != ProcessStats.STATE_NOTHING) {
                setExecuting(true, memFactor, now);
            }
            if (mForegroundState != ProcessStats.STATE_NOTHING) {
                setForeground(true, memFactor, now);
            }
        }
    }

@@ -133,7 +124,8 @@ public final class ServiceState {
                // There was already an old owner, reset this object for its
                // new owner.
                mOwner = newOwner;
                if (mStarted || mBoundState != STATE_NOTHING || mExecState != STATE_NOTHING) {
                if (mStarted || mBoundState != STATE_NOTHING || mExecState != STATE_NOTHING
                        || mForegroundState != STATE_NOTHING) {
                    long now = SystemClock.uptimeMillis();
                    if (mStarted) {
                        if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner
@@ -153,6 +145,12 @@ public final class ServiceState {
                                + mPackage + " service=" + mName + " proc=" + mProc);
                        setExecuting(false, 0, now);
                    }
                    if (mForegroundState != STATE_NOTHING) {
                        if (DEBUG) Slog.d(TAG, "Service has new owner " + newOwner
                                + " from " + mOwner + " while foreground: pkg="
                                + mPackage + " service=" + mName + " proc=" + mProc);
                        setForeground(false, 0, now);
                    }
                }
            }
        }
@@ -161,7 +159,8 @@ public final class ServiceState {
    public void clearCurrentOwner(Object owner, boolean silently) {
        if (mOwner == owner) {
            mProc.decActiveServices(mName);
            if (mStarted || mBoundState != STATE_NOTHING || mExecState != STATE_NOTHING) {
            if (mStarted || mBoundState != STATE_NOTHING || mExecState != STATE_NOTHING
                    || mForegroundState != STATE_NOTHING) {
                long now = SystemClock.uptimeMillis();
                if (mStarted) {
                    if (!silently) {
@@ -187,6 +186,14 @@ public final class ServiceState {
                    }
                    setExecuting(false, 0, now);
                }
                if (mForegroundState != STATE_NOTHING) {
                    if (!silently) {
                        Slog.wtfStack(TAG, "Service owner " + owner
                                + " cleared while foreground: pkg=" + mPackage + " service="
                                + mName + " proc=" + mProc);
                    }
                    setForeground(false, 0, now);
                }
            }
            mOwner = null;
        }
@@ -206,6 +213,7 @@ public final class ServiceState {
        mStartedCount += other.mStartedCount;
        mBoundCount += other.mBoundCount;
        mExecCount += other.mExecCount;
        mForegroundCount += other.mForegroundCount;
    }

    public void resetSafely(long now) {
@@ -214,7 +222,9 @@ public final class ServiceState {
        mStartedCount = mStartedState != STATE_NOTHING ? 1 : 0;
        mBoundCount = mBoundState != STATE_NOTHING ? 1 : 0;
        mExecCount = mExecState != STATE_NOTHING ? 1 : 0;
        mRunStartTime = mStartedStartTime = mBoundStartTime = mExecStartTime = now;
        mForegroundCount = mForegroundState != STATE_NOTHING ? 1 : 0;
        mRunStartTime = mStartedStartTime = mBoundStartTime = mExecStartTime =
                mForegroundStartTime = now;
    }

    public void writeToParcel(Parcel out, long now) {
@@ -223,6 +233,7 @@ public final class ServiceState {
        out.writeInt(mStartedCount);
        out.writeInt(mBoundCount);
        out.writeInt(mExecCount);
        out.writeInt(mForegroundCount);
    }

    public boolean readFromParcel(Parcel in) {
@@ -233,6 +244,7 @@ public final class ServiceState {
        mStartedCount = in.readInt();
        mBoundCount = in.readInt();
        mExecCount = in.readInt();
        mForegroundCount = in.readInt();
        return true;
    }

@@ -257,11 +269,17 @@ public final class ServiceState {
                    now - mExecStartTime);
            mExecStartTime = now;
        }
        if (mForegroundState != STATE_NOTHING) {
            mDurations.addDuration(SERVICE_FOREGROUND + (mForegroundState*SERVICE_COUNT),
                    now - mForegroundStartTime);
            mForegroundStartTime = now;
        }
    }

    private void updateRunning(int memFactor, long now) {
        final int state = (mStartedState != STATE_NOTHING || mBoundState != STATE_NOTHING
                || mExecState != STATE_NOTHING) ? memFactor : STATE_NOTHING;
                || mExecState != STATE_NOTHING || mForegroundState != STATE_NOTHING)
                ? memFactor : STATE_NOTHING;
        if (mRunState != state) {
            if (mRunState != STATE_NOTHING) {
                mDurations.addDuration(SERVICE_RUN + (mRunState*SERVICE_COUNT),
@@ -348,6 +366,24 @@ public final class ServiceState {
        }
    }

    public void setForeground(boolean foreground, int memFactor, long now) {
        if (mOwner == null) {
            Slog.wtf(TAG, "Foregrounding service " + this + " without owner");
        }
        final int state = foreground ? memFactor : STATE_NOTHING;
        if (mForegroundState != state) {
            if (mForegroundState != STATE_NOTHING) {
                mDurations.addDuration(SERVICE_FOREGROUND + (mForegroundState*SERVICE_COUNT),
                        now - mForegroundStartTime);
            } else if (foreground) {
                mForegroundCount++;
            }
            mForegroundState = state;
            mForegroundStartTime = now;
            updateRunning(memFactor, now);
        }
    }

    public long getDuration(int opType, int curState, long startTime, int memFactor,
            long now) {
        int state = opType + (memFactor*SERVICE_COUNT);
@@ -366,6 +402,9 @@ public final class ServiceState {
        dumpStats(pw, prefix, prefixInner, headerPrefix, "Started",
                mStartedCount, ServiceState.SERVICE_STARTED, mStartedState,
                mStartedStartTime, now, totalTime, !dumpSummary || dumpAll);
        dumpStats(pw, prefix, prefixInner, headerPrefix, "Foreground",
                mForegroundCount, ServiceState.SERVICE_FOREGROUND, mForegroundState,
                mForegroundStartTime, now, totalTime, !dumpSummary || dumpAll);
        dumpStats(pw, prefix, prefixInner, headerPrefix, "Bound",
                mBoundCount, ServiceState.SERVICE_BOUND, mBoundState,
                mBoundStartTime, now, totalTime, !dumpSummary || dumpAll);
@@ -393,11 +432,19 @@ public final class ServiceState {
                pw.print(" op count "); pw.print(count); pw.println(":");
                dumpTime(pw, prefixInner, serviceType, state, startTime, now);
            } else {
                long myTime = dumpTime(null, null, serviceType, state, startTime, now);
                long myTime = dumpTimeInternal(null, null, serviceType, state, startTime, now,
                        true);
                pw.print(prefix); pw.print(headerPrefix); pw.print(header);
                pw.print(" count "); pw.print(count);
                pw.print(" / time ");
                boolean isRunning = myTime < 0;
                if (isRunning) {
                    myTime = -myTime;
                }
                DumpUtils.printPercent(pw, (double)myTime/(double)totalTime);
                if (isRunning) {
                    pw.print(" (running)");
                }
                pw.println();
            }
        }
@@ -405,8 +452,14 @@ public final class ServiceState {

    public long dumpTime(PrintWriter pw, String prefix,
            int serviceType, int curState, long curStartTime, long now) {
        return dumpTimeInternal(pw, prefix, serviceType, curState, curStartTime, now, false);
    }

    long dumpTimeInternal(PrintWriter pw, String prefix,
            int serviceType, int curState, long curStartTime, long now, boolean negativeIfRunning) {
        long totalTime = 0;
        int printedScreen = -1;
        boolean isRunning = false;
        for (int iscreen=0; iscreen<ProcessStats.ADJ_COUNT; iscreen+=ProcessStats.ADJ_SCREEN_MOD) {
            int printedMem = -1;
            for (int imem=0; imem<ProcessStats.ADJ_MEM_FACTOR_COUNT; imem++) {
@@ -415,6 +468,7 @@ public final class ServiceState {
                String running = "";
                if (curState == state && pw != null) {
                    running = " (running)";
                    isRunning = true;
                }
                if (time != 0) {
                    if (pw != null) {
@@ -438,7 +492,7 @@ public final class ServiceState {
            TimeUtils.formatDuration(totalTime, pw);
            pw.println();
        }
        return totalTime;
        return (isRunning && negativeIfRunning) ? -totalTime : totalTime;
    }

    public void dumpTimesCheckin(PrintWriter pw, String pkgName, int uid, long vers,
@@ -447,6 +501,9 @@ public final class ServiceState {
                ServiceState.SERVICE_RUN, mRunCount, mRunState, mRunStartTime, now);
        dumpTimeCheckin(pw, "pkgsvc-start", pkgName, uid, vers, serviceName,
                ServiceState.SERVICE_STARTED, mStartedCount, mStartedState, mStartedStartTime, now);
        dumpTimeCheckin(pw, "pkgsvc-fg", pkgName, uid, vers, serviceName,
                ServiceState.SERVICE_FOREGROUND, mForegroundCount, mForegroundState,
                mForegroundStartTime, now);
        dumpTimeCheckin(pw, "pkgsvc-bound", pkgName, uid, vers, serviceName,
                ServiceState.SERVICE_BOUND, mBoundCount, mBoundState, mBoundStartTime, now);
        dumpTimeCheckin(pw, "pkgsvc-exec", pkgName, uid, vers, serviceName,
Loading